From cf3e82dd4e470b8ea404eeb8effd7f99cbbe46ba Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sat, 23 Mar 2024 18:09:24 +0100 Subject: [PATCH 001/125] File: fix not creating PDF as different format Fixes #6268 --- src/Cms/FileActions.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Cms/FileActions.php b/src/Cms/FileActions.php index 890610fe82..fb3b943ece 100644 --- a/src/Cms/FileActions.php +++ b/src/Cms/FileActions.php @@ -139,8 +139,8 @@ public function changeTemplate(string|null $template): static // rename and/or resize the file if configured by new blueprint $create = $file->blueprint()->create(); + $file = $file->manipulate($create); $file = $file->changeExtension($file, $create['format'] ?? null); - $file->manipulate($create); return $file; }); @@ -266,7 +266,6 @@ public static function create(array $props, bool $move = false): File // we need to already rename it so that the correct file rules // are applied $create = $file->blueprint()->create(); - $file = $file->changeExtension($file, $create['format'] ?? null); // run the hook $arguments = compact('file', 'upload'); @@ -284,6 +283,7 @@ public static function create(array $props, bool $move = false): File // resize the file on upload if configured $file = $file->manipulate($create); + $file = $file->changeExtension($file, $create['format'] ?? null); // store the content if necessary // (always create files in the default language) @@ -384,8 +384,8 @@ public function replace(string $source, bool $move = false): static // apply the resizing/crop options from the blueprint $create = $file->blueprint()->create(); - $file = $file->changeExtension($file, $create['format'] ?? null); $file = $file->manipulate($create); + $file = $file->changeExtension($file, $create['format'] ?? null); // return a fresh clone return $file->clone(); From 47bd0b99eeaca10655ee9cc483dabaf77e932b97 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Mon, 25 Mar 2024 15:08:18 +0100 Subject: [PATCH 002/125] Fix deprecation warning in router --- router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router.php b/router.php index 10386c7cc7..c89b72509e 100644 --- a/router.php +++ b/router.php @@ -1,7 +1,7 @@ Date: Wed, 27 Mar 2024 11:38:03 +0100 Subject: [PATCH 003/125] Another try --- router.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/router.php b/router.php index c89b72509e..59d26d211d 100644 --- a/router.php +++ b/router.php @@ -1,11 +1,10 @@ Date: Wed, 27 Mar 2024 20:51:27 +0100 Subject: [PATCH 004/125] Add comment --- router.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/router.php b/router.php index 59d26d211d..ea8cc864ca 100644 --- a/router.php +++ b/router.php @@ -1,5 +1,7 @@ Date: Sat, 30 Mar 2024 15:33:17 +0100 Subject: [PATCH 005/125] New text vertical align icons --- panel/public/img/icons.svg | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/panel/public/img/icons.svg b/panel/public/img/icons.svg index 950867ee6e..0da75ac7f1 100644 --- a/panel/public/img/icons.svg +++ b/panel/public/img/icons.svg @@ -406,24 +406,16 @@ - - - + - - - + - - - + - - - + @@ -578,6 +570,15 @@ + + + + + + + + + From cc395c0af2dc25e64c4584fdef6a32fbc0e8955f Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sat, 6 Apr 2024 15:00:52 +0200 Subject: [PATCH 006/125] Editor: add `insertNode` util --- panel/src/components/Forms/Writer/Nodes/HardBreak.js | 5 +---- .../src/components/Forms/Writer/Nodes/HorizontalRule.js | 5 ++--- panel/src/components/Forms/Writer/Utils/index.js | 2 ++ panel/src/components/Forms/Writer/Utils/insertNode.js | 9 +++++++++ 4 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 panel/src/components/Forms/Writer/Utils/insertNode.js diff --git a/panel/src/components/Forms/Writer/Nodes/HardBreak.js b/panel/src/components/Forms/Writer/Nodes/HardBreak.js index dab4d5e5f5..9b146c06d3 100644 --- a/panel/src/components/Forms/Writer/Nodes/HardBreak.js +++ b/panel/src/components/Forms/Writer/Nodes/HardBreak.js @@ -6,10 +6,7 @@ export default class HardBreak extends Node { } createHardBreak(utils, type) { - return utils.chainCommands(utils.exitCode, (state, dispatch) => { - dispatch(state.tr.replaceSelectionWith(type.create()).scrollIntoView()); - return true; - }); + return utils.chainCommands(utils.exitCode, utils.insertNode(type)); } get defaults() { diff --git a/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js b/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js index 298e0940d7..13a594a1d4 100644 --- a/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js +++ b/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js @@ -1,9 +1,8 @@ import Node from "../Node"; export default class HorizontalRule extends Node { - commands({ type }) { - return () => (state, dispatch) => - dispatch(state.tr.replaceSelectionWith(type.create())); + commands({ type, utils }) { + return () => utils.insertNode(type); } inputRules({ type, utils }) { diff --git a/panel/src/components/Forms/Writer/Utils/index.js b/panel/src/components/Forms/Writer/Utils/index.js index e3c7f2bb77..e4f09ea93a 100644 --- a/panel/src/components/Forms/Writer/Utils/index.js +++ b/panel/src/components/Forms/Writer/Utils/index.js @@ -25,6 +25,7 @@ import { // custom import getMarkAttrs from "./getMarkAttrs"; import getNodeAttrs from "./getNodeAttrs"; +import insertNode from "./insertNode"; import markInputRule from "./markInputRule"; import markIsActive from "./markIsActive"; import markPasteRule from "./markPasteRule"; @@ -61,6 +62,7 @@ export default { // custom getMarkAttrs, getNodeAttrs, + insertNode, markInputRule, markIsActive, markPasteRule, diff --git a/panel/src/components/Forms/Writer/Utils/insertNode.js b/panel/src/components/Forms/Writer/Utils/insertNode.js new file mode 100644 index 0000000000..01eeb53a66 --- /dev/null +++ b/panel/src/components/Forms/Writer/Utils/insertNode.js @@ -0,0 +1,9 @@ +export default function insertNode(type, attrs, content, marks) { + return (state, dispatch) => { + dispatch( + state.tr + .replaceSelectionWith(type.create(attrs, content, marks)) + .scrollIntoView() + ); + }; +} From 44f606439c379ec295cd81803e6544ba3f8e47e7 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sat, 6 Apr 2024 19:11:18 +0200 Subject: [PATCH 007/125] Fix `nodeInputRule` --- .../components/Forms/Writer/Nodes/HorizontalRule.js | 10 +++++++++- .../src/components/Forms/Writer/Utils/nodeInputRule.js | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js b/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js index 298e0940d7..a60b5505f3 100644 --- a/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js +++ b/panel/src/components/Forms/Writer/Nodes/HorizontalRule.js @@ -7,7 +7,15 @@ export default class HorizontalRule extends Node { } inputRules({ type, utils }) { - return [utils.nodeInputRule(/^(?:---|___\s|\*\*\*\s)$/, type)]; + // create regular input rule for horizontal rule + const rule = utils.nodeInputRule(/^(?:---|___\s|\*\*\*\s)$/, type); + + // extend handler to remove the leftover empty line + const handler = rule.handler; + rule.handler = (state, match, start, end) => + handler(state, match, start, end).replaceWith(start - 1, start, ""); + + return [rule]; } get name() { diff --git a/panel/src/components/Forms/Writer/Utils/nodeInputRule.js b/panel/src/components/Forms/Writer/Utils/nodeInputRule.js index 067d903cde..2352238e6a 100644 --- a/panel/src/components/Forms/Writer/Utils/nodeInputRule.js +++ b/panel/src/components/Forms/Writer/Utils/nodeInputRule.js @@ -6,7 +6,7 @@ export default function (regexp, type, getAttrs) { const { tr } = state; if (match[0]) { - tr.replaceWith(start - 1, end, type.create(attrs)); + tr.replaceWith(start, end, type.create(attrs)); } return tr; From 8fd14c847f9faa1558aca16fa650e80c50a9d49a Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sat, 6 Apr 2024 21:59:27 +0200 Subject: [PATCH 008/125] Writer: fix nodes for `inline: true` --- panel/src/components/Forms/Writer/Writer.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/panel/src/components/Forms/Writer/Writer.vue b/panel/src/components/Forms/Writer/Writer.vue index 4063da1402..fe529bf28e 100644 --- a/panel/src/components/Forms/Writer/Writer.vue +++ b/panel/src/components/Forms/Writer/Writer.vue @@ -285,11 +285,6 @@ export default { enter: this.inline }); - // inline fields only get the hard break - if (this.inline === true) { - return [hardBreak]; - } - return this.filterExtensions( { bulletList: new BulletList(), @@ -310,6 +305,11 @@ export default { installed.push(new ListItem()); } + // inline fields should not have non-inline nodes + if (this.inline === true) { + installed = installed.filter((node) => node.schema.inline === true); + } + // always install the hard break installed.push(hardBreak); From f8000c299fac20a66abe1d8d7ab35ccec7516ffc Mon Sep 17 00:00:00 2001 From: Tobias Leugger Date: Fri, 12 Apr 2024 11:23:19 +0200 Subject: [PATCH 009/125] Update searches.php: Fixing panel search when uuids are disabled --- config/areas/site/searches.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/areas/site/searches.php b/config/areas/site/searches.php index 3791ad2f68..4cefefe5ff 100644 --- a/config/areas/site/searches.php +++ b/config/areas/site/searches.php @@ -22,7 +22,7 @@ 'text' => Escape::html($page->title()->value()), 'link' => $page->panel()->url(true), 'info' => Escape::html($page->id()), - 'uuid' => $page->uuid()->toString(), + 'uuid' => $page->uuid()?->toString(), ]), 'pagination' => $pages->pagination()->toArray() ]; From 578724d016bfe9586a0a9145a398b0d5f38c7b12 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Fri, 12 Apr 2024 16:06:27 +0200 Subject: [PATCH 010/125] Upgrade to eslint 9 --- panel/.eslintrc.js | 20 - panel/eslint.config.mjs | 28 + panel/package-lock.json | 481 +++++++++--------- panel/package.json | 20 +- .../src/components/Dialogs/LicenseDialog.vue | 1 - panel/src/components/Dialogs/SearchDialog.vue | 2 +- .../components/Forms/Field/ObjectField.vue | 2 - panel/src/components/Forms/FormButtons.vue | 2 +- .../components/Forms/Input/ColornameInput.vue | 2 +- .../Forms/Writer/Utils/markPasteRule.js | 1 - .../src/components/Navigation/Pagination.vue | 2 +- panel/src/components/Views/SearchView.vue | 2 +- panel/src/helpers/embed.js | 4 +- panel/src/helpers/link.js | 4 +- panel/src/helpers/upload.js | 2 +- panel/src/helpers/url.js | 2 +- panel/src/store/modules/content.js | 2 +- 17 files changed, 293 insertions(+), 284 deletions(-) delete mode 100644 panel/.eslintrc.js create mode 100644 panel/eslint.config.mjs diff --git a/panel/.eslintrc.js b/panel/.eslintrc.js deleted file mode 100644 index 4953eb51aa..0000000000 --- a/panel/.eslintrc.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - extends: ["eslint:recommended", "plugin:vue/recommended", "prettier"], - rules: { - "vue/attributes-order": "error", - "vue/component-definition-name-casing": "off", - "vue/html-closing-bracket-newline": [ - "error", - { - singleline: "never", - multiline: "always" - } - ], - "vue/multi-word-component-names": "off", - "vue/require-default-prop": "off", - "vue/require-prop-types": "error" - }, - parserOptions: { - ecmaVersion: 2022 - } -}; diff --git a/panel/eslint.config.mjs b/panel/eslint.config.mjs new file mode 100644 index 0000000000..cfe049eadc --- /dev/null +++ b/panel/eslint.config.mjs @@ -0,0 +1,28 @@ +import js from "@eslint/js"; +import prettier from "eslint-config-prettier"; +import vue from "eslint-plugin-vue"; + +export default [ + js.configs.recommended, + ...vue.configs["flat/vue2-recommended"], + prettier, + { + rules: { + "vue/attributes-order": "error", + "vue/component-definition-name-casing": "off", + "vue/html-closing-bracket-newline": [ + "error", + { + singleline: "never", + multiline: "always" + } + ], + "vue/multi-word-component-names": "off", + "vue/require-default-prop": "off", + "vue/require-prop-types": "error" + }, + languageOptions: { + ecmaVersion: 2022 + } + } +]; diff --git a/panel/package-lock.json b/panel/package-lock.json index 5965e1156e..b85aa61cc7 100644 --- a/panel/package-lock.json +++ b/panel/package-lock.json @@ -15,9 +15,9 @@ "prosemirror-history": "^1.4.0", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", - "prosemirror-model": "^1.19.4", + "prosemirror-model": "^1.20.0", "prosemirror-schema-list": "^1.3.0", - "prosemirror-view": "^1.33.3", + "prosemirror-view": "^1.33.4", "vue": "^2.7.16", "vuedraggable": "^2.24.3", "vuelidate": "^0.7.7", @@ -25,17 +25,17 @@ }, "devDependencies": { "@vitejs/plugin-vue2": "^2.3.1", - "eslint": "^8.57.0", + "eslint": "^9.0.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-vue": "^9.23.0", - "glob": "^10.3.10", + "eslint-plugin-vue": "^9.24.1", + "glob": "^10.3.12", "jsdom": "^24.0.0", "prettier": "^3.2.5", - "rollup-plugin-external-globals": "^0.9.2", - "terser": "^5.29.2", - "vite": "^5.2.4", - "vite-plugin-static-copy": "^1.0.1", - "vitest": "^1.4.0", + "rollup-plugin-external-globals": "^0.10.0", + "terser": "^5.30.3", + "vite": "^5.2.8", + "vite-plugin-static-copy": "^1.0.2", + "vitest": "^1.5.0", "vue-docgen-api": "^4.78.0", "vue-template-compiler": "^2.7.16" } @@ -485,15 +485,15 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -501,28 +501,57 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.0.0.tgz", + "integrity": "sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.12.3.tgz", + "integrity": "sha512-jsNnTBlMWuTpDkeE3on7+dWJi0D6fdDfeANj/w7MpS8ztROCoLvIO2nG0CcFj+E4k8j4QrSTh4Oryi3i2G669g==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -544,9 +573,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@isaacs/cliui": { @@ -922,12 +951,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@vitejs/plugin-vue2": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue2/-/plugin-vue2-2.3.1.tgz", @@ -942,13 +965,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz", - "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz", + "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==", "dev": true, "dependencies": { - "@vitest/spy": "1.4.0", - "@vitest/utils": "1.4.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "chai": "^4.3.10" }, "funding": { @@ -956,12 +979,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz", - "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", + "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", "dev": true, "dependencies": { - "@vitest/utils": "1.4.0", + "@vitest/utils": "1.5.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -997,9 +1020,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz", - "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", + "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -1017,9 +1040,9 @@ "dev": true }, "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", + "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -1029,9 +1052,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz", - "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz", + "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -1041,9 +1064,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", + "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -1144,9 +1167,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1717,18 +1740,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", @@ -1816,41 +1827,37 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.0.0.tgz", + "integrity": "sha512-IMryZ5SudxzQvuod6rUdIUz29qFItWx281VhtFVc2Psy/ZhlCeD/5DT6lBIJ4H3G+iamGJoTln1v+QSuPw0p7Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/eslintrc": "^3.0.2", + "@eslint/js": "9.0.0", + "@humanwhocodes/config-array": "^0.12.3", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", @@ -1864,7 +1871,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1883,12 +1890,13 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.23.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.23.0.tgz", - "integrity": "sha512-Bqd/b7hGYGrlV+wP/g77tjyFmp81lh5TMw0be9093X02SyelxRRfCI6/IsGq/J7Um0YwB9s0Ry0wlFyjPdmtUw==", + "version": "9.24.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz", + "integrity": "sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", "postcss-selector-parser": "^6.0.15", @@ -1900,7 +1908,22 @@ "node": "^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-scope": { @@ -1931,6 +1954,51 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esm-resolve": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/esm-resolve/-/esm-resolve-1.0.8.tgz", @@ -2094,15 +2162,15 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -2134,22 +2202,22 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/for-each": { @@ -2177,12 +2245,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2239,16 +2301,16 @@ } }, "node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -2297,15 +2359,12 @@ } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2470,9 +2529,9 @@ } }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -2503,16 +2562,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -2851,6 +2900,12 @@ "node": ">=18" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2891,6 +2946,15 @@ "promise": "^7.0.1" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3175,9 +3239,9 @@ } }, "node_modules/lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -3408,15 +3472,6 @@ "node": ">= 0.4" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -3517,15 +3572,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3542,12 +3588,12 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dev": true, "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -3747,9 +3793,9 @@ } }, "node_modules/prosemirror-model": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.19.4.tgz", - "integrity": "sha512-RPmVXxUfOhyFdayHawjuZCxiROsm9L4FCUA6pWI+l7n2yCBsWy9VpdE1hpDHUS8Vad661YLY9AzqfjLhAKQ4iQ==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.20.0.tgz", + "integrity": "sha512-q7AY7vMjKYqDCeoedgUiAgrLabliXxndJuuFmcmc2+YU1SblvnOiG2WEACF2lwAZsMlfLpiAilA3L+TWlDqIsQ==", "dependencies": { "orderedmap": "^2.0.0" } @@ -3783,11 +3829,11 @@ } }, "node_modules/prosemirror-view": { - "version": "1.33.3", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.3.tgz", - "integrity": "sha512-P4Ao/bc4OrU/2yLIf8dL4lJaEtjLR3QjIvQHgJYp2jUS7kYM4bSR6okbBjkqzOs/FwUon6UGjTLdKMnPL1MZqw==", + "version": "1.33.4", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.4.tgz", + "integrity": "sha512-xQqAhH8/HGleVpKDhQsrd+oqdyeKMxFtdCWDxWMmP+n0k27fBpyUqa8pA+RB5cFY8rqDDc1hll69aRZQa7UaAw==", "dependencies": { - "prosemirror-model": "^1.16.0", + "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0" } @@ -4033,41 +4079,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/rollup": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", @@ -4101,9 +4112,9 @@ } }, "node_modules/rollup-plugin-external-globals": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-external-globals/-/rollup-plugin-external-globals-0.9.2.tgz", - "integrity": "sha512-BUzbNhcN20irgWFNOL9XYSAN8pVRL7BfyZJce7oJMxjgPuxMOlQo3oTp3LRH1ehddXQEnp0/XxglMisl/GhnJQ==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-external-globals/-/rollup-plugin-external-globals-0.10.0.tgz", + "integrity": "sha512-RXlupZrmn97AaaS5dWnktkjM+Iy+od0E+8L0mUkMIs3iuoUXNJebueQocQKV7Ircd54fSGGmkBaXwNzY05J1yQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.1.0", @@ -4455,9 +4466,9 @@ "dev": true }, "node_modules/terser": { - "version": "5.29.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", - "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -4491,9 +4502,9 @@ "dev": true }, "node_modules/tinypool": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz", - "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.3.tgz", + "integrity": "sha512-Ud7uepAklqRH1bvwy22ynrliC7Dljz7Tm8M/0RBUW+YRa4YHhZ6e4PpgE+fu1zr/WqB1kbeuVrdfeuyIBpy4tw==", "dev": true, "engines": { "node": ">=14.0.0" @@ -4678,13 +4689,13 @@ "dev": true }, "node_modules/vite": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.4.tgz", - "integrity": "sha512-vjFghvHWidBTinu5TCymJk/lRHlR5ljqB83yugr0HA1xspUPdOZHqbqDLnZ8f9/jINrtFHTCYYyIUi+o+Q5iyg==", + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", + "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", "dev": true, "dependencies": { "esbuild": "^0.20.1", - "postcss": "^8.4.36", + "postcss": "^8.4.38", "rollup": "^4.13.0" }, "bin": { @@ -4733,9 +4744,9 @@ } }, "node_modules/vite-node": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz", - "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", + "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -4755,9 +4766,9 @@ } }, "node_modules/vite-plugin-static-copy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.1.tgz", - "integrity": "sha512-3eGL4mdZoPJMDBT68pv/XKIHR4MgVolStIxxv1gIBP4R8TpHn9C9EnaU0hesqlseJ4ycLGUxckFTu/jpuJXQlA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.2.tgz", + "integrity": "sha512-AfmEF+a/mfjsUsrgjbCkhzUCeIUF4EKQXXt3Ie1cour9MBpy6f6GphbdW2td28oYfOrwCyRzFCksgLkpk58q6Q==", "dev": true, "dependencies": { "chokidar": "^3.5.3", @@ -4787,16 +4798,16 @@ } }, "node_modules/vitest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz", - "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", + "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", "dev": true, "dependencies": { - "@vitest/expect": "1.4.0", - "@vitest/runner": "1.4.0", - "@vitest/snapshot": "1.4.0", - "@vitest/spy": "1.4.0", - "@vitest/utils": "1.4.0", + "@vitest/expect": "1.5.0", + "@vitest/runner": "1.5.0", + "@vitest/snapshot": "1.5.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -4808,9 +4819,9 @@ "std-env": "^3.5.0", "strip-literal": "^2.0.0", "tinybench": "^2.5.1", - "tinypool": "^0.8.2", + "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.4.0", + "vite-node": "1.5.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -4825,8 +4836,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.4.0", - "@vitest/ui": "1.4.0", + "@vitest/browser": "1.5.0", + "@vitest/ui": "1.5.0", "happy-dom": "*", "jsdom": "*" }, @@ -5234,12 +5245,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/ws": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", diff --git a/panel/package.json b/panel/package.json index 1ae9821d24..a9e2b9e3f1 100644 --- a/panel/package.json +++ b/panel/package.json @@ -20,9 +20,9 @@ "prosemirror-history": "^1.4.0", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", - "prosemirror-model": "^1.19.4", + "prosemirror-model": "^1.20.0", "prosemirror-schema-list": "^1.3.0", - "prosemirror-view": "^1.33.3", + "prosemirror-view": "^1.33.4", "vue": "^2.7.16", "vuedraggable": "^2.24.3", "vuelidate": "^0.7.7", @@ -30,17 +30,17 @@ }, "devDependencies": { "@vitejs/plugin-vue2": "^2.3.1", - "eslint": "^8.57.0", + "eslint": "^9.0.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-vue": "^9.23.0", - "glob": "^10.3.10", + "eslint-plugin-vue": "^9.24.1", + "glob": "^10.3.12", "jsdom": "^24.0.0", "prettier": "^3.2.5", - "rollup-plugin-external-globals": "^0.9.2", - "terser": "^5.29.2", - "vite": "^5.2.4", - "vite-plugin-static-copy": "^1.0.1", - "vitest": "^1.4.0", + "rollup-plugin-external-globals": "^0.10.0", + "terser": "^5.30.3", + "vite": "^5.2.8", + "vite-plugin-static-copy": "^1.0.2", + "vitest": "^1.5.0", "vue-docgen-api": "^4.78.0", "vue-template-compiler": "^2.7.16" }, diff --git a/panel/src/components/Dialogs/LicenseDialog.vue b/panel/src/components/Dialogs/LicenseDialog.vue index d3493af29b..3e936d6b42 100644 --- a/panel/src/components/Dialogs/LicenseDialog.vue +++ b/panel/src/components/Dialogs/LicenseDialog.vue @@ -47,7 +47,6 @@ export const props = { mixins: [Dialog], props: { license: Object, - // eslint-disable-next-line vue/require-prop-types size: { default: "large" } diff --git a/panel/src/components/Dialogs/SearchDialog.vue b/panel/src/components/Dialogs/SearchDialog.vue index 25080ba6e9..686f7ae98e 100644 --- a/panel/src/components/Dialogs/SearchDialog.vue +++ b/panel/src/components/Dialogs/SearchDialog.vue @@ -155,7 +155,7 @@ export default { const response = await this.$search(this.current, this.query); this.items = response.results; this.pagination = response.pagination; - } catch (error) { + } catch { this.items = []; this.pagination = {}; } finally { diff --git a/panel/src/components/Forms/Field/ObjectField.vue b/panel/src/components/Forms/Field/ObjectField.vue index f85b2cbbd0..82a70ab847 100644 --- a/panel/src/components/Forms/Field/ObjectField.vue +++ b/panel/src/components/Forms/Field/ObjectField.vue @@ -123,8 +123,6 @@ export default { this.object = {}; this.save(); }, - // TODO: field is not yet used to pre-focus correct field - // eslint-disable-next-line no-unused-vars open(field) { if (this.disabled) { return false; diff --git a/panel/src/components/Forms/FormButtons.vue b/panel/src/components/Forms/FormButtons.vue index 869b20b6fa..ae97c175e6 100644 --- a/panel/src/components/Forms/FormButtons.vue +++ b/panel/src/components/Forms/FormButtons.vue @@ -230,7 +230,7 @@ export default { if (lock === true) { try { await this.$api.patch(...this.api); - } catch (error) { + } catch { // If setting lock failed, a competing lock has been set between // API calls. In that case, discard changes, stop setting lock clearInterval(this.isLocking); diff --git a/panel/src/components/Forms/Input/ColornameInput.vue b/panel/src/components/Forms/Input/ColornameInput.vue index aabaee7eec..eb49af01a9 100644 --- a/panel/src/components/Forms/Input/ColornameInput.vue +++ b/panel/src/components/Forms/Input/ColornameInput.vue @@ -68,7 +68,7 @@ export default { try { // first try to parse the color via the library return this.$library.colors.toString(value, this.format, this.alpha); - } catch (e) { + } catch { // if that fails, // create a new secret tester const test = document.createElement("div"); diff --git a/panel/src/components/Forms/Writer/Utils/markPasteRule.js b/panel/src/components/Forms/Writer/Utils/markPasteRule.js index b2df111409..a281986156 100644 --- a/panel/src/components/Forms/Writer/Utils/markPasteRule.js +++ b/panel/src/components/Forms/Writer/Utils/markPasteRule.js @@ -13,7 +13,6 @@ export default function (regexp, type, getAttrs) { const isLink = !!marks.filter((x) => x.type.name === "link")[0]; - // eslint-disable-next-line while (!isLink && (match = regexp.exec(text)) !== null) { if (parent?.type?.allowsMarkType(type) && match[1]) { const start = match.index; diff --git a/panel/src/components/Navigation/Pagination.vue b/panel/src/components/Navigation/Pagination.vue index fee41577e3..a981f60fb3 100644 --- a/panel/src/components/Navigation/Pagination.vue +++ b/panel/src/components/Navigation/Pagination.vue @@ -157,7 +157,7 @@ export default { offset: start - 1, total: this.total }); - } catch (e) { + } catch { // pagination stopped } }, diff --git a/panel/src/components/Views/SearchView.vue b/panel/src/components/Views/SearchView.vue index f4a001dd83..1e9a4e215b 100644 --- a/panel/src/components/Views/SearchView.vue +++ b/panel/src/components/Views/SearchView.vue @@ -125,7 +125,7 @@ export default { }); this.items = response.results; this.pagination = response.pagination; - } catch (error) { + } catch { this.items = []; this.pagination = {}; } finally { diff --git a/panel/src/helpers/embed.js b/panel/src/helpers/embed.js index d2999dfd6e..c378c83d39 100644 --- a/panel/src/helpers/embed.js +++ b/panel/src/helpers/embed.js @@ -14,7 +14,7 @@ export function youtube(url, doNotTrack = false) { try { uri = new URL(url); - } catch (e) { + } catch { return false; } @@ -103,7 +103,7 @@ export function vimeo(url, doNotTrack = false) { try { uri = new URL(url); - } catch (e) { + } catch { return false; } diff --git a/panel/src/helpers/link.js b/panel/src/helpers/link.js index db7d97d22b..554b601c5b 100644 --- a/panel/src/helpers/link.js +++ b/panel/src/helpers/link.js @@ -102,7 +102,7 @@ async function previewForFile(id, fields = ["filename", "panelImage"]) { label: file.filename, image: file.panelImage }; - } catch (e) { + } catch { return null; } } @@ -123,7 +123,7 @@ async function previewForPage(id, fields = ["title", "panelImage"]) { label: page.title, image: page.panelImage }; - } catch (e) { + } catch { return null; } } diff --git a/panel/src/helpers/upload.js b/panel/src/helpers/upload.js index a5d01343bc..515d21ed30 100644 --- a/panel/src/helpers/upload.js +++ b/panel/src/helpers/upload.js @@ -62,7 +62,7 @@ export default async (file, params) => { try { response = JSON.parse(event.target.response); - } catch (error) { + } catch { response = { status: "error", message: "The file could not be uploaded" diff --git a/panel/src/helpers/url.js b/panel/src/helpers/url.js index 378a68f39c..67acf99984 100644 --- a/panel/src/helpers/url.js +++ b/panel/src/helpers/url.js @@ -97,7 +97,7 @@ export function isUrl(url, strict) { // validate it try { new URL(url, window.location); - } catch (error) { + } catch { return false; } diff --git a/panel/src/store/modules/content.js b/panel/src/store/modules/content.js index 69729d3a4f..a3db508722 100644 --- a/panel/src/store/modules/content.js +++ b/panel/src/store/modules/content.js @@ -214,7 +214,7 @@ export default { try { data = JSON.parse(json); - } catch (e) { + } catch { // fail silently } From 24acf16e4c5660fc8141335072b4b717f1ec537f Mon Sep 17 00:00:00 2001 From: Lukas Bestle Date: Sun, 21 Apr 2024 18:03:58 +0200 Subject: [PATCH 011/125] Update check: Support for new license model Closes #5974 --- src/Cms/System/UpdateStatus.php | 55 ++++- tests/Cms/System/UpdateStatusTest.php | 192 ++++++++++++------ .../getkirby.com/security.json | 6 +- .../UpdateStatusTest/logic/basic.json | 14 +- 4 files changed, 201 insertions(+), 66 deletions(-) diff --git a/src/Cms/System/UpdateStatus.php b/src/Cms/System/UpdateStatus.php index b9e80e3d84..8adf65df0b 100644 --- a/src/Cms/System/UpdateStatus.php +++ b/src/Cms/System/UpdateStatus.php @@ -392,6 +392,46 @@ protected function filterArrayByVersion(array $array, array $filters, string $re }); } + /** + * Finds the maximum possible major update + * that is included with the current license + * + * @return string|null Version number of the update or + * `null` if no free update is possible + */ + protected function findMaximumFreeUpdate(): string|null + { + // get the timestamp of included updates + $renewal = $this->app->system()->license()->renewal(); + + if ($renewal === null || $this->data === null) { + return null; + } + + foreach ($this->data['versions'] ?? [] as $entry) { + $initialRelease = $entry['initialRelease'] ?? null; + $latest = $entry['latest'] ?? ''; + + // skip entries of irrelevant releases + if ( + is_string($initialRelease) !== true || + version_compare($latest, $this->currentVersion, '<=') === true + ) { + continue; + } + + $timestamp = strtotime($initialRelease); + + // update is free if the initial release was before the + // license renewal date + if (is_int($timestamp) === true && $timestamp < $renewal) { + return $latest; + } + } + + return null; + } + /** * Finds the minimum possible security update * to fix all known vulnerabilities @@ -655,7 +695,7 @@ protected function targetData(): array ]; } - // check if free updates are possible from the current version + // check if updates within the same major version are possible $latest = $versionEntry['latest'] ?? null; if (is_string($latest) === true && $latest !== $this->currentVersion) { return $this->targetData = [ @@ -665,6 +705,19 @@ protected function targetData(): array ]; } + // check if the license includes updates to a newer major version + if ($version = $this->findMaximumFreeUpdate()) { + // extract the part before the first dot + // to find the major release page URL + preg_match('/^(\w+)\./', $version, $matches); + + return $this->targetData = [ + 'status' => 'update', + 'url' => $this->urlFor($matches[1] . '.0', 'changes'), + 'version' => $version + ]; + } + // no free update is possible, but we are not on the latest version, // so the overall latest version must be an upgrade return $this->targetData = [ diff --git a/tests/Cms/System/UpdateStatusTest.php b/tests/Cms/System/UpdateStatusTest.php index 70f4b1d7b4..8e9c895e05 100644 --- a/tests/Cms/System/UpdateStatusTest.php +++ b/tests/Cms/System/UpdateStatusTest.php @@ -2,10 +2,12 @@ namespace Kirby\Cms\System; +use Kirby\Cms\License; use Kirby\Cms\Plugin; use Kirby\Data\Json; use Kirby\Filesystem\Dir; use Kirby\TestCase; +use ReflectionProperty; /** * @coversDefaultClass \Kirby\Cms\System\UpdateStatus @@ -55,7 +57,8 @@ public function testLoadData() '*' => [ 'description' => 'Actively supported', 'latest' => '88888.8.8', - 'status' => 'active-support' + 'status' => 'active-support', + 'initialRelease' => '2023-11-28' ] ], 'urls' => [ @@ -68,7 +71,8 @@ public function testLoadData() 'php' => [ '8.0' => '2023-11-26', '8.1' => '2024-11-25', - '8.2' => '2025-12-08' + '8.2' => '2025-12-08', + '8.3' => '2026-11-23' ], 'incidents' => [], 'messages' => [], @@ -87,13 +91,15 @@ public function testLoadDataCacheKirby() 'versions' => [ '*' => [ 'latest' => '88888.8.6', - 'status' => 'active-support' + 'status' => 'active-support', + 'initialRelease' => '2023-11-28' ] ], 'php' => [ '8.0' => '2023-11-26', '8.1' => '2024-11-25', - '8.2' => '2025-12-08' + '8.2' => '2025-12-08', + '8.3' => '2026-11-23' ], 'urls' => [ '*' => [ @@ -123,7 +129,8 @@ public function testLoadDataCacheKirby() '*' => [ 'description' => 'Actively supported', 'latest' => '88888.8.8', - 'status' => 'active-support' + 'status' => 'active-support', + 'initialRelease' => '2023-11-28' ] ], 'urls' => [ @@ -136,7 +143,8 @@ public function testLoadDataCacheKirby() 'php' => [ '8.0' => '2023-11-26', '8.1' => '2024-11-25', - '8.2' => '2025-12-08' + '8.2' => '2025-12-08', + '8.3' => '2026-11-23' ], 'incidents' => [], 'messages' => [], @@ -241,7 +249,8 @@ public function testLoadDataCacheInvalid() '*' => [ 'description' => 'Actively supported', 'latest' => '88888.8.8', - 'status' => 'active-support' + 'status' => 'active-support', + 'initialRelease' => '2023-11-28' ] ], 'urls' => [ @@ -254,7 +263,8 @@ public function testLoadDataCacheInvalid() 'php' => [ '8.0' => '2023-11-26', '8.1' => '2024-11-25', - '8.2' => '2025-12-08' + '8.2' => '2025-12-08', + '8.3' => '2026-11-23' ], 'incidents' => [], 'messages' => [], @@ -353,12 +363,12 @@ public function testLoadDataNotJson() */ public function testLogic( string $packageType, - string|null $version, + array $packageData, bool $securityOnly, array|null $data, array $expected ) { - $package = $this->$packageType($version); + $package = $this->$packageType(...$packageData); $updateStatus = new UpdateStatus($package, $securityOnly, $data); foreach ($expected as $method => $value) { @@ -372,7 +382,7 @@ public static function logicProvider(): array // update check (Kirby) 'Kirby up-to-date' => [ 'app', - '88888.8.8', + ['88888.8.8'], false, static::data('basic'), [ @@ -391,7 +401,7 @@ public static function logicProvider(): array ], 'Kirby unreleased' => [ 'app', - '88888.8.9-rc.1', + ['88888.8.9-rc.1'], false, static::data('basic'), [ @@ -410,7 +420,7 @@ public static function logicProvider(): array ], 'Kirby security-update' => [ 'app', - '77777.1.2', + ['77777.1.2'], false, static::data('basic'), [ @@ -443,7 +453,7 @@ public static function logicProvider(): array ], 'Kirby security-upgrade' => [ 'app', - '55555.1.2', + ['55555.1.2'], false, static::data('basic'), [ @@ -476,7 +486,7 @@ public static function logicProvider(): array ], 'Kirby not-vulnerable (update "no-vulnerabilities")' => [ 'app', - '77777.7.6', + ['77777.7.6'], true, static::data('basic'), [ @@ -495,7 +505,7 @@ public static function logicProvider(): array ], 'Kirby not-vulnerable (update)' => [ 'app', - '66666.6.5', + ['66666.6.5'], true, static::data('basic'), [ @@ -512,9 +522,28 @@ public static function logicProvider(): array 'exceptionMessages' => [] ] ], + 'Kirby not-vulnerable (free major update)' => [ + 'app', + ['66666.6.6', '2023-11-28'], + true, + static::data('basic'), + [ + 'currentVersion' => '66666.6.6', + 'icon' => 'check', + 'label' => 'No known vulnerabilities', + 'latestVersion' => '88888.8.8', + 'messages' => [], + 'status' => 'not-vulnerable', + 'targetVersion' => null, + 'theme' => 'positive', + 'url' => 'https://getkirby.com/old-releases/66666.6.6', + 'vulnerabilities' => [], + 'exceptionMessages' => [] + ] + ], 'Kirby not-vulnerable (upgrade)' => [ 'app', - '77777.7.7', + ['77777.7.7'], true, static::data('basic'), [ @@ -533,7 +562,7 @@ public static function logicProvider(): array ], 'Kirby update' => [ 'app', - '77777.7.6', + ['77777.7.6'], false, static::data('basic'), [ @@ -550,9 +579,47 @@ public static function logicProvider(): array 'exceptionMessages' => [] ] ], - 'Kirby upgrade' => [ + 'Kirby free major update' => [ + 'app', + ['66666.6.6', '2023-11-28'], + false, + static::data('basic'), + [ + 'currentVersion' => '66666.6.6', + 'icon' => 'info', + 'label' => 'Free update 77777.7.7 available', + 'latestVersion' => '88888.8.8', + 'messages' => [], + 'status' => 'update', + 'targetVersion' => '77777.7.7', + 'theme' => 'info', + 'url' => 'https://getkirby.com/old-releases/77777.0', + 'vulnerabilities' => [], + 'exceptionMessages' => [] + ] + ], + 'Kirby upgrade (without license)' => [ 'app', - '77777.7.7', + ['77777.7.7'], + false, + static::data('basic'), + [ + 'currentVersion' => '77777.7.7', + 'icon' => 'info', + 'label' => 'Upgrade 88888.8.8 available', + 'latestVersion' => '88888.8.8', + 'messages' => [], + 'status' => 'upgrade', + 'targetVersion' => '88888.8.8', + 'theme' => 'info', + 'url' => 'https://getkirby.com/releases/88888', + 'vulnerabilities' => [], + 'exceptionMessages' => [] + ] + ], + 'Kirby upgrade (with inactive license)' => [ + 'app', + ['77777.7.7', '2023-11-28'], false, static::data('basic'), [ @@ -573,7 +640,7 @@ public static function logicProvider(): array // update check (plugin) 'Plugin up-to-date' => [ 'plugin', - '88888.8.8', + ['88888.8.8'], false, static::data('basic'), [ @@ -595,7 +662,7 @@ public static function logicProvider(): array ], 'Plugin unreleased' => [ 'plugin', - '88888.8.9-rc.1', + ['88888.8.9-rc.1'], false, static::data('basic'), [ @@ -617,7 +684,7 @@ public static function logicProvider(): array ], 'Plugin security-update' => [ 'plugin', - '77777.1.2', + ['77777.1.2'], false, static::data('basic'), [ @@ -656,7 +723,7 @@ public static function logicProvider(): array ], 'Plugin security-upgrade' => [ 'plugin', - '55555.1.2', + ['55555.1.2'], false, static::data('basic'), [ @@ -695,7 +762,7 @@ public static function logicProvider(): array ], 'Plugin update' => [ 'plugin', - '77777.7.6', + ['77777.7.6'], false, static::data('basic'), [ @@ -717,7 +784,7 @@ public static function logicProvider(): array ], 'Plugin upgrade' => [ 'plugin', - '77777.7.7', + ['77777.7.7'], false, static::data('basic'), [ @@ -739,7 +806,7 @@ public static function logicProvider(): array ], 'Plugin with prefix' => [ 'plugin', - 'v77777.7.7', + ['v77777.7.7'], false, static::data('basic'), [ @@ -761,7 +828,7 @@ public static function logicProvider(): array ], 'Plugin with invalid version' => [ 'plugin', - 'not a version', + ['not a version'], false, static::data('basic'), [ @@ -783,7 +850,7 @@ public static function logicProvider(): array ], 'Plugin without version' => [ 'plugin', - null, + [null], false, static::data('basic'), [ @@ -807,7 +874,7 @@ public static function logicProvider(): array // vulnerabilities 'Vulnerability sorting' => [ 'app', - '77777.1.2', + ['77777.1.2'], false, static::data('incidents-severity'), [ @@ -888,7 +955,7 @@ public static function logicProvider(): array ], 'Unstable release' => [ 'app', - '77777.0.0-rc.1', + ['77777.0.0-rc.1'], false, static::data('basic'), [ @@ -921,7 +988,7 @@ public static function logicProvider(): array ], 'Minimum security update' => [ 'app', - '77777.1.2', + ['77777.1.2'], false, static::data('incidents-cascade'), [ @@ -954,7 +1021,7 @@ public static function logicProvider(): array ], 'Incidents with infinite loop' => [ 'app', - '77777.1.2', + ['77777.1.2'], false, static::data('incidents-loop'), [ @@ -989,7 +1056,7 @@ public static function logicProvider(): array // messages 'Messages' => [ 'app', - '77777.6.0', + ['77777.6.0'], false, static::data('basic'), [ @@ -1014,7 +1081,7 @@ public static function logicProvider(): array ], 'EOL warning (Kirby)' => [ 'app', - '44444.1.2', + ['44444.1.2'], false, static::data('basic'), [ @@ -1052,7 +1119,7 @@ public static function logicProvider(): array ], 'EOL warning (plugin)' => [ 'plugin', - '44444.1.2', + ['44444.1.2'], false, static::data('basic'), [ @@ -1090,7 +1157,7 @@ public static function logicProvider(): array ], 'EOL warning (PHP)' => [ 'app', - '88888.8.8', + ['88888.8.8'], false, static::data('php'), [ @@ -1117,7 +1184,7 @@ public static function logicProvider(): array ], 'EOL warning with custom link' => [ 'app', - '44444.1.2', + ['44444.1.2'], false, static::data('eol-link'), [ @@ -1157,7 +1224,7 @@ public static function logicProvider(): array // invalid/incomplete data array 'No data' => [ 'plugin', - '77777.7.7', + ['77777.7.7'], false, null, [ @@ -1179,7 +1246,7 @@ public static function logicProvider(): array ], 'Empty data' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, [], [ @@ -1201,7 +1268,7 @@ public static function logicProvider(): array ], 'No latest version (update)' => [ 'app', - '77777.7.5', + ['77777.7.5'], false, static::data('no-latest'), [ @@ -1220,7 +1287,7 @@ public static function logicProvider(): array ], 'No latest version (upgrade)' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-latest'), [ @@ -1239,7 +1306,7 @@ public static function logicProvider(): array ], 'No versions' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-versions'), [ @@ -1260,7 +1327,7 @@ public static function logicProvider(): array ], 'No URLs' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-urls'), [ @@ -1281,7 +1348,7 @@ public static function logicProvider(): array ], 'No PHP' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-php'), [ @@ -1300,7 +1367,7 @@ public static function logicProvider(): array ], 'No incidents' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-incidents'), [ @@ -1319,7 +1386,7 @@ public static function logicProvider(): array ], 'No messages' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-messages'), [ @@ -1338,7 +1405,7 @@ public static function logicProvider(): array ], 'Missing URL entry' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-url-entry'), [ @@ -1359,7 +1426,7 @@ public static function logicProvider(): array ], 'URL entry without `changes` key' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('url-entry-without-changes'), [ @@ -1380,7 +1447,7 @@ public static function logicProvider(): array ], 'Missing version entry' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('no-version-entry'), [ @@ -1401,7 +1468,7 @@ public static function logicProvider(): array ], 'Missing version entry (with vulnerability)' => [ 'app', - '77777.4.3', + ['77777.4.3'], false, static::data('no-version-entry'), [ @@ -1436,7 +1503,7 @@ public static function logicProvider(): array ], 'Version entry without `latest` key' => [ 'app', - '77777.7.5', + ['77777.7.5'], false, static::data('version-entry-without-latest'), [ @@ -1455,7 +1522,7 @@ public static function logicProvider(): array ], 'Invalid constraint (message)' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('invalid-constraint-message'), [ @@ -1479,7 +1546,7 @@ public static function logicProvider(): array ], 'Invalid constraint (incident)' => [ 'app', - '77777.3.2', + ['77777.3.2'], false, static::data('invalid-constraint-incident'), [ @@ -1501,7 +1568,7 @@ public static function logicProvider(): array ], 'Invalid constraint (URL entry)' => [ 'app', - '77777.7.5', + ['77777.7.5'], false, static::data('invalid-constraint-url'), [ @@ -1523,7 +1590,7 @@ public static function logicProvider(): array ], 'Invalid constraint (version entry)' => [ 'app', - '77777.7.5', + ['77777.7.5'], false, static::data('invalid-constraint-version'), [ @@ -1545,7 +1612,7 @@ public static function logicProvider(): array ], 'Missing constraint (message)' => [ 'app', - '77777.7.7', + ['77777.7.7'], false, static::data('missing-constraint-message'), [ @@ -1567,7 +1634,7 @@ public static function logicProvider(): array ], 'Missing constraint (incident)' => [ 'app', - '77777.3.2', + ['77777.3.2'], false, static::data('missing-constraint-incident'), [ @@ -1610,14 +1677,19 @@ public function testMessagesCache() $this->assertSame($expected, $updateStatus->messages()); } - protected function app(string $version): MockApp + protected function app(string $version, string|null $activation = null): MockApp { MockApp::$version = $version; - return new MockApp([ + $app = new MockApp([ 'roots' => [ 'index' => static::TMP ] ]); + + $property = new ReflectionProperty($app->system(), 'license'); + $property->setValue($app->system(), new License(activation: $activation)); + + return $app; } protected static function data(string $name): array diff --git a/tests/Cms/System/fixtures/UpdateStatusTest/getkirby.com/security.json b/tests/Cms/System/fixtures/UpdateStatusTest/getkirby.com/security.json index 868f081be8..ae35bd070c 100644 --- a/tests/Cms/System/fixtures/UpdateStatusTest/getkirby.com/security.json +++ b/tests/Cms/System/fixtures/UpdateStatusTest/getkirby.com/security.json @@ -8,7 +8,8 @@ "*": { "description": "Actively supported", "latest": "88888.8.8", - "status": "active-support" + "status": "active-support", + "initialRelease": "2023-11-28" } }, "urls": { @@ -21,7 +22,8 @@ "php": { "8.0": "2023-11-26", "8.1": "2024-11-25", - "8.2": "2025-12-08" + "8.2": "2025-12-08", + "8.3": "2026-11-23" }, "incidents": [], "messages": [] diff --git a/tests/Cms/System/fixtures/UpdateStatusTest/logic/basic.json b/tests/Cms/System/fixtures/UpdateStatusTest/logic/basic.json index 87387e462d..e613bc99ea 100644 --- a/tests/Cms/System/fixtures/UpdateStatusTest/logic/basic.json +++ b/tests/Cms/System/fixtures/UpdateStatusTest/logic/basic.json @@ -7,17 +7,25 @@ ">=77777.5.5": { "status": "no-vulnerabilities" }, + "88888.*": { + "latest": "88888.8.8", + "status": "active-support", + "initialRelease": "2027-10-05" + }, "77777.*": { "latest": "77777.7.7", - "status": "active-support" + "status": "active-support", + "initialRelease": "2026-10-05" }, "66666.*": { "latest": "66666.6.6", - "status": "security-support" + "status": "security-support", + "initialRelease": "2025-10-05" }, "55555.*": { "latest": "55555.5.5", - "status": "security-support" + "status": "security-support", + "initialRelease": "2024-10-05" }, "<55555.0.0": { "latest": "44444.4.4", From 251d8cd910cfa9943c2ace37fd5076a802540f81 Mon Sep 17 00:00:00 2001 From: Ahmet Bora Date: Tue, 23 Apr 2024 13:23:11 +0300 Subject: [PATCH 012/125] Fix email dialog title prop translation #6402 --- panel/src/components/Dialogs/EmailDialog.vue | 2 +- .../components/Forms/Toolbar/EmailDialog.vue | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/panel/src/components/Dialogs/EmailDialog.vue b/panel/src/components/Dialogs/EmailDialog.vue index 0ac36037d6..6e01554d33 100644 --- a/panel/src/components/Dialogs/EmailDialog.vue +++ b/panel/src/components/Dialogs/EmailDialog.vue @@ -24,7 +24,7 @@ export default { icon: "email" }, title: { - label: window.panel.$t("link.text"), + label: window.panel.$t("title"), type: "text", icon: "title" } diff --git a/panel/src/components/Forms/Toolbar/EmailDialog.vue b/panel/src/components/Forms/Toolbar/EmailDialog.vue index f12b3cc920..3c1c225615 100644 --- a/panel/src/components/Forms/Toolbar/EmailDialog.vue +++ b/panel/src/components/Forms/Toolbar/EmailDialog.vue @@ -3,6 +3,23 @@ import EmailDialog from "@/components/Dialogs/EmailDialog.vue"; export default { extends: EmailDialog, + props: { + // eslint-disable-next-line vue/require-prop-types + fields: { + default: () => ({ + href: { + label: window.panel.$t("email"), + type: "email", + icon: "email" + }, + title: { + label: window.panel.$t("link.text"), + type: "text", + icon: "title" + } + }) + }, + }, methods: { submit() { const email = this.values.href ?? ""; From 592618109490eaee5537c15f653c56e1b72f87a2 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Tue, 23 Apr 2024 21:48:44 +0200 Subject: [PATCH 013/125] CSS `data-theme` with color names --- panel/src/styles/utilities/theme.css | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/panel/src/styles/utilities/theme.css b/panel/src/styles/utilities/theme.css index b6a882ef46..4298247060 100644 --- a/panel/src/styles/utilities/theme.css +++ b/panel/src/styles/utilities/theme.css @@ -32,6 +32,7 @@ } /* Color themes */ +[data-theme="red"], [data-theme="error"], [data-theme="negative"] { --theme-color-h: var(--color-red-h); @@ -39,36 +40,53 @@ --theme-color-boost: var(--color-red-boost); } +[data-theme="orange"], [data-theme="notice"] { --theme-color-h: var(--color-orange-h); --theme-color-s: var(--color-orange-s); --theme-color-boost: var(--color-orange-boost); } +[data-theme="yellow"], [data-theme="warning"] { --theme-color-h: var(--color-yellow-h); --theme-color-s: var(--color-yellow-s); --theme-color-boost: var(--color-yellow-boost); } +[data-theme="blue"], [data-theme="info"] { --theme-color-h: var(--color-blue-h); --theme-color-s: var(--color-blue-s); --theme-color-boost: var(--color-blue-boost); } +[data-theme="pink"], [data-theme="love"] { --theme-color-h: var(--color-pink-h); --theme-color-s: var(--color-pink-s); --theme-color-boost: var(--color-pink-boost); } +[data-theme="green"], [data-theme="positive"] { --theme-color-h: var(--color-green-h); --theme-color-s: var(--color-green-s); --theme-color-boost: var(--color-green-boost); } +[data-theme="aqua"] { + --theme-color-h: var(--color-aqua-h); + --theme-color-s: var(--color-aqua-s); + --theme-color-boost: var(--color-aqua-boost); +} + +[data-theme="purple"] { + --theme-color-h: var(--color-purple-h); + --theme-color-s: var(--color-purple-s); + --theme-color-boost: var(--color-purple-boost); +} + [data-theme="passive"] { --theme-color-h: var(--color-gray-h); --theme-color-s: var(--color-gray-s); From d570140d86f1e0996f202485ad1583ffe133c86e Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 24 Apr 2024 15:33:27 +0200 Subject: [PATCH 014/125] Theme lab examples --- panel/lab/basics/utilities/theme/index.vue | 144 +++++++++++++++++++++ panel/src/styles/utilities/theme.css | 1 + 2 files changed, 145 insertions(+) create mode 100644 panel/lab/basics/utilities/theme/index.vue diff --git a/panel/lab/basics/utilities/theme/index.vue b/panel/lab/basics/utilities/theme/index.vue new file mode 100644 index 0000000000..8e6df65d8d --- /dev/null +++ b/panel/lab/basics/utilities/theme/index.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/panel/src/styles/utilities/theme.css b/panel/src/styles/utilities/theme.css index 4298247060..81587655fe 100644 --- a/panel/src/styles/utilities/theme.css +++ b/panel/src/styles/utilities/theme.css @@ -87,6 +87,7 @@ --theme-color-boost: var(--color-purple-boost); } +[data-theme="gray"], [data-theme="passive"] { --theme-color-h: var(--color-gray-h); --theme-color-s: var(--color-gray-s); From 9fd6ec96761d999045cae730b625dfde60a83512 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 11 Apr 2024 20:44:22 +0200 Subject: [PATCH 015/125] `k-button`: New `variant` for only colored icon --- panel/src/components/Navigation/Button.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/panel/src/components/Navigation/Button.vue b/panel/src/components/Navigation/Button.vue index 9a5de5b66b..fb276f830f 100644 --- a/panel/src/components/Navigation/Button.vue +++ b/panel/src/components/Navigation/Button.vue @@ -307,13 +307,12 @@ export default { --button-color-text: var(--button-color-dimmed-off); } .k-button:where([data-theme][data-variant="dimmed"]) { - --button-color-icon: var(--theme-color-icon); --button-color-dimmed-on: var(--theme-color-text-dimmed); --button-color-dimmed-off: var(--theme-color-text); } /** Filled Buttons **/ -.k-button:where([data-variant="filled"]) { +.k-button:where([data-variant="filled"], [data-variant="filled-icon"]) { --button-color-back: var(--color-gray-300); } .k-button:where([data-variant="filled"]):not([aria-disabled]):hover { @@ -325,6 +324,11 @@ export default { --button-color-text: var(--theme-color-text); } +.k-button:where([data-theme][data-variant="filled-icon"]) { + --button-color-back: var(--color-gray-300); + --button-color-icon: var(--theme-color-600); +} + /** Icon Buttons **/ /** TODO: .k-button:not(:has(.k-button-text)) */ .k-button:not([data-has-text="true"]) { From 3b8ce345c60e4d59281881cd24d0019d180edeac Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 11 Apr 2024 21:01:53 +0200 Subject: [PATCH 016/125] `k-button`: `theme="positive-icon"` --- panel/src/components/Navigation/Button.vue | 14 ++++---- panel/src/components/Views/Pages/PageView.vue | 7 ---- panel/src/helpers/page.js | 6 ++-- panel/src/styles/utilities/theme.css | 36 +++++++++---------- 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/panel/src/components/Navigation/Button.vue b/panel/src/components/Navigation/Button.vue index fb276f830f..4a572786b7 100644 --- a/panel/src/components/Navigation/Button.vue +++ b/panel/src/components/Navigation/Button.vue @@ -312,23 +312,23 @@ export default { } /** Filled Buttons **/ -.k-button:where([data-variant="filled"], [data-variant="filled-icon"]) { +.k-button:where([data-variant="filled"]) { --button-color-back: var(--color-gray-300); } .k-button:where([data-variant="filled"]):not([aria-disabled]):hover { filter: brightness(97%); } -.k-button:where([data-theme][data-variant="filled"]) { +.k-button:where([data-theme$="-icon"][data-variant="filled"]) { + --button-color-icon: var(--theme-color-600); +} +.k-button:where([data-theme][data-variant="filled"]):not( + [data-theme$="-icon"] + ) { --button-color-icon: var(--theme-color-700); --button-color-back: var(--theme-color-back); --button-color-text: var(--theme-color-text); } -.k-button:where([data-theme][data-variant="filled-icon"]) { - --button-color-back: var(--color-gray-300); - --button-color-icon: var(--theme-color-600); -} - /** Icon Buttons **/ /** TODO: .k-button:not(:has(.k-button-text)) */ .k-button:not([data-has-text="true"]) { diff --git a/panel/src/components/Views/Pages/PageView.vue b/panel/src/components/Views/Pages/PageView.vue index 114be29bd7..8fc70db8c0 100644 --- a/panel/src/components/Views/Pages/PageView.vue +++ b/panel/src/components/Views/Pages/PageView.vue @@ -51,7 +51,6 @@ v-if="status" v-bind="statusBtn" class="k-page-view-status" - variant="filled" @click="$dialog(id + '/changeStatus')" /> @@ -106,10 +105,4 @@ export default { .k-page-view[data-has-tabs="true"] .k-page-view-header { margin-bottom: 0; } - -.k-page-view-status { - --button-color-back: var(--color-gray-300); - --button-color-icon: var(--theme-color-600); - --button-color-text: initial; -} diff --git a/panel/src/helpers/page.js b/panel/src/helpers/page.js index 8913549b51..af2a6bc0ad 100644 --- a/panel/src/helpers/page.js +++ b/panel/src/helpers/page.js @@ -24,11 +24,11 @@ export function status(status, disabled = false) { } if (status === "draft") { - button.theme = "negative"; + button.theme = "negative-icon"; } else if (status === "unlisted") { - button.theme = "info"; + button.theme = "info-icon"; } else { - button.theme = "positive"; + button.theme = "positive-icon"; } return button; diff --git a/panel/src/styles/utilities/theme.css b/panel/src/styles/utilities/theme.css index 81587655fe..3b04cf241b 100644 --- a/panel/src/styles/utilities/theme.css +++ b/panel/src/styles/utilities/theme.css @@ -32,63 +32,63 @@ } /* Color themes */ -[data-theme="red"], -[data-theme="error"], -[data-theme="negative"] { +[data-theme^="red"], +[data-theme^="error"], +[data-theme^="negative"] { --theme-color-h: var(--color-red-h); --theme-color-s: var(--color-red-s); --theme-color-boost: var(--color-red-boost); } -[data-theme="orange"], -[data-theme="notice"] { +[data-theme^="orange"], +[data-theme^="notice"] { --theme-color-h: var(--color-orange-h); --theme-color-s: var(--color-orange-s); --theme-color-boost: var(--color-orange-boost); } -[data-theme="yellow"], -[data-theme="warning"] { +[data-theme^="yellow"], +[data-theme^="warning"] { --theme-color-h: var(--color-yellow-h); --theme-color-s: var(--color-yellow-s); --theme-color-boost: var(--color-yellow-boost); } -[data-theme="blue"], -[data-theme="info"] { +[data-theme^="blue"], +[data-theme^="info"] { --theme-color-h: var(--color-blue-h); --theme-color-s: var(--color-blue-s); --theme-color-boost: var(--color-blue-boost); } -[data-theme="pink"], -[data-theme="love"] { +[data-theme^="pink"], +[data-theme^="love"] { --theme-color-h: var(--color-pink-h); --theme-color-s: var(--color-pink-s); --theme-color-boost: var(--color-pink-boost); } -[data-theme="green"], -[data-theme="positive"] { +[data-theme^="green"], +[data-theme^="positive"] { --theme-color-h: var(--color-green-h); --theme-color-s: var(--color-green-s); --theme-color-boost: var(--color-green-boost); } -[data-theme="aqua"] { +[data-theme^="aqua"] { --theme-color-h: var(--color-aqua-h); --theme-color-s: var(--color-aqua-s); --theme-color-boost: var(--color-aqua-boost); } -[data-theme="purple"] { +[data-theme^="purple"] { --theme-color-h: var(--color-purple-h); --theme-color-s: var(--color-purple-s); --theme-color-boost: var(--color-purple-boost); } -[data-theme="gray"], -[data-theme="passive"] { +[data-theme^="gray"], +[data-theme^="passive"] { --theme-color-h: var(--color-gray-h); --theme-color-s: var(--color-gray-s); --theme-color-boost: 10%; @@ -103,7 +103,7 @@ } /* Special Themes */ -[data-theme="dark"] { +[data-theme^="dark"] { --theme-color-h: var(--color-gray-h); --theme-color-s: var(--color-gray-s); --theme-color-boost: var(--color-gray-boost); From b1b3a758d5e2984be7476224dc126369192adf5b Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 11 Apr 2024 21:06:38 +0200 Subject: [PATCH 017/125] Simplify CSS --- panel/src/components/Navigation/Button.vue | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/panel/src/components/Navigation/Button.vue b/panel/src/components/Navigation/Button.vue index 4a572786b7..8b7afd7b34 100644 --- a/panel/src/components/Navigation/Button.vue +++ b/panel/src/components/Navigation/Button.vue @@ -318,11 +318,9 @@ export default { .k-button:where([data-variant="filled"]):not([aria-disabled]):hover { filter: brightness(97%); } -.k-button:where([data-theme$="-icon"][data-variant="filled"]) { - --button-color-icon: var(--theme-color-600); -} -.k-button:where([data-theme][data-variant="filled"]):not( - [data-theme$="-icon"] + +.k-button:where([data-theme]):not([data-theme$="-icon"]):where( + [data-variant="filled"] ) { --button-color-icon: var(--theme-color-700); --button-color-back: var(--theme-color-back); From 31d96d400a84e0adaa8a68323016aa2334b50e4c Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Tue, 23 Apr 2024 21:46:08 +0200 Subject: [PATCH 018/125] Fix regression --- panel/src/components/Navigation/Button.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/panel/src/components/Navigation/Button.vue b/panel/src/components/Navigation/Button.vue index 8b7afd7b34..5806bc0542 100644 --- a/panel/src/components/Navigation/Button.vue +++ b/panel/src/components/Navigation/Button.vue @@ -307,6 +307,7 @@ export default { --button-color-text: var(--button-color-dimmed-off); } .k-button:where([data-theme][data-variant="dimmed"]) { + --button-color-icon: var(--theme-color-icon); --button-color-dimmed-on: var(--theme-color-text-dimmed); --button-color-dimmed-off: var(--theme-color-text); } From 2c99ade92965e473028104e45fb79c81cd34dbd6 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 24 Apr 2024 15:47:29 +0200 Subject: [PATCH 019/125] Extend lab examples --- panel/lab/components/buttons/2_themes/index.php | 1 + panel/lab/components/buttons/2_themes/index.vue | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/panel/lab/components/buttons/2_themes/index.php b/panel/lab/components/buttons/2_themes/index.php index 9e3a1d31cf..3de529a8e3 100644 --- a/panel/lab/components/buttons/2_themes/index.php +++ b/panel/lab/components/buttons/2_themes/index.php @@ -7,6 +7,7 @@ 'warning', 'positive', 'info', + 'love', null, 'empty', ] diff --git a/panel/lab/components/buttons/2_themes/index.vue b/panel/lab/components/buttons/2_themes/index.vue index 2b6733e376..aee2f88d21 100644 --- a/panel/lab/components/buttons/2_themes/index.vue +++ b/panel/lab/components/buttons/2_themes/index.vue @@ -27,13 +27,24 @@ Button + + + Button + + From 435a3ce35ffda3f7ae8ff237166fa03b56c505d0 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 25 Apr 2024 10:54:13 +0200 Subject: [PATCH 020/125] Fix text color of only-icon themed filled btn --- panel/src/components/Navigation/Button.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panel/src/components/Navigation/Button.vue b/panel/src/components/Navigation/Button.vue index 5806bc0542..12a8b46314 100644 --- a/panel/src/components/Navigation/Button.vue +++ b/panel/src/components/Navigation/Button.vue @@ -292,6 +292,9 @@ export default { --button-color-icon: var(--theme-color-icon); --button-color-text: var(--theme-color-text); } +.k-button[data-theme$="-icon"] { + --button-color-text: currentColor; +} /** Dimmed Buttons **/ .k-button:where([data-variant="dimmed"]) { From 7db0c588076006fb40e1589e166d3ead5cc4d92b Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Thu, 25 Apr 2024 12:17:35 +0200 Subject: [PATCH 021/125] Improve theme and button styles --- .../lab/components/buttons/2_themes/index.php | 15 +++++---- .../lab/components/buttons/2_themes/index.vue | 24 +++++++++++--- panel/src/components/Navigation/Button.vue | 32 +++++++++++-------- panel/src/styles/utilities/theme.css | 10 ++++-- 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/panel/lab/components/buttons/2_themes/index.php b/panel/lab/components/buttons/2_themes/index.php index 3de529a8e3..7745db2cf1 100644 --- a/panel/lab/components/buttons/2_themes/index.php +++ b/panel/lab/components/buttons/2_themes/index.php @@ -2,13 +2,14 @@ return [ 'themes' => [ - 'negative', - 'notice', - 'warning', - 'positive', - 'info', - 'love', null, - 'empty', + 'red', + 'orange', + 'yellow', + 'green', + 'aqua', + 'blue', + 'purple', + 'pink', ] ]; diff --git a/panel/lab/components/buttons/2_themes/index.vue b/panel/lab/components/buttons/2_themes/index.vue index aee2f88d21..b360bab703 100644 --- a/panel/lab/components/buttons/2_themes/index.vue +++ b/panel/lab/components/buttons/2_themes/index.vue @@ -1,11 +1,11 @@ diff --git a/panel/src/components/Navigation/Button.vue b/panel/src/components/Navigation/Button.vue index 12a8b46314..e023dbff13 100644 --- a/panel/src/components/Navigation/Button.vue +++ b/panel/src/components/Navigation/Button.vue @@ -292,27 +292,28 @@ export default { --button-color-icon: var(--theme-color-icon); --button-color-text: var(--theme-color-text); } -.k-button[data-theme$="-icon"] { +.k-button:where([data-theme$="-icon"]) { --button-color-text: currentColor; } /** Dimmed Buttons **/ .k-button:where([data-variant="dimmed"]) { --button-color-icon: var(--color-text); - --button-color-dimmed-on: var(--color-text-dimmed); - --button-color-dimmed-off: var(--color-text); - --button-color-text: var(--button-color-dimmed-on); + --button-color-text: var(--color-text-dimmed); } .k-button:where([data-variant="dimmed"]):not([aria-disabled]):is( :hover, [aria-current] - ) { - --button-color-text: var(--button-color-dimmed-off); + ) + .k-button-text { + filter: brightness(75%); } -.k-button:where([data-theme][data-variant="dimmed"]) { +.k-button:where([data-variant="dimmed"][data-theme]) { --button-color-icon: var(--theme-color-icon); - --button-color-dimmed-on: var(--theme-color-text-dimmed); - --button-color-dimmed-off: var(--theme-color-text); + --button-color-text: var(--theme-color-text-dimmed); +} +.k-button:where([data-variant="dimmed"][data-theme$="-icon"]) { + --button-color-text: var(--color-text-dimmed); } /** Filled Buttons **/ @@ -322,13 +323,16 @@ export default { .k-button:where([data-variant="filled"]):not([aria-disabled]):hover { filter: brightness(97%); } - -.k-button:where([data-theme]):not([data-theme$="-icon"]):where( - [data-variant="filled"] - ) { +.k-button:where([data-variant="filled"][data-theme]) { --button-color-icon: var(--theme-color-700); --button-color-back: var(--theme-color-back); - --button-color-text: var(--theme-color-text); +} +.k-button:where([data-theme$="-icon"][data-variant="filled"]) { + --button-color-icon: hsl( + var(--theme-color-hs), + 57% + ); /* slightly improve the contrast */ + --button-color-back: var(--color-gray-300); } /** Icon Buttons **/ diff --git a/panel/src/styles/utilities/theme.css b/panel/src/styles/utilities/theme.css index 3b04cf241b..fcd4a8f1bf 100644 --- a/panel/src/styles/utilities/theme.css +++ b/panel/src/styles/utilities/theme.css @@ -25,7 +25,11 @@ --theme-color-900: hsl(var(--theme-color-hs), var(--theme-color-l-900)); --theme-color-text: var(--theme-color-900); - --theme-color-text-dimmed: var(--theme-color-700); + --theme-color-text-dimmed: hsl( + var(--theme-color-h), + calc(var(--theme-color-s) - 60%), + 50% + ); --theme-color-back: var(--theme-color-400); --theme-color-hover: var(--theme-color-500); --theme-color-icon: var(--theme-color-600); @@ -94,8 +98,8 @@ --theme-color-boost: 10%; } -[data-theme="white"], -[data-theme="text"] { +[data-theme^="white"], +[data-theme^="text"] { --theme-color-back: var(--color-white); --theme-color-icon: var(--color-gray-800); --theme-color-text: var(--color-text); From abdc5baead92a0db6664973aecdbd2da24b1446c Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 25 Apr 2024 15:26:55 +0200 Subject: [PATCH 022/125] Language view: fix slot assignment --- .../Views/Languages/LanguageView.vue | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/panel/src/components/Views/Languages/LanguageView.vue b/panel/src/components/Views/Languages/LanguageView.vue index f17d82a664..d2fe42e239 100644 --- a/panel/src/components/Views/Languages/LanguageView.vue +++ b/panel/src/components/Views/Languages/LanguageView.vue @@ -6,31 +6,34 @@ {{ name }} - - - - - + + From 5a7fdc57d43f6ace58a0d2d66e6e404d857d0cf4 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 25 Apr 2024 19:03:02 +0200 Subject: [PATCH 023/125] Clean up Panel js dev assets loading --- src/Panel/Assets.php | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/Panel/Assets.php b/src/Panel/Assets.php index 808026b430..70dccfe081 100644 --- a/src/Panel/Assets.php +++ b/src/Panel/Assets.php @@ -201,8 +201,8 @@ public function favicons(): array */ public function icons(): string { - $dir = $this->kirby->root('panel') . '/'; - $dir .= $this->dev ? 'public' : 'dist'; + $dir = $this->kirby->root('panel') . '/'; + $dir .= $this->dev ? 'public' : 'dist'; $icons = F::read($dir . '/img/icons.svg'); $icons = preg_replace('//', '', $icons); return $icons; @@ -254,23 +254,18 @@ public function js(): array // path to `index.js` - vendor does not need // to be loaded in dev mode if ($this->dev === true) { + // load the non-minified index.js, remove vendor script and + // development version of Vue + $js['vendor']['src'] = null; + $js['index']['src'] = $this->url . '/src/index.js'; + $js['vue']['src'] = $this->url . '/node_modules/vue/dist/vue.js'; + + // add vite dev client $js['vite'] = [ 'nonce' => $this->nonce, 'src' => $this->url . '/@vite/client', 'type' => 'module' ]; - - $js['index'] = [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/src/index.js', - 'type' => 'module' - ]; - - // load the development version of Vue - $js['vue']['src'] = $this->url . '/node_modules/vue/dist/vue.js'; - - // remove the vendor script - $js['vendor']['src'] = null; } return array_filter($js, fn ($js) => empty($js['src']) === false); From 7b284fefeefd0757a0ad056a46f3d5fd943507dd Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 25 Apr 2024 20:07:05 +0200 Subject: [PATCH 024/125] Panel Assets: simplify code --- src/Panel/Assets.php | 68 ++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/src/Panel/Assets.php b/src/Panel/Assets.php index 70dccfe081..1bf45a8669 100644 --- a/src/Panel/Assets.php +++ b/src/Panel/Assets.php @@ -56,13 +56,11 @@ public function __construct() */ public function css(): array { - $css = A::merge( - [ - 'index' => $this->url . '/css/style.min.css', - 'plugins' => $this->plugins->url('css') - ], - $this->custom('panel.css') - ); + $css = [ + 'index' => $this->url . '/css/style.min.css', + 'plugins' => $this->plugins->url('css'), + ...$this->custom('panel.css') + ]; // during dev mode we do not need to load // the general stylesheet (as styling will be inlined) @@ -213,41 +211,37 @@ public function icons(): string */ public function js(): array { - $js = A::merge( - [ - 'vue' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/vue.min.js' - ], - 'vendor' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/vendor.min.js', - 'type' => 'module' - ], - 'pluginloader' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/plugins.js', - 'type' => 'module' - ], - 'plugins' => [ - 'nonce' => $this->nonce, - 'src' => $this->plugins->url('js'), - 'defer' => true - ] + $js = [ + 'vue' => [ + 'nonce' => $this->nonce, + 'src' => $this->url . '/js/vue.min.js' + ], + 'vendor' => [ + 'nonce' => $this->nonce, + 'src' => $this->url . '/js/vendor.min.js', + 'type' => 'module' + ], + 'pluginloader' => [ + 'nonce' => $this->nonce, + 'src' => $this->url . '/js/plugins.js', + 'type' => 'module' ], - A::map($this->custom('panel.js'), fn ($src) => [ + 'plugins' => [ + 'nonce' => $this->nonce, + 'src' => $this->plugins->url('js'), + 'defer' => true + ], + ...A::map($this->custom('panel.js'), fn ($src) => [ 'nonce' => $this->nonce, 'src' => $src, 'type' => 'module' ]), - [ - 'index' => [ - 'nonce' => $this->nonce, - 'src' => $this->url . '/js/index.min.js', - 'type' => 'module' - ], - ] - ); + 'index' => [ + 'nonce' => $this->nonce, + 'src' => $this->url . '/js/index.min.js', + 'type' => 'module' + ], + ]; // during dev mode, add vite client and adapt From 69c77124509b1f00c348334ccb834a6574504d02 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 25 Apr 2024 20:07:17 +0200 Subject: [PATCH 025/125] Vite config: segment config code --- panel/vite.config.mjs | 103 ++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/panel/vite.config.mjs b/panel/vite.config.mjs index f7270d3894..a00619efee 100644 --- a/panel/vite.config.mjs +++ b/panel/vite.config.mjs @@ -4,21 +4,61 @@ import path from "path"; import { defineConfig, splitVendorChunkPlugin } from "vite"; import vue from "@vitejs/plugin-vue2"; import { viteStaticCopy } from "vite-plugin-static-copy"; -import externalGlobals from "rollup-plugin-external-globals"; +import externalize from "rollup-plugin-external-globals"; import kirby from "./scripts/vite-kirby.mjs"; -let customServer; -try { - customServer = require("./vite.config.custom.js"); -} catch (err) { - customServer = {}; +/** + * Returns all aliases used in the project + */ +function createAliases() { + return { + "@": path.resolve(__dirname, "src") + }; } -export default defineConfig(({ command }) => { - // gather plugins depending on environment +/** + * Returns the server configuration + */ +function createServer() { + const proxy = { + target: process.env.VUE_APP_DEV_SERVER ?? "http://sandbox.test", + changeOrigin: true, + secure: false + }; + + return { + proxy: { + "/api": proxy, + "/env": proxy, + "/media": proxy + }, + open: proxy.target + "/panel", + port: 3000, + ...createCustomServer() + }; +} + +/** + * Returns custom server configuration, if it exists + */ +function createCustomServer() { + try { + return require("./vite.config.custom.js"); + } catch { + return {}; + } +} + +/** + * Returns an array of plugins used, + * depending on the mode (development or build) + */ +function createPlugins(mode) { const plugins = [vue(), splitVendorChunkPlugin(), kirby()]; - if (command === "build") { + // when building… + if (mode === "build") { + //copy Vue to the dist directory plugins.push( viteStaticCopy({ targets: [ @@ -36,20 +76,32 @@ export default defineConfig(({ command }) => { // Externalize Vue so it's not loaded from node_modules // but accessed via window.Vue { - ...externalGlobals({ vue: "Vue" }), + ...externalize({ vue: "Vue" }), enforce: "post" } ); } - const proxy = { - target: process.env.VUE_APP_DEV_SERVER ?? "http://sandbox.test", - changeOrigin: true, - secure: false + return plugins; +} + +/** + * Returns vitest configuration + */ +function createTest() { + return { + environment: "node", + include: ["**/*.test.js"], + setupFiles: ["vitest.setup.js"] }; +} +/** + * Returns the Vite configuration + */ +export default defineConfig(({ command }) => { return { - plugins, + plugins: createPlugins(command), define: { // Fix vuelidate error "process.env.BUILD": JSON.stringify("production") @@ -73,24 +125,9 @@ export default defineConfig(({ command }) => { holdUntilCrawlEnd: false }, resolve: { - alias: { - "@": path.resolve(__dirname, "src") - } - }, - server: { - proxy: { - "/api": proxy, - "/env": proxy, - "/media": proxy - }, - open: proxy.target + "/panel", - port: 3000, - ...customServer + alias: createAliases() }, - test: { - environment: "node", - include: ["**/*.test.js"], - setupFiles: ["vitest.setup.js"] - } + server: createServer(), + test: createTest() }; }); From 134343c05d4e30998b4fff90506f99edaa13c8c1 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 25 Apr 2024 21:05:51 +0200 Subject: [PATCH 026/125] Improve button themes lab example --- .../lab/components/buttons/2_themes/index.php | 15 ------- .../lab/components/buttons/2_themes/index.vue | 44 ++++++++++++++++--- 2 files changed, 37 insertions(+), 22 deletions(-) delete mode 100644 panel/lab/components/buttons/2_themes/index.php diff --git a/panel/lab/components/buttons/2_themes/index.php b/panel/lab/components/buttons/2_themes/index.php deleted file mode 100644 index 7745db2cf1..0000000000 --- a/panel/lab/components/buttons/2_themes/index.php +++ /dev/null @@ -1,15 +0,0 @@ - [ - null, - 'red', - 'orange', - 'yellow', - 'green', - 'aqua', - 'blue', - 'purple', - 'pink', - ] -]; diff --git a/panel/lab/components/buttons/2_themes/index.vue b/panel/lab/components/buttons/2_themes/index.vue index b360bab703..5be3144971 100644 --- a/panel/lab/components/buttons/2_themes/index.vue +++ b/panel/lab/components/buttons/2_themes/index.vue @@ -1,11 +1,15 @@ From fd1ae628f1b4e47d6c95c4cdaf9af474010c996d Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Mon, 29 Apr 2024 14:48:25 +0200 Subject: [PATCH 043/125] Fix permissions Co-authored-by: Lukas Bestle --- tests/Cms/System/SystemTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Cms/System/SystemTest.php b/tests/Cms/System/SystemTest.php index 922ff73477..8c8ec73351 100644 --- a/tests/Cms/System/SystemTest.php +++ b/tests/Cms/System/SystemTest.php @@ -511,7 +511,7 @@ public function testIsOkContentMissingPermissions() $system = new System($app); $before = fileperms($app->root('content')); - chmod($app->root('content'), 0000); + chmod($app->root('content'), 0o000); $this->assertFalse($system->isOk()); From 98332ba60c416c6ed552579c1eb5061897ba5aa6 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Mon, 29 Apr 2024 16:04:31 +0200 Subject: [PATCH 044/125] Use fields from parent dialog --- .../components/Forms/Toolbar/EmailDialog.vue | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/panel/src/components/Forms/Toolbar/EmailDialog.vue b/panel/src/components/Forms/Toolbar/EmailDialog.vue index 3c1c225615..4caa63b36d 100644 --- a/panel/src/components/Forms/Toolbar/EmailDialog.vue +++ b/panel/src/components/Forms/Toolbar/EmailDialog.vue @@ -6,19 +6,15 @@ export default { props: { // eslint-disable-next-line vue/require-prop-types fields: { - default: () => ({ - href: { - label: window.panel.$t("email"), - type: "email", - icon: "email" - }, - title: { - label: window.panel.$t("link.text"), - type: "text", - icon: "title" - } - }) - }, + default: () => { + const fields = EmailDialog.props.fields.default(); + + // change the label to "Link Text" + fields.title.label = window.panel.$t("link.text"); + + return fields; + } + } }, methods: { submit() { From 0167ed733370ff26acb6c4c48d3bf026e82374ac Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Mon, 29 Apr 2024 19:47:35 +0200 Subject: [PATCH 045/125] Adaptations after code review --- .../src/components/Dropdowns/DropdownContent.vue | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/panel/src/components/Dropdowns/DropdownContent.vue b/panel/src/components/Dropdowns/DropdownContent.vue index e5950994f3..6bf446ec3c 100644 --- a/panel/src/components/Dropdowns/DropdownContent.vue +++ b/panel/src/components/Dropdowns/DropdownContent.vue @@ -194,17 +194,21 @@ export default { } // click handler is an action string - // which is emitted to the parent as well as globally + // which is emitted to the parent if (typeof option.click === "string") { - this.$emit("action", option.click); - this.$events.emit("dropdown:" + option.click); - return; + return this.$emit("action", option.click); } // click handler is an object with a name and payload - // which is emitted globally + // and optional flag to also emit globally if (option.click) { - this.$events.emit(option.click.name, option.click.payload); + if (option.click.name) { + this.$emit(option.click.name, option.click.payload); + } + + if (option.click.global) { + this.$events.emit(option.click.global, option.click.payload); + } } }, /** From e2c2632be88fd0b8ed6afb85eb8887b065eead98 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Tue, 30 Apr 2024 11:50:05 +0200 Subject: [PATCH 046/125] Panel notifcations: support themes --- .../internals/panel/notification/index.vue | 45 +++++++++++++------ panel/src/panel/notification.js | 26 ++++------- panel/src/panel/notification.test.js | 1 + 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/panel/lab/internals/panel/notification/index.vue b/panel/lab/internals/panel/notification/index.vue index 2e46b6f1c1..931725e871 100644 --- a/panel/lab/internals/panel/notification/index.vue +++ b/panel/lab/internals/panel/notification/index.vue @@ -9,7 +9,7 @@

{{ $panel.notification.context || " " }} @@ -24,7 +24,7 @@

{{ $panel.notification.details || " " }} window.panel.notification.close();

Closes the current notification

@@ -136,7 +136,7 @@ >

Used to show a deprecation warning in the console.

@@ -149,7 +149,7 @@ >

Displays an error notification.

@@ -162,7 +162,7 @@ >

Displays a fatal error in an iframe overlay for better isolation

@@ -174,11 +174,18 @@ >window.panel.notification.open(notification);

Open a custom notification

+ + + @@ -190,7 +197,7 @@ >

Displays a success notification

@@ -198,3 +205,15 @@ + + diff --git a/panel/src/panel/notification.js b/panel/src/panel/notification.js index 27639f93ef..e487929b81 100644 --- a/panel/src/panel/notification.js +++ b/panel/src/panel/notification.js @@ -11,6 +11,7 @@ export const defaults = () => { icon: null, isOpen: false, message: null, + theme: null, timeout: null, type: null }; @@ -89,8 +90,7 @@ export default (panel = {}) => { // convert strings to full error objects if (typeof error === "string") { error = { - message: error, - type: "error" + message: error }; } @@ -105,16 +105,16 @@ export default (panel = {}) => { if (panel.context === "view") { panel.dialog.open({ component: "k-error-dialog", - props: error, - type: "error" + props: error }); } // show the error notification bar return this.open({ message: error.message, - type: "error", - icon: "alert" + icon: "alert", + theme: "negative", + type: "error" }); }, @@ -209,23 +209,13 @@ export default (panel = {}) => { } return this.open({ - timeout: 4000, - type: "success", icon: "check", + theme: "positive", + timeout: 4000, ...success }); }, - /** - * Getter that converts the notification type - * into the matching notification component theme - * - * @returns {String} - */ - get theme() { - return this.type === "error" ? "negative" : "positive"; - }, - /** * Holds the timer object */ diff --git a/panel/src/panel/notification.test.js b/panel/src/panel/notification.test.js index 44c3814e74..d286073d20 100644 --- a/panel/src/panel/notification.test.js +++ b/panel/src/panel/notification.test.js @@ -19,6 +19,7 @@ describe("panel.notification", () => { icon: null, isOpen: false, message: null, + theme: null, timeout: null, type: null }; From ca7966d5e927fee1c103883a7a8cbb92f30bea86 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Tue, 30 Apr 2024 12:02:59 +0200 Subject: [PATCH 047/125] Panel notification: improve timeout handling --- panel/src/panel/notification.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/panel/src/panel/notification.js b/panel/src/panel/notification.js index e487929b81..a118491a4f 100644 --- a/panel/src/panel/notification.js +++ b/panel/src/panel/notification.js @@ -174,6 +174,11 @@ export default (panel = {}) => { return this.success(notification); } + // add timeout if not error or fatal notification + if (notification.type !== "error" && notification.type !== "fatal") { + notification.timeout ??= 4000; + } + // set the new state this.set({ // add the current editing context @@ -211,7 +216,6 @@ export default (panel = {}) => { return this.open({ icon: "check", theme: "positive", - timeout: 4000, ...success }); }, From 154a573ed76992ec36b8bfb9d78987e9f4051865 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Tue, 30 Apr 2024 12:06:37 +0200 Subject: [PATCH 048/125] `panel.notification.info(message)` --- .../internals/panel/notification/index.vue | 13 ++++++++++ panel/src/panel/modal.test.js | 2 +- panel/src/panel/notification.js | 26 +++++++++++++++---- panel/src/panel/notification.test.js | 8 ++++-- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/panel/lab/internals/panel/notification/index.vue b/panel/lab/internals/panel/notification/index.vue index 931725e871..4e109f7630 100644 --- a/panel/lab/internals/panel/notification/index.vue +++ b/panel/lab/internals/panel/notification/index.vue @@ -55,6 +55,19 @@ /> + + + window.panel.notification.info(notification); +

Displays an info notification

+ +
+

diff --git a/panel/src/panel/modal.test.js b/panel/src/panel/modal.test.js index 7a8a50e5e5..f2eb71a252 100644 --- a/panel/src/panel/modal.test.js +++ b/panel/src/panel/modal.test.js @@ -147,8 +147,8 @@ describe.concurrent("panel/modal.js", () => { message: "Test" }); - expect(panel.notification.type).toStrictEqual("success"); expect(panel.notification.message).toStrictEqual("Test"); + expect(panel.notification.theme).toStrictEqual("positive"); }); it("should emit panel events after submit", async () => { diff --git a/panel/src/panel/notification.js b/panel/src/panel/notification.js index a118491a4f..b99811626b 100644 --- a/panel/src/panel/notification.js +++ b/panel/src/panel/notification.js @@ -118,6 +118,26 @@ export default (panel = {}) => { }); }, + /** + * Shortcut to create an info + * notification. You can pass a simple + * string or a state object. + * + * @param {Object|String} info + * @returns {Object} The notification state + */ + info(info = {}) { + if (typeof info === "string") { + info = { message: info }; + } + + return this.open({ + icon: "info", + theme: "info", + ...info + }); + }, + /** * Checks if the notification is a fatal * error. Those are displayed in the @@ -204,11 +224,7 @@ export default (panel = {}) => { * @param {Object|String} success * @returns {Object} The notification state */ - success(success) { - if (!success) { - success = {}; - } - + success(success = {}) { if (typeof success === "string") { success = { message: success }; } diff --git a/panel/src/panel/notification.test.js b/panel/src/panel/notification.test.js index d286073d20..d53d91c1a1 100644 --- a/panel/src/panel/notification.test.js +++ b/panel/src/panel/notification.test.js @@ -100,12 +100,16 @@ describe("panel.notification", () => { const notification = Notification(panel); notification.success("Test"); - expect(notification.theme).toStrictEqual("positive"); - notification.error("Test"); + notification.info("Test"); + expect(notification.theme).toStrictEqual("info"); + notification.error("Test"); expect(notification.theme).toStrictEqual("negative"); + + notification.open({ theme: "love" }); + expect(notification.theme).toStrictEqual("love"); }); it("should set a timer for success notifications", async () => { From 324859318c7243b919f302a28b9b5211fcfe498c Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Tue, 30 Apr 2024 19:33:51 +0200 Subject: [PATCH 049/125] Fix DropdownItem --- .../src/components/Dropdowns/DropdownItem.vue | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/panel/src/components/Dropdowns/DropdownItem.vue b/panel/src/components/Dropdowns/DropdownItem.vue index ca860eee82..4793a6db18 100644 --- a/panel/src/components/Dropdowns/DropdownItem.vue +++ b/panel/src/components/Dropdowns/DropdownItem.vue @@ -1,7 +1,16 @@ +current: [Boolean, String], + diff --git a/panel/src/components/Dialogs/Elements/index.js b/panel/src/components/Dialogs/Elements/index.js index 31b12f8f4f..68420b4066 100644 --- a/panel/src/components/Dialogs/Elements/index.js +++ b/panel/src/components/Dialogs/Elements/index.js @@ -6,6 +6,8 @@ import Notification from "./Notification.vue"; import Search from "./Search.vue"; import Text from "./Text.vue"; +import UploadPreview from "./UploadPreview.vue"; + export default { install(app) { app.component("k-dialog-body", Body); @@ -15,5 +17,7 @@ export default { app.component("k-dialog-notification", Notification); app.component("k-dialog-search", Search); app.component("k-dialog-text", Text); + + app.component("k-upload-dialog-preview", UploadPreview); } }; diff --git a/panel/src/components/Dialogs/UploadDialog.vue b/panel/src/components/Dialogs/UploadDialog.vue index 966cc61ea6..5f7e70a3b3 100644 --- a/panel/src/components/Dialogs/UploadDialog.vue +++ b/panel/src/components/Dialogs/UploadDialog.vue @@ -8,81 +8,76 @@ @submit="$emit('submit')" > - - + + + + + @@ -105,34 +100,6 @@ export default { }; } } - }, - methods: { - isPreviewable(mime) { - return [ - "image/jpeg", - "image/jpg", - "image/gif", - "image/png", - "image/webp", - "image/avif", - "image/svg+xml" - ].includes(mime); - }, - previewIcon(mime) { - if (mime.startsWith("image/")) { - return "file-image"; - } - - if (mime.startsWith("audio/")) { - return "file-audio"; - } - - if (mime.startsWith("video/")) { - return "file-video"; - } - - return "file"; - } } }; diff --git a/panel/src/components/Dialogs/UploadReplaceDialog.vue b/panel/src/components/Dialogs/UploadReplaceDialog.vue index a47204c927..f7c20ebf70 100644 --- a/panel/src/components/Dialogs/UploadReplaceDialog.vue +++ b/panel/src/components/Dialogs/UploadReplaceDialog.vue @@ -8,18 +8,11 @@ >

  • - -
  • @@ -31,21 +24,13 @@ :data-completed="file.completed" class="k-upload-item" > - - - - + + +

    {{ file.niceSize }} @@ -60,12 +46,14 @@

    {{ file.error }}

    +
    +
    +
    From 34927ce990a61b7d84ae5f69749034ce1b8544a3 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Tue, 30 Apr 2024 19:40:33 +0200 Subject: [PATCH 054/125] CSS fixes --- panel/src/components/Dialogs/Elements/UploadPreview.vue | 2 +- panel/src/components/Dialogs/UploadDialog.vue | 2 ++ panel/src/components/Dialogs/UploadReplaceDialog.vue | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/panel/src/components/Dialogs/Elements/UploadPreview.vue b/panel/src/components/Dialogs/Elements/UploadPreview.vue index 790ed3246c..7a5f4b94c3 100644 --- a/panel/src/components/Dialogs/Elements/UploadPreview.vue +++ b/panel/src/components/Dialogs/Elements/UploadPreview.vue @@ -1,5 +1,5 @@ diff --git a/panel/src/components/Dialogs/UploadReplaceDialog.vue b/panel/src/components/Dialogs/UploadReplaceDialog.vue index 2f9d15262b..3bf2204321 100644 --- a/panel/src/components/Dialogs/UploadReplaceDialog.vue +++ b/panel/src/components/Dialogs/UploadReplaceDialog.vue @@ -18,55 +18,14 @@
  • -
  • - - - - -
    -

    - {{ file.niceSize }} - -

    -

    {{ file.error }}

    -
    - -
    - -
    - -
    - - -
    - -
    -
    -
  • +
@@ -90,6 +49,11 @@ export default { }; } } + }, + computed: { + file() { + return this.$panel.upload.files[0]; + } } }; @@ -108,10 +72,6 @@ export default { overflow: hidden; } -.k-upload-item-input { - --input-color-back: var(--color-white) !important; -} - .k-upload-replace-dialog .k-upload-item { flex-grow: 1; } diff --git a/panel/src/components/Uploads/UploadItem.vue b/panel/src/components/Uploads/UploadItem.vue index 9db75cb1d9..09945becc2 100644 --- a/panel/src/components/Uploads/UploadItem.vue +++ b/panel/src/components/Uploads/UploadItem.vue @@ -1,9 +1,14 @@ @@ -92,6 +147,9 @@ export default { z-index: 1; border-radius: var(--rounded); } +.k-upload-item-input.k-input[data-disabled="true"] { + --input-color-back: var(--color-white); +} .k-upload-item-input .k-input-after { color: var(--color-gray-600); } @@ -107,6 +165,7 @@ export default { .k-upload-item-progress { --progress-height: 0.25rem; --progress-color-back: var(--color-light); + margin-bottom: 0.3125rem; } .k-upload-item-toggle { grid-area: toggle; diff --git a/panel/src/components/Uploads/UploadItemPreview.vue b/panel/src/components/Uploads/UploadItemPreview.vue index cca548d9fe..2379873d2e 100644 --- a/panel/src/components/Uploads/UploadItemPreview.vue +++ b/panel/src/components/Uploads/UploadItemPreview.vue @@ -12,17 +12,34 @@ diff --git a/panel/src/components/Uploads/UploadItems.vue b/panel/src/components/Uploads/UploadItems.vue index 0d087a39e9..07ddf9dfb8 100644 --- a/panel/src/components/Uploads/UploadItems.vue +++ b/panel/src/components/Uploads/UploadItems.vue @@ -12,12 +12,14 @@ From d31e27a85b1575bf369c0a2fa92be65f0dbcdad0 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 3 May 2024 12:59:11 +0200 Subject: [PATCH 083/125] Refactor App::language and introduce App::currentLanguage --- src/Cms/App.php | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Cms/App.php b/src/Cms/App.php index e3016a860a..43a14ac6b9 100644 --- a/src/Cms/App.php +++ b/src/Cms/App.php @@ -538,6 +538,14 @@ public function csrf(string|null $check = null): string|bool return false; } + /** + * Returns the current language, set by `static::setCurrentLanguage` + */ + public function currentLanguage(): Language + { + return $this->language ??= $this->defaultLanguage(); + } + /** * Returns the default language object */ @@ -879,27 +887,16 @@ public function kirbytext(string $text = null, array $options = []): string } /** - * Returns the current language + * Returns the language by code or shortcut (`default`, `current`). + * Passing `null` is an alias for passing `current` */ public function language(string $code = null): Language|null { - if ($this->multilang() === false) { - return null; - } - - if ($code === 'default') { - return $this->defaultLanguage(); - } - - // if requesting a non-default language, - // find it but don't cache it - if ($code !== null) { - return $this->languages()->find($code); - } - - // otherwise return language set by `AppTranslation::setCurrentLanguage` - // or default language - return $this->language ??= $this->defaultLanguage(); + return match($code ?? 'current') { + 'default' => $this->defaultLanguage(), + 'current' => $this->currentLanguage(), + default => $this->languages()->find($code) + }; } /** From be2cb3baa1d7998bb6bd008d2e1e62c8549d8073 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 3 May 2024 13:03:52 +0200 Subject: [PATCH 084/125] Fix CS issue --- src/Cms/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cms/App.php b/src/Cms/App.php index 43a14ac6b9..92ecbf5706 100644 --- a/src/Cms/App.php +++ b/src/Cms/App.php @@ -892,7 +892,7 @@ public function kirbytext(string $text = null, array $options = []): string */ public function language(string $code = null): Language|null { - return match($code ?? 'current') { + return match ($code ?? 'current') { 'default' => $this->defaultLanguage(), 'current' => $this->currentLanguage(), default => $this->languages()->find($code) From 330406c959482dc01765b1596721180af288933c Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 3 May 2024 13:04:44 +0200 Subject: [PATCH 085/125] Fix return type --- src/Cms/App.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cms/App.php b/src/Cms/App.php index 92ecbf5706..c81d95f0a9 100644 --- a/src/Cms/App.php +++ b/src/Cms/App.php @@ -539,9 +539,9 @@ public function csrf(string|null $check = null): string|bool } /** - * Returns the current language, set by `static::setCurrentLanguage` + * Returns the current language, if set by `static::setCurrentLanguage` */ - public function currentLanguage(): Language + public function currentLanguage(): Language|null { return $this->language ??= $this->defaultLanguage(); } From e611cd83ad5044ca4ba0e5cfaaa2bf8b914cdd2a Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 3 May 2024 13:26:34 +0200 Subject: [PATCH 086/125] Better be safe --- src/Cms/App.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Cms/App.php b/src/Cms/App.php index c81d95f0a9..1e37de1666 100644 --- a/src/Cms/App.php +++ b/src/Cms/App.php @@ -892,6 +892,10 @@ public function kirbytext(string $text = null, array $options = []): string */ public function language(string $code = null): Language|null { + if ($this->multilang() === false) { + return null; + } + return match ($code ?? 'current') { 'default' => $this->defaultLanguage(), 'current' => $this->currentLanguage(), From 7111bcde226fcb2307f692a2a8a92d6b1f4d02c0 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 3 May 2024 13:37:52 +0200 Subject: [PATCH 087/125] Move App::setCurrentLanguage and fix type hinting --- src/Cms/App.php | 27 ++++++++++++++++++++++++++- src/Cms/AppTranslations.php | 28 ---------------------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/Cms/App.php b/src/Cms/App.php index 1e37de1666..b91f192f23 100644 --- a/src/Cms/App.php +++ b/src/Cms/App.php @@ -31,6 +31,7 @@ use Kirby\Toolkit\Controller; use Kirby\Toolkit\LazyValue; use Kirby\Toolkit\Str; +use Kirby\Toolkit\Locale; use Kirby\Uuid\Uuid; use Throwable; @@ -1213,7 +1214,7 @@ public function request(): Request * @internal * @throws \Kirby\Exception\NotFoundException if the home page cannot be found */ - public function resolve(string $path = null, string $language = null): mixed + public function resolve(string|null $path = null, string|null $language = null): mixed { // set the current translation $this->setCurrentTranslation($language); @@ -1411,6 +1412,30 @@ public function sessionHandler(): AutoSession ); } + /** + * Load and set the current language if it exists + * Otherwise fall back to the default language + * + * @internal + */ + public function setCurrentLanguage( + string|null $languageCode = null + ): Language|null { + if ($this->multilang() === false) { + Locale::set($this->option('locale', 'en_US.utf-8')); + return $this->language = null; + } + + $this->language = $this->language($languageCode) ?? $this->defaultLanguage(); + + Locale::set($this->language->locale()); + + // add language slug rules to Str class + Str::$language = $this->language->rules(); + + return $this->language; + } + /** * Create your own set of languages * diff --git a/src/Cms/AppTranslations.php b/src/Cms/AppTranslations.php index f3d80b114f..1efae287cb 100644 --- a/src/Cms/AppTranslations.php +++ b/src/Cms/AppTranslations.php @@ -3,7 +3,6 @@ namespace Kirby\Cms; use Kirby\Toolkit\I18n; -use Kirby\Toolkit\Locale; use Kirby\Toolkit\Str; /** @@ -104,33 +103,6 @@ public function panelLanguage(): string return $this->option('panel.language', $defaultCode); } - /** - * Load and set the current language if it exists - * Otherwise fall back to the default language - * - * @internal - */ - public function setCurrentLanguage( - string $languageCode = null - ): Language|null { - if ($this->multilang() === false) { - Locale::set($this->option('locale', 'en_US.utf-8')); - return $this->language = null; - } - - $this->language = $this->language($languageCode); - $this->language ??= $this->defaultLanguage(); - - if ($this->language) { - Locale::set($this->language->locale()); - } - - // add language slug rules to Str class - Str::$language = $this->language->rules(); - - return $this->language; - } - /** * Set the current translation * From 8b84c9681b783806364b5e544c7aecbc0acaa2a6 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 3 May 2024 13:44:33 +0200 Subject: [PATCH 088/125] Fix CS issue --- src/Cms/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cms/App.php b/src/Cms/App.php index b91f192f23..a29aa14cdf 100644 --- a/src/Cms/App.php +++ b/src/Cms/App.php @@ -30,8 +30,8 @@ use Kirby\Toolkit\Config; use Kirby\Toolkit\Controller; use Kirby\Toolkit\LazyValue; -use Kirby\Toolkit\Str; use Kirby\Toolkit\Locale; +use Kirby\Toolkit\Str; use Kirby\Uuid\Uuid; use Throwable; From e4f85589456e5184de31ab0f4f826d0961ba683c Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Thu, 9 May 2024 10:43:29 +0200 Subject: [PATCH 089/125] QrCode: `border` argument --- src/Image/QrCode.php | 28 +++++++++++++++-------- tests/Image/QrCodeTest.php | 9 ++++++++ tests/Image/fixtures/qr/image-border.png | Bin 0 -> 623 bytes 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 tests/Image/fixtures/qr/image-border.png diff --git a/src/Image/QrCode.php b/src/Image/QrCode.php index b6599fb6eb..d675f41d0a 100644 --- a/src/Image/QrCode.php +++ b/src/Image/QrCode.php @@ -59,13 +59,15 @@ public function __construct(public string $data) * @param int|null $size Image width/height in pixels, defaults to a size per module of 4x4 * @param string $color Foreground color in hex format * @param string $back Background color in hex format + * @param int $border Border size in number of modules */ public function toDataUri( int|null $size = null, string $color = '#000000', - string $back = '#ffffff' + string $back = '#ffffff', + int $border = 4 ): string { - $image = $this->toImage($size, $color, $back); + $image = $this->toImage($size, $color, $back, $border); ob_start(); imagepng($image); @@ -82,14 +84,16 @@ public function toDataUri( * @param int|null $size Image width/height in pixels, defaults to a size per module of 4x4 * @param string $color Foreground color in hex format * @param string $back Background color in hex format + * @param int $border Border size in number of modules */ public function toImage( int|null $size = null, string $color = '#000000', - string $back = '#ffffff' + string $back = '#ffffff', + int $border = 4 ): GdImage { // get code and size measurements - $code = $this->encode(); + $code = $this->encode($border); [$width, $height] = $this->measure($code); $size ??= ceil($width * 4); $ws = $size / $width; @@ -132,13 +136,15 @@ public function toImage( * @param int|string|null $size Optional CSS width of the `` element * @param string $color Foreground color in hex format * @param string $back Background color in hex format + * @param int $border Border size in number of modules */ public function toSvg( int|string|null $size = null, string $color = '#000000', - string $back = '#ffffff' + string $back = '#ffffff', + int $border = 4 ): string { - $code = $this->encode(); + $code = $this->encode($border); [$vbw, $vbh] = $this->measure($code); $modules = $this->eachModuleGroup( @@ -167,15 +173,17 @@ public function __toString(): string * @param int|string|null $size Optional image width/height in pixels (defaults to a size per module of 4x4) or CSS width of the `` element * @param string $color Foreground color in hex format * @param string $back Background color in hex format + * @param int $border Border size in number of modules */ public function write( string $file, int|string|null $size = null, string $color = '#000000', - string $back = '#ffffff' + string $back = '#ffffff', + int $border = 4 ): void { $format = F::extension($file); - $args = [$size, $color, $back]; + $args = [$size, $color, $back, $border]; match ($format) { 'gif' => imagegif($this->toImage(...$args), $file), @@ -395,7 +403,7 @@ protected function eachModuleGroup(array $code, Closure $action): array return $result; } - protected function encode(): array + protected function encode(int $q = 4): array { [$data, $version, $ecl, $ec] = $this->encodeData(); $data = $this->encodeErrorCorrection($data, $ec, $version); @@ -404,7 +412,7 @@ protected function encode(): array $mtx = $this->finalizeMatrix($mtx, $size, $ecl, $mask, $version); return [ - 'q' => [4, 4, 4, 4], + 'q' => [$q, $q, $q, $q], 'size' => [$size, $size], 'bits' => $mtx ]; diff --git a/tests/Image/QrCodeTest.php b/tests/Image/QrCodeTest.php index 2b573af41a..69905a3395 100644 --- a/tests/Image/QrCodeTest.php +++ b/tests/Image/QrCodeTest.php @@ -72,6 +72,15 @@ public function testToImageColors() $this->assertSame($expected, $data); } + public function testToImageBorder() + { + $qr = new QrCode('https://getkirby.com'); + $image = $qr->toImage(null, '#000000', '#ffffff', 0); + $data = $this->imageContent($image); + $expected = F::read(static::FIXTURES . '/image-border.png'); + $this->assertSame($expected, $data); + } + public function testToSvg() { $qr = new QrCode('12345678'); diff --git a/tests/Image/fixtures/qr/image-border.png b/tests/Image/fixtures/qr/image-border.png new file mode 100644 index 0000000000000000000000000000000000000000..cb1227f792503bab8645eba85a4e994eb34003dc GIT binary patch literal 623 zcmeAS@N?(olHy`uVBq!ia0vp^DIm(=Sjx8|JD&b;3Pafr>+H78?oHr?MIdi+9Skab!LBiQk`PMOLIefPR@ zC;Y7h$kHjS8m}J+mp&1VPG09?JH7aD{34M4iUgy|u(WJh+mCnr)$dC}RA$)bTSylB zJ}Zg--5Fg9b9Pkm;V$d>xn;Jm`xk<=E-nnK+OKc8&wArE#SW0?d(M@vSa)Bl-uK!q z&AE0^TRW~FRDY!?lzy?qE*t8!*XM41|6;jFeQwONeTf24r)j?Y`u@mG(-Qv!CxD^2 zK<7a8oM5l(hhDti!Vh!6y?1jiO+K>u!gEuT<4~7YM4q$qyt1 Date: Sun, 12 May 2024 12:00:32 +0200 Subject: [PATCH 090/125] Upgrad npm dependencies --- panel/package-lock.json | 214 ++++++++++++++++++++-------------------- panel/package.json | 20 ++-- 2 files changed, 119 insertions(+), 115 deletions(-) diff --git a/panel/package-lock.json b/panel/package-lock.json index b85aa61cc7..6222f4806e 100644 --- a/panel/package-lock.json +++ b/panel/package-lock.json @@ -8,16 +8,16 @@ "dependencies": { "autosize": "^6.0.1", "container-query-polyfill": "^1.0.2", - "dayjs": "^1.11.10", + "dayjs": "^1.11.11", "mitt": "^3.0.1", "portal-vue": "^2.1.7", "prosemirror-commands": "^1.5.2", "prosemirror-history": "^1.4.0", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", - "prosemirror-model": "^1.20.0", + "prosemirror-model": "^1.21.0", "prosemirror-schema-list": "^1.3.0", - "prosemirror-view": "^1.33.4", + "prosemirror-view": "^1.33.6", "vue": "^2.7.16", "vuedraggable": "^2.24.3", "vuelidate": "^0.7.7", @@ -25,17 +25,17 @@ }, "devDependencies": { "@vitejs/plugin-vue2": "^2.3.1", - "eslint": "^9.0.0", + "eslint": "^9.2.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-vue": "^9.24.1", - "glob": "^10.3.12", + "eslint-plugin-vue": "^9.26.0", + "glob": "^10.3.15", "jsdom": "^24.0.0", "prettier": "^3.2.5", "rollup-plugin-external-globals": "^0.10.0", - "terser": "^5.30.3", - "vite": "^5.2.8", - "vite-plugin-static-copy": "^1.0.2", - "vitest": "^1.5.0", + "terser": "^5.31.0", + "vite": "^5.2.11", + "vite-plugin-static-copy": "^1.0.4", + "vitest": "^1.6.0", "vue-docgen-api": "^4.78.0", "vue-template-compiler": "^2.7.16" } @@ -537,18 +537,18 @@ } }, "node_modules/@eslint/js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.0.0.tgz", - "integrity": "sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.2.0.tgz", + "integrity": "sha512-ESiIudvhoYni+MdsI8oD7skpprZ89qKocwRM2KEvhhBJ9nl5MRh7BXU5GTod7Mdygq+AUl+QzId6iWJKR/wABA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.12.3.tgz", - "integrity": "sha512-jsNnTBlMWuTpDkeE3on7+dWJi0D6fdDfeANj/w7MpS8ztROCoLvIO2nG0CcFj+E4k8j4QrSTh4Oryi3i2G669g==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", @@ -578,6 +578,19 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, + "node_modules/@humanwhocodes/retry": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.2.4.tgz", + "integrity": "sha512-Ttl/jHpxfS3st5sxwICYfk4pOH0WrLI1SpW283GgQL7sCWU7EHIOhX4b4fkIxr3tkfzwg8+FNojtzsIEE7Ecgg==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -965,13 +978,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz", - "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.0", - "@vitest/utils": "1.5.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -979,12 +992,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", - "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.0", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -1020,9 +1033,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", - "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -1040,21 +1053,18 @@ "dev": true }, "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", - "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/@vitest/spy": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz", - "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -1064,9 +1074,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", - "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -1641,9 +1651,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" }, "node_modules/de-indent": { "version": "1.0.2", @@ -1827,17 +1837,18 @@ } }, "node_modules/eslint": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.0.0.tgz", - "integrity": "sha512-IMryZ5SudxzQvuod6rUdIUz29qFItWx281VhtFVc2Psy/ZhlCeD/5DT6lBIJ4H3G+iamGJoTln1v+QSuPw0p7Q==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.2.0.tgz", + "integrity": "sha512-0n/I88vZpCOzO+PQpt0lbsqmn9AsnsJAQseIqhZFI8ibQT0U1AkEKRxA3EVMos0BoHSXDQvCXY25TUjB5tr8Og==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^3.0.2", - "@eslint/js": "9.0.0", - "@humanwhocodes/config-array": "^0.12.3", + "@eslint/js": "9.2.0", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.2.3", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", "chalk": "^4.0.0", @@ -1853,7 +1864,6 @@ "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", @@ -1890,9 +1900,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.24.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz", - "integrity": "sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==", + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.26.0.tgz", + "integrity": "sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -2301,22 +2311,22 @@ } }, "node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "version": "10.3.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", + "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", "minimatch": "^9.0.1", "minipass": "^7.0.4", - "path-scurry": "^1.10.2" + "path-scurry": "^1.11.0" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2388,12 +2398,6 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -3239,9 +3243,9 @@ } }, "node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -3330,9 +3334,9 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", + "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" @@ -3588,16 +3592,16 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3793,9 +3797,9 @@ } }, "node_modules/prosemirror-model": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.20.0.tgz", - "integrity": "sha512-q7AY7vMjKYqDCeoedgUiAgrLabliXxndJuuFmcmc2+YU1SblvnOiG2WEACF2lwAZsMlfLpiAilA3L+TWlDqIsQ==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.21.0.tgz", + "integrity": "sha512-zLpS1mVCZLA7VTp82P+BfMiYVPcX1/z0Mf3gsjKZtzMWubwn2pN7CceMV0DycjlgE5JeXPR7UF4hJPbBV98oWA==", "dependencies": { "orderedmap": "^2.0.0" } @@ -3829,9 +3833,9 @@ } }, "node_modules/prosemirror-view": { - "version": "1.33.4", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.4.tgz", - "integrity": "sha512-xQqAhH8/HGleVpKDhQsrd+oqdyeKMxFtdCWDxWMmP+n0k27fBpyUqa8pA+RB5cFY8rqDDc1hll69aRZQa7UaAw==", + "version": "1.33.6", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.6.tgz", + "integrity": "sha512-zRLUNgLIQfd8IfGprsXxWTjdA8xEAFJe8cDNrOptj6Mop9sj+BMeVbJvceyAYCm5G2dOdT2prctH7K9dfnpIMw==", "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -4004,9 +4008,9 @@ ] }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "node_modules/readdirp": { @@ -4466,9 +4470,9 @@ "dev": true }, "node_modules/terser": { - "version": "5.30.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", - "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", + "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -4689,9 +4693,9 @@ "dev": true }, "node_modules/vite": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", - "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", + "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -4744,9 +4748,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", - "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -4766,9 +4770,9 @@ } }, "node_modules/vite-plugin-static-copy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.2.tgz", - "integrity": "sha512-AfmEF+a/mfjsUsrgjbCkhzUCeIUF4EKQXXt3Ie1cour9MBpy6f6GphbdW2td28oYfOrwCyRzFCksgLkpk58q6Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.4.tgz", + "integrity": "sha512-UtyOttgoeotSCwmBugsEZCZJZcIpjE9NGO7jlZ9OeedYpBueBdspD8waRZrjE+yQLH6qGNU2CvYB2FILviCQjg==", "dev": true, "dependencies": { "chokidar": "^3.5.3", @@ -4798,16 +4802,16 @@ } }, "node_modules/vitest": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", - "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.0", - "@vitest/runner": "1.5.0", - "@vitest/snapshot": "1.5.0", - "@vitest/spy": "1.5.0", - "@vitest/utils": "1.5.0", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -4821,7 +4825,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.0", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -4836,8 +4840,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.0", - "@vitest/ui": "1.5.0", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, diff --git a/panel/package.json b/panel/package.json index a9e2b9e3f1..4446c4c83f 100644 --- a/panel/package.json +++ b/panel/package.json @@ -13,16 +13,16 @@ "dependencies": { "autosize": "^6.0.1", "container-query-polyfill": "^1.0.2", - "dayjs": "^1.11.10", + "dayjs": "^1.11.11", "mitt": "^3.0.1", "portal-vue": "^2.1.7", "prosemirror-commands": "^1.5.2", "prosemirror-history": "^1.4.0", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", - "prosemirror-model": "^1.20.0", + "prosemirror-model": "^1.21.0", "prosemirror-schema-list": "^1.3.0", - "prosemirror-view": "^1.33.4", + "prosemirror-view": "^1.33.6", "vue": "^2.7.16", "vuedraggable": "^2.24.3", "vuelidate": "^0.7.7", @@ -30,17 +30,17 @@ }, "devDependencies": { "@vitejs/plugin-vue2": "^2.3.1", - "eslint": "^9.0.0", + "eslint": "^9.2.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-vue": "^9.24.1", - "glob": "^10.3.12", + "eslint-plugin-vue": "^9.26.0", + "glob": "^10.3.15", "jsdom": "^24.0.0", "prettier": "^3.2.5", "rollup-plugin-external-globals": "^0.10.0", - "terser": "^5.30.3", - "vite": "^5.2.8", - "vite-plugin-static-copy": "^1.0.2", - "vitest": "^1.5.0", + "terser": "^5.31.0", + "vite": "^5.2.11", + "vite-plugin-static-copy": "^1.0.4", + "vitest": "^1.6.0", "vue-docgen-api": "^4.78.0", "vue-template-compiler": "^2.7.16" }, From 94d5729e861ccfc0bbdd8b846d8b82bd8188cd1c Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sun, 24 Mar 2024 18:15:19 +0100 Subject: [PATCH 091/125] Login lab examples --- .../lab/components/login/login-code/index.php | 5 + .../lab/components/login/login-code/index.vue | 15 ++ panel/lab/components/login/login/index.php | 5 + panel/lab/components/login/login/index.vue | 26 +++ panel/src/components/Forms/Login.vue | 155 +++++++++++------- panel/src/components/Forms/LoginCode.vue | 41 +++-- .../src/components/Views/Login/LoginView.vue | 59 ++----- 7 files changed, 189 insertions(+), 117 deletions(-) create mode 100644 panel/lab/components/login/login-code/index.php create mode 100644 panel/lab/components/login/login-code/index.vue create mode 100644 panel/lab/components/login/login/index.php create mode 100644 panel/lab/components/login/login/index.vue diff --git a/panel/lab/components/login/login-code/index.php b/panel/lab/components/login/login-code/index.php new file mode 100644 index 0000000000..939f9c01da --- /dev/null +++ b/panel/lab/components/login/login-code/index.php @@ -0,0 +1,5 @@ + 'k-login-code' +]; diff --git a/panel/lab/components/login/login-code/index.vue b/panel/lab/components/login/login-code/index.vue new file mode 100644 index 0000000000..a9581334a8 --- /dev/null +++ b/panel/lab/components/login/login-code/index.vue @@ -0,0 +1,15 @@ + diff --git a/panel/lab/components/login/login/index.php b/panel/lab/components/login/login/index.php new file mode 100644 index 0000000000..681fdf8c82 --- /dev/null +++ b/panel/lab/components/login/login/index.php @@ -0,0 +1,5 @@ + 'k-login' +]; diff --git a/panel/lab/components/login/login/index.vue b/panel/lab/components/login/login/index.vue new file mode 100644 index 0000000000..7b201b4df2 --- /dev/null +++ b/panel/lab/components/login/login/index.vue @@ -0,0 +1,26 @@ + diff --git a/panel/src/components/Forms/Login.vue b/panel/src/components/Forms/Login.vue index 27b2535048..d006baf3a3 100644 --- a/panel/src/components/Forms/Login.vue +++ b/panel/src/components/Forms/Login.vue @@ -1,32 +1,31 @@ - - + @@ -48,12 +46,18 @@ export const props = { /** * List of available login method names */ - methods: Array, + methods: { + type: Array, + default: () => [] + }, /** * Values to prefill the inputs - * @value { email: String, password: String } + * @value { email: String, password: String, remember: Boolean } */ - value: Object + value: { + type: Object, + default: () => ({}) + } } }; @@ -62,22 +66,36 @@ export default { emits: ["error"], data() { return { - currentForm: null, + mode: null, isLoading: false, user: { - email: this.value.email ?? "", - password: this.value.password ?? "", - remember: false + email: "", + password: "", + remember: false, + ...this.value } }; }, computed: { + alternateMode() { + if (this.form === "email-password") { + return "email"; + } + + return "email-password"; + }, canToggle() { + if (this.codeMode === null) { + return false; + } + + if (this.methods.includes("password") === false) { + return false; + } + return ( - this.codeMode !== null && - this.methods.includes("password") === true && - (this.methods.includes("password-reset") === true || - this.methods.includes("code") === true) + this.methods.includes("password-reset") === true || + this.methods.includes("code") === true ); }, codeMode() { @@ -90,7 +108,7 @@ export default { return null; }, fields() { - let fields = { + const fields = { email: { autofocus: true, label: this.$t("email"), @@ -114,8 +132,8 @@ export default { return fields; }, form() { - if (this.currentForm) { - return this.currentForm; + if (this.mode) { + return this.mode; } if (this.methods[0] === "password") { @@ -127,28 +145,30 @@ export default { isResetForm() { return this.codeMode === "password-reset" && this.form === "email"; }, + submitText() { + const suffix = this.isLoading ? " …" : ""; + + if (this.isResetForm) { + return this.$t("login.reset") + suffix; + } + + return this.$t("login") + suffix; + }, toggleText() { return this.$t( - "login.toggleText." + this.codeMode + "." + this.formOpposite(this.form) + "login.toggleText." + this.codeMode + "." + this.alternateMode ); } }, methods: { - formOpposite(input) { - if (input === "email-password") { - return "email"; - } else { - return "email-password"; - } - }, async login() { this.$emit("error", null); this.isLoading = true; // clear field data that is not needed for login - let user = Object.assign({}, this.user); + const user = Object.assign({}, this.user); - if (this.currentForm === "email") { + if (this.mode === "email") { user.password = null; } @@ -173,10 +193,35 @@ export default { this.isLoading = false; } }, - toggleForm() { - this.currentForm = this.formOpposite(this.form); + toggle() { + this.mode = this.alternateMode; this.$refs.fieldset.focus("email"); } } }; + + diff --git a/panel/src/components/Forms/LoginCode.vue b/panel/src/components/Forms/LoginCode.vue index 642dcf9b2d..dfe25125d3 100644 --- a/panel/src/components/Forms/LoginCode.vue +++ b/panel/src/components/Forms/LoginCode.vue @@ -1,6 +1,6 @@ @@ -49,12 +49,18 @@ export const props = { /** * List of available login method names */ - methods: Array, + methods: { + type: Array, + default: () => [] + }, /** * Pending login data (user email, challenge type) * @value { email: String, challenge: String } */ - pending: Object, + pending: { + type: Object, + default: () => ({ challenge: "email" }) + }, /** * Code value to prefill the input */ @@ -68,27 +74,20 @@ export default { data() { return { code: this.value ?? "", - isLoadingBack: false, - isLoadingLogin: false + isLoading: false }; }, computed: { mode() { - if (this.methods.includes("password-reset") === true) { - return "password-reset"; - } - - return "login"; + return this.methods.includes("password-reset") + ? "password-reset" + : "login"; } }, methods: { - async back() { - this.isLoadingBack = true; - this.$go("/logout"); - }, async login() { this.$emit("error", null); - this.isLoadingLogin = true; + this.isLoading = true; try { await this.$api.auth.verifyCode(this.code); @@ -106,7 +105,7 @@ export default { } catch (error) { this.$emit("error", error); } finally { - this.isLoadingLogin = false; + this.isLoading = false; } } } diff --git a/panel/src/components/Views/Login/LoginView.vue b/panel/src/components/Views/Login/LoginView.vue index 4552b4d817..4118caa96b 100644 --- a/panel/src/components/Views/Login/LoginView.vue +++ b/panel/src/components/Views/Login/LoginView.vue @@ -1,7 +1,9 @@