From 606aeaa55bde4fcd4ee9a3fa5ab34dff77c175a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Sat, 28 Jan 2023 13:17:00 +0100 Subject: [PATCH 1/5] feat(editor): Use text editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/PageController.php | 11 +- src/components/Note.vue | 490 +---------------------------- src/components/NotePlain.vue | 505 ++++++++++++++++++++++++++++++ src/components/NoteRich.vue | 138 ++++++++ 4 files changed, 661 insertions(+), 483 deletions(-) create mode 100644 src/components/NotePlain.vue create mode 100644 src/components/NoteRich.vue diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index b9baf3e0c..07239d8bc 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -6,10 +6,12 @@ use OCA\Notes\Service\NotesService; +use OCA\Text\Event\LoadEditor; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\RedirectResponse; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; @@ -18,18 +20,21 @@ class PageController extends Controller { private NotesService $notesService; private IUserSession $userSession; private IURLGenerator $urlGenerator; + private IEventDispatcher $eventDispatcher; public function __construct( string $AppName, IRequest $request, NotesService $notesService, IUserSession $userSession, - IURLGenerator $urlGenerator + IURLGenerator $urlGenerator, + IEventDispatcher $eventDispatcher ) { parent::__construct($AppName, $request); $this->notesService = $notesService; $this->userSession = $userSession; $this->urlGenerator = $urlGenerator; + $this->eventDispatcher = $eventDispatcher; } @@ -45,6 +50,10 @@ public function index() : TemplateResponse { [ ] ); + if (class_exists(LoadEditor::class)) { + $this->eventDispatcher->dispatchTyped(new LoadEditor()); + } + $csp = new ContentSecurityPolicy(); $csp->addAllowedImageDomain('*'); $response->setContentSecurityPolicy($csp); diff --git a/src/components/Note.vue b/src/components/Note.vue index 28eb36679..84e87534a 100644 --- a/src/components/Note.vue +++ b/src/components/Note.vue @@ -1,150 +1,20 @@ - diff --git a/src/components/NotePlain.vue b/src/components/NotePlain.vue new file mode 100644 index 000000000..5eac70a26 --- /dev/null +++ b/src/components/NotePlain.vue @@ -0,0 +1,505 @@ + + + diff --git a/src/components/NoteRich.vue b/src/components/NoteRich.vue new file mode 100644 index 000000000..210c51c95 --- /dev/null +++ b/src/components/NoteRich.vue @@ -0,0 +1,138 @@ + + + From 1acb08d33fccfcc016125c560803ae66779f1827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Fri, 24 Feb 2023 10:27:52 +0100 Subject: [PATCH 2/5] feat: Add sidebar button to navigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/components/NavigationNoteItem.vue | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/components/NavigationNoteItem.vue b/src/components/NavigationNoteItem.vue index 4ee74b96b..e222d64cc 100644 --- a/src/components/NavigationNoteItem.vue +++ b/src/components/NavigationNoteItem.vue @@ -15,6 +15,10 @@ {{ actionFavoriteText }} + + + {{ t('notes', 'Details') }} + {{ t('notes', 'Delete note') }} @@ -32,7 +36,9 @@ import { NcActionSeparator, NcAppNavigationItem, } from '@nextcloud/vue' +import SidebarIcon from 'vue-material-design-icons/PageLayoutSidebarRight.vue' import { showError } from '@nextcloud/dialogs' +import store from '../store.js' import { setFavorite, setTitle, fetchNote, deleteNote } from '../NotesService.js' import { categoryLabel, routeIsNewNote } from '../Util.js' @@ -44,6 +50,7 @@ export default { NcActionButton, NcActionSeparator, NcAppNavigationItem, + SidebarIcon, }, props: { @@ -117,6 +124,11 @@ export default { this.$emit('category-selected', this.note.category) }, + onToggleSidebar() { + this.actionsOpen = false + store.commit('setSidebarOpen', !store.state.app.sidebarOpen) + }, + onRename(newTitle) { this.loading.note = true setTitle(this.note.id, newTitle) From cdaf360676cd0d43484172d8960369250afecd41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Fri, 24 Feb 2023 10:28:11 +0100 Subject: [PATCH 3/5] feat: Add setting for rich mode and make markdown the default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Service/SettingsService.php | 4 ++-- src/components/AppSettings.vue | 3 ++- tests/api/APIv1Test.php | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Service/SettingsService.php b/lib/Service/SettingsService.php index 5fb97bcba..073deec24 100644 --- a/lib/Service/SettingsService.php +++ b/lib/Service/SettingsService.php @@ -18,7 +18,7 @@ class SettingsService { /* Allowed attributes */ private array $attrs; - private $defaultSuffixes = [ '.txt', '.md' ]; + private $defaultSuffixes = [ '.md', '.txt' ]; public function __construct( IConfig $config, @@ -48,7 +48,7 @@ public function __construct( return implode(DIRECTORY_SEPARATOR, $path); }, ], - 'noteMode' => $this->getListAttrs('noteMode', ['edit', 'preview']), + 'noteMode' => $this->getListAttrs('noteMode', ['rich', 'edit', 'preview']), 'customSuffix' => [ 'default' => $this->defaultSuffixes[0], 'validate' => function ($value) { diff --git a/src/components/AppSettings.vue b/src/components/AppSettings.vue index 2bb89eee3..f80bea2f3 100644 --- a/src/components/AppSettings.vue +++ b/src/components/AppSettings.vue @@ -63,11 +63,12 @@ export default { data() { return { extensions: [ - { value: '.txt', label: '.txt' }, { value: '.md', label: '.md' }, + { value: '.txt', label: '.txt' }, { value: 'custom', label: t('notes', 'User defined') }, ], noteModes: [ + { value: 'rich', label: t('notes', 'Open in rich text mode') }, { value: 'edit', label: t('notes', 'Open in edit mode') }, { value: 'preview', label: t('notes', 'Open in preview mode') }, ], diff --git a/tests/api/APIv1Test.php b/tests/api/APIv1Test.php index 65e4a3b9e..5567d61af 100644 --- a/tests/api/APIv1Test.php +++ b/tests/api/APIv1Test.php @@ -195,14 +195,14 @@ public function testSettings(array $refNotes, \stdClass $settings) : void { $this->updateSettings($settings, (object)[ 'fileSuffix' => '', ], (object)[ - 'fileSuffix' => '.txt', + 'fileSuffix' => '.md', ], 'Update fileSuffix with empty value'); $this->updateSettings($settings, (object)[ 'notesPath' => null, 'fileSuffix' => null, ], (object)[ 'notesPath' => 'Notes', - 'fileSuffix' => '.txt', + 'fileSuffix' => '.md', ], 'Update settings with default values'); $this->updateSettings($settings, (object)[ 'notesPath' => $originalPath, From 55605e52570c680992969dca0054f56444b1ba49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 1 Mar 2023 11:21:39 +0100 Subject: [PATCH 4/5] chore: Add krankerl config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- .nextcloudignore | 28 ++++++++++++++++++++++++++++ appinfo/info.xml | 4 ++-- krankerl.toml | 5 +++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 .nextcloudignore create mode 100644 krankerl.toml diff --git a/.nextcloudignore b/.nextcloudignore new file mode 100644 index 000000000..90b486c88 --- /dev/null +++ b/.nextcloudignore @@ -0,0 +1,28 @@ +/build/ +/.git +/.github +/docs/ +/tests +/babel.config.js +/.editorconfig +/.eslintrc.js +/.nextcloudignore +/webpack.*.js +/.codecov.yml +/composer.json +/composer.lock +/_config.yml +/.drone.yml +/.travis.yml +/.eslintignore +/.eslintrc.yml +/.gitignore +/issue_template.md +/krankerl.toml +/Makefile +/mkdocs.yml +/run-eslint.sh +/package.json +/package-lock.json +/node_modules/ +/src/ diff --git a/appinfo/info.xml b/appinfo/info.xml index 4014d76a3..818c881cd 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -7,7 +7,7 @@ - 4.6.0 + 4.7.0-beta.0 agpl Kristof Hamann Bernhard Posselt @@ -22,7 +22,7 @@ The Notes app is a distraction free notes taking app for [Nextcloud](https://www https://github.com/nextcloud/notes.git https://raw.githubusercontent.com/nextcloud/screenshots/master/apps/Notes/notes.png - + diff --git a/krankerl.toml b/krankerl.toml new file mode 100644 index 000000000..2c98a14f4 --- /dev/null +++ b/krankerl.toml @@ -0,0 +1,5 @@ +[package] +before_cmds = [ + 'npm ci', + 'npm run build' +] From ff897cf0b4b51a137d5cd5f34bec73650a579d79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 15 Mar 2023 20:10:29 +0100 Subject: [PATCH 5/5] enh: Add migration step to cover migration for existing users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/info.xml | 1 + appinfo/routes.php | 1 + lib/Controller/PageController.php | 26 +++++++++- lib/Controller/SettingsController.php | 5 ++ lib/Migration/EditorHint.php | 63 +++++++++++++++++++++++ lib/Service/SettingsService.php | 4 ++ package-lock.json | 1 + package.json | 1 + src/App.vue | 7 ++- src/NotesService.js | 9 ++++ src/components/Modal/EditorHint.vue | 72 +++++++++++++++++++++++++++ src/components/Note.vue | 2 +- src/store/app.js | 6 +++ 13 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 lib/Migration/EditorHint.php create mode 100644 src/components/Modal/EditorHint.vue diff --git a/appinfo/info.xml b/appinfo/info.xml index 818c881cd..bf162a42a 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -28,6 +28,7 @@ The Notes app is a distraction free notes taking app for [Nextcloud](https://www OCA\Notes\Migration\Cleanup + OCA\Notes\Migration\EditorHint diff --git a/appinfo/routes.php b/appinfo/routes.php index bc16fec3d..b1a7cd8b6 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -100,6 +100,7 @@ ////////// S E T T I N G S ////////// ['name' => 'settings#set', 'url' => '/settings', 'verb' => 'PUT'], ['name' => 'settings#get', 'url' => '/settings', 'verb' => 'GET'], + ['name' => 'settings#migrate', 'url' => '/settings/migrate', 'verb' => 'POST'], ////////// A P I ////////// diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index 07239d8bc..d61803461 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -4,43 +4,55 @@ namespace OCA\Notes\Controller; +use OCA\Notes\AppInfo\Application; use OCA\Notes\Service\NotesService; +use OCA\Notes\Service\SettingsService; use OCA\Text\Event\LoadEditor; +use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\RedirectResponse; +use OCP\AppFramework\Services\IInitialState; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IConfig; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; class PageController extends Controller { private NotesService $notesService; + private IConfig $config; private IUserSession $userSession; private IURLGenerator $urlGenerator; private IEventDispatcher $eventDispatcher; + private IInitialState $initialState; public function __construct( string $AppName, IRequest $request, NotesService $notesService, + IConfig $config, IUserSession $userSession, IURLGenerator $urlGenerator, - IEventDispatcher $eventDispatcher + IEventDispatcher $eventDispatcher, + IInitialState $initialState ) { parent::__construct($AppName, $request); $this->notesService = $notesService; + $this->config = $config; $this->userSession = $userSession; $this->urlGenerator = $urlGenerator; $this->eventDispatcher = $eventDispatcher; + $this->initialState = $initialState; } /** * @NoAdminRequired * @NoCSRFRequired + * @suppress PhanUndeclaredClassReference, PhanTypeMismatchArgument, PhanUndeclaredClassMethod */ public function index() : TemplateResponse { $devMode = !is_file(dirname(__FILE__).'/../../js/notes-main.js'); @@ -50,10 +62,20 @@ public function index() : TemplateResponse { [ ] ); - if (class_exists(LoadEditor::class)) { + if (\OCP\Server::get(IAppManager::class)->isEnabledForUser('text') && class_exists(LoadEditor::class)) { $this->eventDispatcher->dispatchTyped(new LoadEditor()); } + $this->initialState->provideInitialState( + 'config', + \OCP\Server::get(SettingsService::class)->getPublic($this->userSession->getUser()->getUID()) + ); + + $this->initialState->provideInitialState( + 'editorHint', + $this->config->getUserValue($this->userSession->getUser()->getUID(), Application::APP_ID, 'editorHint', '') + ); + $csp = new ContentSecurityPolicy(); $csp->addAllowedImageDomain('*'); $response->setContentSecurityPolicy($csp); diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 1d6efb340..9d7a6fbd9 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -48,4 +48,9 @@ public function set(): JSONResponse { public function get(): JSONResponse { return new JSONResponse($this->service->getAll($this->getUID())); } + + public function migrate(): JSONResponse { + $this->service->delete($this->getUID(), 'editorHint'); + return new JSONResponse(); + } } diff --git a/lib/Migration/EditorHint.php b/lib/Migration/EditorHint.php new file mode 100644 index 000000000..1a1f922ea --- /dev/null +++ b/lib/Migration/EditorHint.php @@ -0,0 +1,63 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + +namespace OCA\Notes\Migration; + +use OCA\Notes\AppInfo\Application; +use OCP\IConfig; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class EditorHint implements IRepairStep { + private IConfig $config; + private IUserManager $userManager; + public function __construct(IConfig $config, IUserManager $userManager) { + $this->config = $config; + $this->userManager = $userManager; + } + + public function getName() { + return 'Show a hint about the new editor to existing users'; + } + + public function run(IOutput $output) { + $appVersion = $this->config->getAppValue('text', 'installed_version'); + + if (!$appVersion || version_compare($appVersion, '4.7.0') !== -1) { + return; + } + + $this->userManager->callForSeenUsers(function (IUser $user) { + if ($this->config->getUserValue($user->getUID(), Application::APP_ID, 'notesLastViewedNote', '') === '') { + return; + } + + $this->config->setUserValue($user->getUID(), Application::APP_ID, 'editorHint', 'yes'); + }); + } +} diff --git a/lib/Service/SettingsService.php b/lib/Service/SettingsService.php index 073deec24..5f9a8d571 100644 --- a/lib/Service/SettingsService.php +++ b/lib/Service/SettingsService.php @@ -168,6 +168,10 @@ public function get(string $uid, string $name) : string { } } + public function delete(string $uid, string $name): void { + $this->config->deleteUserValue($uid, Application::APP_ID, $name); + } + public function getPublic(string $uid) : \stdClass { // initialize and load settings $settings = $this->getAll($uid, true); diff --git a/package-lock.json b/package-lock.json index 39e20d53e..b61f1e226 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "@nextcloud/axios": "^2.2.0", "@nextcloud/dialogs": "^3.2.0", "@nextcloud/event-bus": "^3.0.2", + "@nextcloud/initial-state": "^2.0.0", "@nextcloud/moment": "^1.2.1", "@nextcloud/router": "^2.0.1", "@nextcloud/vue": "^7.3.0", diff --git a/package.json b/package.json index 66b28972c..f0b766197 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@nextcloud/axios": "^2.2.0", "@nextcloud/dialogs": "^3.2.0", "@nextcloud/event-bus": "^3.0.2", + "@nextcloud/initial-state": "^2.0.0", "@nextcloud/moment": "^1.2.1", "@nextcloud/router": "^2.0.1", "@nextcloud/vue": "^7.3.0", diff --git a/src/App.vue b/src/App.vue index d36b2616d..f9f0bff7d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,6 @@