From 3c83320c20a9bd33dae4cf2c12561ae5dc96e61e Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Tue, 6 Sep 2022 18:03:44 +0200 Subject: [PATCH] implement card reference widget, fix DeckIcon.vue bring back eslint and stylelint on compilation, fix almost all warnings, ignore some Signed-off-by: Julien Veyssier --- .eslintrc.js | 3 +- lib/AppInfo/Application.php | 17 +- lib/Reference/CardReferenceProvider.php | 113 ++++ package-lock.json | 502 +++++++++++++++--- package.json | 3 + src/App.vue | 4 +- src/CardCreateDialog.vue | 8 +- src/components/ActivityEntry.vue | 2 +- src/components/ActivityList.vue | 2 +- src/components/AttachmentDragAndDrop.vue | 2 +- src/components/Controls.vue | 14 +- src/components/board/Board.vue | 8 +- src/components/board/BoardSidebar.vue | 8 +- src/components/board/DeletedTabSidebar.vue | 2 +- src/components/board/Stack.vue | 4 +- src/components/board/TagsTabSidebar.vue | 2 +- src/components/board/TimelineTabSidebar.vue | 2 +- src/components/boards/Boards.vue | 4 +- src/components/card/AttachmentList.vue | 6 +- src/components/card/CardSidebar.vue | 10 +- .../card/CardSidebarTabActivity.vue | 2 +- .../card/CardSidebarTabAttachments.vue | 2 +- .../card/CardSidebarTabComments.vue | 4 +- src/components/card/CardSidebarTabDetails.vue | 4 +- src/components/card/CommentForm.vue | 2 +- src/components/card/CommentItem.vue | 4 +- src/components/card/Description.vue | 2 +- src/components/cards/CardBadges.vue | 4 +- src/components/cards/CardItem.vue | 12 +- src/components/icons/DeckIcon.vue | 71 ++- src/components/navigation/AppNavigation.vue | 4 +- .../navigation/AppNavigationBoardCategory.vue | 2 +- src/components/overview/Overview.vue | 6 +- src/components/search/GlobalSearchResults.vue | 4 +- src/init-card-reference.js | 49 ++ src/init-collections.js | 8 +- src/init-dashboard.js | 2 +- src/init-talk.js | 6 +- src/main.js | 8 +- src/mixins/labelStyle.js | 2 +- src/router.js | 14 +- src/services/BoardApi.js | 2 +- src/services/StackApi.js | 2 +- src/store/attachment.js | 2 +- src/store/card.js | 2 +- src/store/comment.js | 2 +- src/store/main.js | 16 +- src/store/overview.js | 2 +- src/store/stack.js | 4 +- src/store/trashbin.js | 4 +- src/views/CardReferenceWidget.vue | 235 ++++++++ src/views/Dashboard.vue | 6 +- src/views/FileSharingPicker.js | 4 +- webpack.js | 20 + 54 files changed, 1029 insertions(+), 200 deletions(-) create mode 100644 lib/Reference/CardReferenceProvider.php create mode 100644 src/init-card-reference.js create mode 100644 src/views/CardReferenceWidget.vue diff --git a/.eslintrc.js b/.eslintrc.js index 690fc606a..69b8d1e1c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -8,6 +8,7 @@ module.exports = { 'jsdoc/require-param-type': ['off'], 'jsdoc/check-param-names': ['off'], 'jsdoc/no-undefined-types': ['off'], - 'jsdoc/require-property-description' : ['off'] + 'jsdoc/require-property-description': ['off'], + 'import/no-named-as-default-member': ['off'] }, } diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 53eb60258..edbd2b3a2 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -36,7 +36,6 @@ use OCA\Deck\Db\AclMapper; use OCA\Deck\Db\AssignmentMapper; use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\CardMapper; -use OCA\Deck\Db\User; use OCA\Deck\Event\AclCreatedEvent; use OCA\Deck\Event\AclDeletedEvent; use OCA\Deck\Event\AclUpdatedEvent; @@ -48,6 +47,7 @@ use OCA\Deck\Listeners\FullTextSearchEventListener; use OCA\Deck\Middleware\DefaultBoardMiddleware; use OCA\Deck\Middleware\ExceptionMiddleware; use OCA\Deck\Notification\Notifier; +use OCA\Deck\Reference\CardReferenceProvider; use OCA\Deck\Search\CardCommentProvider; use OCA\Deck\Search\DeckProvider; use OCA\Deck\Service\PermissionService; @@ -58,6 +58,7 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; +use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\Collaboration\Resources\IProviderManager; use OCP\Comments\CommentsEntityEvent; use OCP\Comments\ICommentsManager; @@ -83,6 +84,14 @@ class Application extends App implements IBootstrap { public function __construct(array $urlParams = []) { parent::__construct(self::APP_ID, $urlParams); + + // TODO move this back to ::register after fixing the autoload issue + // (and use a listener class) + $container = $this->getContainer(); + $eventDispatcher = $container->get(IEventDispatcher::class); + $eventDispatcher->addListener(RenderReferenceEvent::class, function () { + Util::addScript(self::APP_ID, self::APP_ID . '-card-reference'); + }); } public function boot(IBootContext $context): void { @@ -121,8 +130,12 @@ class Application extends App implements IBootstrap { $context->registerSearchProvider(CardCommentProvider::class); $context->registerDashboardWidget(DeckWidget::class); + // reference widget + $context->registerReferenceProvider(CardReferenceProvider::class); + // $context->registerEventListener(RenderReferenceEvent::class, CardReferenceListener::class); + $context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class); - + // Event listening for full text search indexing $context->registerEventListener(CardCreatedEvent::class, FullTextSearchEventListener::class); $context->registerEventListener(CardUpdatedEvent::class, FullTextSearchEventListener::class); diff --git a/lib/Reference/CardReferenceProvider.php b/lib/Reference/CardReferenceProvider.php new file mode 100644 index 000000000..a4e4a9c8b --- /dev/null +++ b/lib/Reference/CardReferenceProvider.php @@ -0,0 +1,113 @@ + + * + * @author Julien Veyssier + * + * @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\Deck\Reference; + +use OC\Collaboration\Reference\Reference; +use OCA\Deck\AppInfo\Application; +use OCA\Deck\Service\BoardService; +use OCA\Deck\Service\CardService; +use OCA\Deck\Service\StackService; +use OCP\Collaboration\Reference\IReference; +use OCP\Collaboration\Reference\IReferenceProvider; +use OCP\IURLGenerator; + +class CardReferenceProvider implements IReferenceProvider { + private CardService $cardService; + private IURLGenerator $urlGenerator; + private BoardService $boardService; + private StackService $stackService; + + public function __construct(CardService $cardService, + BoardService $boardService, + StackService $stackService, + IURLGenerator $urlGenerator, + ?string $userId) { + $this->cardService = $cardService; + $this->urlGenerator = $urlGenerator; + $this->boardService = $boardService; + $this->stackService = $stackService; + } + + /** + * @inheritDoc + */ + public function matchReference(string $referenceText): bool { + $start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID); + $startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID); + + // link example: https://nextcloud.local/index.php/apps/deck/#/board/2/card/11 + $noIndexMatch = preg_match('/^' . preg_quote($start, '/') . '\/#\/board\/[0-9]+\/card\/[0-9]+$/', $referenceText) === 1; + $indexMatch = preg_match('/^' . preg_quote($startIndex, '/') . '\/#\/board\/[0-9]+\/card\/[0-9]+$/', $referenceText) === 1; + + return $noIndexMatch || $indexMatch; + } + + /** + * @inheritDoc + */ + public function resolveReference(string $referenceText): ?IReference { + if ($this->matchReference($referenceText)) { + $cardIds = $this->getBoardCardId($referenceText); + if ($cardIds !== null) { + [$boardId, $cardId] = $cardIds; + $card = $this->cardService->find((int) $cardId); + $board = $this->boardService->find((int) $boardId); + $stack = $this->stackService->find((int) $card->jsonSerialize()['stackId']); + $reference = new Reference($referenceText); + $reference->setRichObject(Application::APP_ID . '-card', [ + 'card' => $card, + 'board' => $board, + 'stack' => $stack, + ]); + return $reference; + } + } + + return null; + } + + private function getBoardCardId(string $url): ?array { + $start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID); + $startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID); + + preg_match('/^' . preg_quote($start, '/') . '\/#\/board\/([0-9]+)\/card\/([0-9]+)$/', $url, $matches); + if ($matches && count($matches) > 2) { + return [$matches[1], $matches[2]]; + } + + preg_match('/^' . preg_quote($startIndex, '/') . '\/#\/board\/([0-9]+)\/card\/([0-9]+)$/', $url, $matches2); + if ($matches2 && count($matches2) > 2) { + return [$matches2[1], $matches2[2]]; + } + + return null; + } + + public function getCachePrefix(string $referenceId): string { + return $referenceId; + } + + public function getCacheKey(string $referenceId): ?string { + return null; + } +} diff --git a/package-lock.json b/package-lock.json index dfa2caf66..fe9550132 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@nextcloud/router": "^2.0.0", "@nextcloud/vue": "^6.0.0-beta.4", "@nextcloud/vue-dashboard": "^2.0.1", + "@nextcloud/vue-richtext": "^2.0.0", "blueimp-md5": "^2.19.0", "dompurify": "^2.4.0", "lodash": "^4.17.21", @@ -53,8 +54,10 @@ "@relative-ci/agent": "^4.1.0", "@vue/test-utils": "^1.3.0", "cypress": "^10.7.0", + "eslint-webpack-plugin": "^3.2.0", "jest": "^29.0.1", "jest-serializer-vue": "^2.0.2", + "stylelint-webpack-plugin": "^3.3.0", "vue-jest": "^3.0.7", "vue-template-compiler": "^2.7.9" }, @@ -3497,6 +3500,24 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/@nextcloud/vue-richtext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/vue-richtext/-/vue-richtext-2.0.0.tgz", + "integrity": "sha512-Z/AbweVmIB8shWZVLI0kUPrJnkCBlU5xIkkfv+RPFepLY7eZ+ttm5HRhLGqgFyXFNf4RIM7yGt/l6K35XcEX2A==", + "dependencies": { + "@nextcloud/axios": "^2.0.0", + "@nextcloud/router": "^2.0.0", + "clone": "^2.1.2", + "vue": "^2.7.8" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=7.0.0" + }, + "peerDependencies": { + "vue": "^2.7.8" + } + }, "node_modules/@nextcloud/vue/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -3600,7 +3621,6 @@ "version": "2.1.4", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" @@ -3613,7 +3633,6 @@ "version": "2.0.4", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 8" } @@ -3622,7 +3641,6 @@ "version": "1.2.6", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" @@ -3798,10 +3816,9 @@ } }, "node_modules/@types/eslint": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz", - "integrity": "sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA==", - "peer": true, + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", + "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -4463,7 +4480,6 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, - "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -4481,7 +4497,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -4497,8 +4512,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "peer": true + "dev": true }, "node_modules/ajv-keywords": { "version": "3.5.2", @@ -4636,7 +4650,6 @@ "version": "2.1.0", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -7438,7 +7451,6 @@ "version": "3.0.1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "path-type": "^4.0.0" }, @@ -7450,7 +7462,6 @@ "version": "4.0.0", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -8450,6 +8461,121 @@ "node": ">=10" } }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/eslint/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -9068,7 +9194,6 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, - "peer": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -9105,7 +9230,6 @@ "version": "1.11.0", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "reusify": "^1.0.4" } @@ -9625,7 +9749,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "peer": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -9711,7 +9834,6 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "peer": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -10223,7 +10345,6 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, - "peer": true, "engines": { "node": ">= 4" } @@ -10533,7 +10654,6 @@ "version": "2.1.1", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -10590,7 +10710,6 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "peer": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -13815,7 +13934,6 @@ "version": "1.4.1", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 8" } @@ -15452,8 +15570,7 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/quick-lru": { "version": "4.0.1", @@ -15866,7 +15983,6 @@ "version": "2.0.2", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -15964,7 +16080,6 @@ "version": "1.0.4", "dev": true, "license": "MIT", - "peer": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -16020,7 +16135,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "queue-microtask": "^1.2.2" } @@ -17112,6 +17226,121 @@ "stylelint": "^14.5.1" } }, + "node_modules/stylelint-webpack-plugin": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stylelint-webpack-plugin/-/stylelint-webpack-plugin-3.3.0.tgz", + "integrity": "sha512-F53bapIZ9zI16ero8IWm6TrUE6SSibZBphJE9b5rR2FxtvmGmm1YmS+a5xjQzn63+cv71GVSCu4byX66fBLpEw==", + "dev": true, + "dependencies": { + "globby": "^11.1.0", + "jest-worker": "^28.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "stylelint": "^13.0.0 || ^14.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/stylelint-webpack-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/stylelint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/stylelint-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stylelint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/stylelint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/stylelint-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/stylelint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/stylelint/node_modules/@csstools/selector-specificity": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", @@ -21677,6 +21906,17 @@ } } }, + "@nextcloud/vue-richtext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/vue-richtext/-/vue-richtext-2.0.0.tgz", + "integrity": "sha512-Z/AbweVmIB8shWZVLI0kUPrJnkCBlU5xIkkfv+RPFepLY7eZ+ttm5HRhLGqgFyXFNf4RIM7yGt/l6K35XcEX2A==", + "requires": { + "@nextcloud/axios": "^2.0.0", + "@nextcloud/router": "^2.0.0", + "clone": "^2.1.2", + "vue": "^2.7.8" + } + }, "@nextcloud/webpack-vue-config": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@nextcloud/webpack-vue-config/-/webpack-vue-config-5.3.0.tgz", @@ -21687,7 +21927,6 @@ "@nodelib/fs.scandir": { "version": "2.1.4", "dev": true, - "peer": true, "requires": { "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" @@ -21695,13 +21934,11 @@ }, "@nodelib/fs.stat": { "version": "2.0.4", - "dev": true, - "peer": true + "dev": true }, "@nodelib/fs.walk": { "version": "1.2.6", "dev": true, - "peer": true, "requires": { "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" @@ -21857,10 +22094,9 @@ } }, "@types/eslint": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz", - "integrity": "sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA==", - "peer": true, + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", + "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", "requires": { "@types/estree": "*", "@types/json-schema": "*" @@ -22455,7 +22691,6 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, - "peer": true, "requires": { "ajv": "^8.0.0" }, @@ -22465,7 +22700,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", "dev": true, - "peer": true, "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -22477,8 +22711,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "peer": true + "dev": true } } }, @@ -22567,8 +22800,7 @@ }, "array-union": { "version": "2.1.0", - "dev": true, - "peer": true + "dev": true }, "array.prototype.flat": { "version": "1.3.0", @@ -24732,15 +24964,13 @@ "dir-glob": { "version": "3.0.1", "dev": true, - "peer": true, "requires": { "path-type": "^4.0.0" }, "dependencies": { "path-type": { "version": "4.0.0", - "dev": true, - "peer": true + "dev": true } } }, @@ -25681,6 +25911,86 @@ "dev": true, "peer": true }, + "eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "requires": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "espree": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", @@ -25947,7 +26257,6 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, - "peer": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -25976,7 +26285,6 @@ "fastq": { "version": "1.11.0", "dev": true, - "peer": true, "requires": { "reusify": "^1.0.4" } @@ -26358,7 +26666,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "peer": true, "requires": { "is-glob": "^4.0.1" } @@ -26420,7 +26727,6 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "peer": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -26787,8 +27093,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "peer": true + "dev": true }, "immutable": { "version": "4.1.0", @@ -26990,8 +27295,7 @@ }, "is-extglob": { "version": "2.1.1", - "dev": true, - "peer": true + "dev": true }, "is-finite": { "version": "1.1.0", @@ -27027,7 +27331,6 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "peer": true, "requires": { "is-extglob": "^2.1.1" } @@ -29365,8 +29668,7 @@ }, "merge2": { "version": "1.4.1", - "dev": true, - "peer": true + "dev": true }, "methods": { "version": "1.1.2", @@ -30559,8 +30861,7 @@ }, "queue-microtask": { "version": "1.2.3", - "dev": true, - "peer": true + "dev": true }, "quick-lru": { "version": "4.0.1", @@ -30869,8 +31170,7 @@ }, "require-from-string": { "version": "2.0.2", - "dev": true, - "peer": true + "dev": true }, "requireindex": { "version": "1.2.0", @@ -30935,8 +31235,7 @@ }, "reusify": { "version": "1.0.4", - "dev": true, - "peer": true + "dev": true }, "rfdc": { "version": "1.3.0", @@ -30967,7 +31266,6 @@ "run-parallel": { "version": "1.2.0", "dev": true, - "peer": true, "requires": { "queue-microtask": "^1.2.2" } @@ -31870,6 +32168,86 @@ "postcss-value-parser": "^4.1.0" } }, + "stylelint-webpack-plugin": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stylelint-webpack-plugin/-/stylelint-webpack-plugin-3.3.0.tgz", + "integrity": "sha512-F53bapIZ9zI16ero8IWm6TrUE6SSibZBphJE9b5rR2FxtvmGmm1YmS+a5xjQzn63+cv71GVSCu4byX66fBLpEw==", + "dev": true, + "requires": { + "globby": "^11.1.0", + "jest-worker": "^28.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "superstruct": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.16.0.tgz", diff --git a/package.json b/package.json index 7c825036c..13b879b0c 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@nextcloud/router": "^2.0.0", "@nextcloud/vue": "^6.0.0-beta.4", "@nextcloud/vue-dashboard": "^2.0.1", + "@nextcloud/vue-richtext": "^2.0.0", "blueimp-md5": "^2.19.0", "dompurify": "^2.4.0", "lodash": "^4.17.21", @@ -79,8 +80,10 @@ "@relative-ci/agent": "^4.1.0", "@vue/test-utils": "^1.3.0", "cypress": "^10.7.0", + "eslint-webpack-plugin": "^3.2.0", "jest": "^29.0.1", "jest-serializer-vue": "^2.0.2", + "stylelint-webpack-plugin": "^3.3.0", "vue-jest": "^3.0.7", "vue-template-compiler": "^2.7.9" }, diff --git a/src/App.vue b/src/App.vue index 1f2e6e90f..cffef1b84 100644 --- a/src/App.vue +++ b/src/App.vue @@ -43,9 +43,9 @@ + + diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue index 4daf7a000..958d07d8c 100644 --- a/src/views/Dashboard.vue +++ b/src/views/Dashboard.vue @@ -59,10 +59,10 @@