From f215df8e36adf144cb2039bb7207e95343027759 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sat, 11 Jan 2025 14:02:37 +0100 Subject: [PATCH 01/37] System view: plugin license status separate column --- config/areas/system/views.php | 1 + .../components/Views/System/SystemPlugins.vue | 4 ++ .../Views/System/TableLicenseCell.vue | 21 ++------- .../Views/System/TableLicenseStatusCell.vue | 45 +++++++++++++++++++ panel/src/components/Views/System/index.js | 2 + src/Plugin/LicenseStatus.php | 38 ++++++++++++++-- tests/Panel/Areas/SystemTest.php | 31 +++++++++---- 7 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 panel/src/components/Views/System/TableLicenseStatusCell.vue diff --git a/config/areas/system/views.php b/config/areas/system/views.php index 44797d5a35..d31143ff8b 100644 --- a/config/areas/system/views.php +++ b/config/areas/system/views.php @@ -63,6 +63,7 @@ 'text' => $plugin->name() ?? '–', 'href' => $plugin->link(), ], + 'status' => $plugin->license()->status()->toArray(), 'version' => $version, ]; }); diff --git a/panel/src/components/Views/System/SystemPlugins.vue b/panel/src/components/Views/System/SystemPlugins.vue index e2c6ec2519..687ba13cce 100644 --- a/panel/src/components/Views/System/SystemPlugins.vue +++ b/panel/src/components/Views/System/SystemPlugins.vue @@ -19,6 +19,10 @@ label: $t('license'), type: 'license' }, + status: { + label: $t('license.status'), + type: 'license-status' + }, version: { label: $t('version'), type: 'update-status', diff --git a/panel/src/components/Views/System/TableLicenseCell.vue b/panel/src/components/Views/System/TableLicenseCell.vue index 35c3c680b1..c0365b09f6 100644 --- a/panel/src/components/Views/System/TableLicenseCell.vue +++ b/panel/src/components/Views/System/TableLicenseCell.vue @@ -1,16 +1,9 @@ @@ -25,9 +18,3 @@ export default { } }; - - diff --git a/panel/src/components/Views/System/TableLicenseStatusCell.vue b/panel/src/components/Views/System/TableLicenseStatusCell.vue new file mode 100644 index 0000000000..d6a3eb7ea6 --- /dev/null +++ b/panel/src/components/Views/System/TableLicenseStatusCell.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/panel/src/components/Views/System/index.js b/panel/src/components/Views/System/index.js index 557d3ac448..f770ed0588 100644 --- a/panel/src/components/Views/System/index.js +++ b/panel/src/components/Views/System/index.js @@ -1,11 +1,13 @@ import SystemView from "./SystemView.vue"; import TableLicenseCell from "./TableLicenseCell.vue"; +import TableLicenseStatusCell from "./TableLicenseStatusCell.vue"; import TableUpdateStatusCell from "./TableUpdateStatusCell.vue"; export default { install(app) { app.component("k-system-view", SystemView); app.component("k-table-license-cell", TableLicenseCell); + app.component("k-table-license-status-cell", TableLicenseStatusCell); app.component("k-table-update-status-cell", TableUpdateStatusCell); } }; diff --git a/src/Plugin/LicenseStatus.php b/src/Plugin/LicenseStatus.php index 1a75e7c544..e47c233490 100644 --- a/src/Plugin/LicenseStatus.php +++ b/src/Plugin/LicenseStatus.php @@ -20,6 +20,9 @@ public function __construct( protected string $value, protected string $icon, protected string $label, + protected string|null $link = null, + protected string|null $dialog = null, + protected string|null $drawer = null, protected string|null $theme = null ) { } @@ -32,6 +35,22 @@ public function __toString(): string return $this->label(); } + /** + * Returns the status dialog + */ + public function dialog(): string|null + { + return $this->dialog; + } + + /** + * Returns the status drawer + */ + public function drawer(): string|null + { + return $this->drawer; + } + /** * Returns a status by its name */ @@ -72,6 +91,14 @@ public function label(): string return $this->label; } + /** + * Returns the status link + */ + public function link(): string|null + { + return $this->link; + } + /** * Returns the theme */ @@ -86,10 +113,13 @@ public function theme(): string|null public function toArray(): array { return [ - 'icon' => $this->icon(), - 'label' => $this->label(), - 'theme' => $this->theme(), - 'value' => $this->value(), + 'dialog' => $this->dialog(), + 'drawer' => $this->drawer(), + 'icon' => $this->icon(), + 'label' => $this->label(), + 'link' => $this->link(), + 'theme' => $this->theme(), + 'value' => $this->value(), ]; } diff --git a/tests/Panel/Areas/SystemTest.php b/tests/Panel/Areas/SystemTest.php index 9f5bbd7c40..de558c7e01 100644 --- a/tests/Panel/Areas/SystemTest.php +++ b/tests/Panel/Areas/SystemTest.php @@ -37,14 +37,22 @@ public function setUp(): void public function unknownLicense(): array { return [ - 'link' => null, - 'name' => '-', - 'status' => [ - 'icon' => 'question', - 'label' => 'Unknown license', - 'theme' => 'passive', - 'value' => 'unknown', - ] + 'link' => null, + 'name' => '-', + 'status' => $this->unknownLicenseStatus() + ]; + } + + public function unknownLicenseStatus(): array + { + return [ + 'dialog' => null, + 'drawer' => null, + 'icon' => 'question', + 'label' => 'Unknown license', + 'link' => null, + 'theme' => 'passive', + 'value' => 'unknown', ]; } @@ -199,6 +207,7 @@ public function testViewWithPlugins(): void 'text' => 'getkirby/private', 'href' => null ], + 'status' => $this->unknownLicenseStatus(), 'version' => [ 'currentVersion' => '?', 'icon' => 'question', @@ -216,6 +225,7 @@ public function testViewWithPlugins(): void 'text' => 'getkirby/public', 'href' => 'https://getkirby.com' ], + 'status' => $this->unknownLicenseStatus(), 'version' => [ 'currentVersion' => '1.0.0', 'icon' => 'info', @@ -233,6 +243,7 @@ public function testViewWithPlugins(): void 'text' => 'getkirby/unknown', 'href' => null ], + 'status' => $this->unknownLicenseStatus(), 'version' => [ 'currentVersion' => '1.0.0', 'icon' => 'question', @@ -293,6 +304,7 @@ public function testViewWithPluginsDebug(): void 'text' => 'getkirby/private', 'href' => null ], + 'status' => $this->unknownLicenseStatus(), 'version' => [ 'currentVersion' => '?', 'icon' => 'question', @@ -310,6 +322,7 @@ public function testViewWithPluginsDebug(): void 'text' => 'getkirby/public', 'href' => 'https://getkirby.com' ], + 'status' => $this->unknownLicenseStatus(), 'version' => [ 'currentVersion' => '1.0.0', 'icon' => 'info', @@ -327,6 +340,7 @@ public function testViewWithPluginsDebug(): void 'text' => 'getkirby/unknown', 'href' => null ], + 'status' => $this->unknownLicenseStatus(), 'version' => [ 'currentVersion' => '1.0.0', 'icon' => 'question', @@ -411,6 +425,7 @@ public function testViewWithoutUpdateCheck(): void 'text' => 'getkirby/public', 'href' => 'https://getkirby.com' ], + 'status' => $this->unknownLicenseStatus(), 'version' => '1.0.0' ] ], $props['plugins']); From 959509f7fd33731f7c89989648e93f647a444717 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 15 Jan 2025 11:48:09 +0100 Subject: [PATCH 02/37] Make the image location required --- config/blocks/image/image.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/blocks/image/image.yml b/config/blocks/image/image.yml index ada9313a36..dc348a591f 100644 --- a/config/blocks/image/image.yml +++ b/config/blocks/image/image.yml @@ -7,6 +7,7 @@ fields: type: radio columns: 2 default: "kirby" + required: true options: kirby: "{{ t('field.blocks.image.location.internal') }}" web: "{{ t('field.blocks.image.location.external') }}" From 867a1018ac86c9916e46dc3d3cb974334f5580aa Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 17 Jan 2025 10:09:32 +0100 Subject: [PATCH 03/37] Merge latest content changes to keep them --- panel/src/panel/content.js | 1 + 1 file changed, 1 insertion(+) diff --git a/panel/src/panel/content.js b/panel/src/panel/content.js index 443235856f..ba902140ff 100644 --- a/panel/src/panel/content.js +++ b/panel/src/panel/content.js @@ -167,6 +167,7 @@ export default (panel) => { panel.view.props.content = { ...panel.view.props.originals, + ...panel.view.props.content, ...values }; From 1208fcc19a886f9fa8cb12379cfe97f967053c74 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Fri, 17 Jan 2025 10:24:53 +0100 Subject: [PATCH 04/37] Bring back the onInput event emitter in the files field --- panel/src/components/Forms/Field/FilesField.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/panel/src/components/Forms/Field/FilesField.vue b/panel/src/components/Forms/Field/FilesField.vue index 0b9fce491c..d11f30e621 100644 --- a/panel/src/components/Forms/Field/FilesField.vue +++ b/panel/src/components/Forms/Field/FilesField.vue @@ -59,6 +59,7 @@ export default { [this.name]: this.selected }); + this.onInput(); this.$events.emit("file.upload"); this.$events.emit("model.update"); } From 53a5b62c8cd005015589bf21eaed00423aea79cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20Hoffmann=20=20=E0=B7=B4=2E?= Date: Fri, 17 Jan 2025 15:55:05 +0100 Subject: [PATCH 05/37] Delete stale bot --- .github/workflows/stale.yml | 46 ------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index d4ba3dbf95..0000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,46 +0,0 @@ -# Close Stale Issues -# Warns and then closes issues and PRs that have had no activity for a specified amount of time. -# https://github.com/actions/stale - -name: Close Stale Issues -on: - schedule: - - cron: "0 0 * * *" - -jobs: - stale: - runs-on: ubuntu-22.04 - steps: - - uses: actions/stale@6f05e4244c9a0b2ed3401882b05d701dd0a7289b # pin@v7 - with: - # Idle number of days before marking issues stale, set `-1` to disable - days-before-issue-stale: 60 - - # Idle number of days before marking issues stale, set `-1` to disable - days-before-pr-stale: 60 - - # Idle number of days before closing stale issues/PRs - days-before-close: 15 - - # Comment on the staled issues - stale-issue-message: "This issue has been marked as stale because it requires further input but has not seen activity in the past months. This is for us to prioritize issues that are still relevant and actionable. It will be closed if no further activity occurs within the next 15 days. If this issue is still relevant to you, please help us in gathering the necessary input." - - # Comment on the staled PRs - stale-pr-message: "This PR has been marked as stale because it requires further changes but has not seen activity in the past months. This is for us to prioritize PRs that can be reviewed and merged. It will be closed if no further activity occurs within the next 15 days. If you still have interest in this PR, please help us finalizing it. Please let us know in case you are stuck on the required changes." - - # Label to apply on staled issues - stale-issue-label: "type: stale 💤" - - # Label to apply on staled PRs - stale-pr-label: "type: stale 💤" - - # Reason to use when closing issues - close-issue-reason: not_planned - - # Labels to check for stale issues/PRs - any-of-pr-labels: "needs: changes 🔁" - any-of-issue-labels: "needs: information ❓,needs: replication 🔬" - - # PRs/issues exempted from stale - exempt-all-milestones: true - exempt-issue-labels: "critical: roadblock 🚧,type: regression 🚨" From 7f6a30097f56b6c60f1867678461cb370f222f68 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sat, 7 Dec 2024 18:20:21 +0100 Subject: [PATCH 06/37] Make use of CSS `:has()` --- panel/src/components/Collection/Item.vue | 17 +++-------------- panel/src/components/Dialogs/Dialog.vue | 1 - panel/src/components/Dialogs/Elements/Body.vue | 3 +-- panel/src/components/Drawers/Elements/Body.vue | 1 - .../components/Forms/Blocks/Types/Fields.vue | 5 ----- .../src/components/Forms/Field/BlocksField.vue | 6 ++++-- panel/src/components/Forms/Field/DateField.vue | 5 ++--- .../src/components/Forms/Field/LayoutField.vue | 5 +++-- .../components/Forms/Field/StructureField.vue | 5 +++-- .../src/components/Forms/Input/TogglesInput.vue | 9 ++------- .../src/components/Forms/Input/WriterInput.vue | 1 - panel/src/components/Forms/Toolbar/Toolbar.vue | 8 +++++--- panel/src/components/Forms/Writer/Toolbar.vue | 7 ++++--- panel/src/components/Lab/PlaygroundView.vue | 7 ++----- panel/src/components/Layout/Bubble.vue | 4 +--- panel/src/components/Layout/Header.vue | 10 +++------- panel/src/components/Navigation/Browser.vue | 1 - panel/src/components/Navigation/Button.vue | 13 ++++--------- panel/src/components/Navigation/Tag.vue | 5 +---- panel/src/components/Navigation/Tree.vue | 8 ++------ panel/src/components/Views/Files/FileView.vue | 4 +--- panel/src/components/Views/ModelView.vue | 3 --- panel/src/components/Views/Pages/PageView.vue | 4 +--- panel/src/components/Views/Pages/SiteView.vue | 4 +--- panel/src/components/Views/Users/UserView.vue | 4 +--- panel/src/styles/reset.css | 17 ++++++----------- 26 files changed, 50 insertions(+), 107 deletions(-) diff --git a/panel/src/components/Collection/Item.vue b/panel/src/components/Collection/Item.vue index 7a8e0b6e4b..0b0bcf7d9b 100644 --- a/panel/src/components/Collection/Item.vue +++ b/panel/src/components/Collection/Item.vue @@ -2,7 +2,6 @@
:first-child:last-child) */ -.k-item-options[data-only-option="true"] { +.k-item-options:has(> :first-child:last-child) { justify-content: flex-end; } .k-item-options .k-button { @@ -219,8 +210,7 @@ export default { align-items: center; grid-template-columns: 1fr auto; } -/** TODO: .k-item[data-layout="list"]:has(.k-item-image) */ -.k-item[data-layout="list"][data-has-image="true"] { +.k-item[data-layout="list"]:has(.k-item-image) { grid-template-columns: var(--item-height) 1fr auto; } .k-item[data-layout="list"] .k-frame { @@ -279,8 +269,7 @@ export default { grid-template-columns: 1fr; grid-template-rows: 1fr var(--height-md); } -/** TODO: .k-item[data-layout="cardlets"]:has(.k-item-image) */ -.k-item[data-layout="cardlets"][data-has-image="true"] { +.k-item[data-layout="cardlets"]:has(.k-item-image) { grid-template-areas: "image content" "image options"; diff --git a/panel/src/components/Dialogs/Dialog.vue b/panel/src/components/Dialogs/Dialog.vue index 88966fd328..c16a232b3e 100644 --- a/panel/src/components/Dialogs/Dialog.vue +++ b/panel/src/components/Dialogs/Dialog.vue @@ -7,7 +7,6 @@ $vnode.data.staticClass, $attrs.class ]" - :data-has-footer="Boolean(cancelButton || submitButton)" :data-size="size" method="dialog" @click.stop diff --git a/panel/src/components/Dialogs/Elements/Body.vue b/panel/src/components/Dialogs/Elements/Body.vue index 888d818d7b..0deebaad28 100644 --- a/panel/src/components/Dialogs/Elements/Body.vue +++ b/panel/src/components/Dialogs/Elements/Body.vue @@ -16,8 +16,7 @@ export default {}; .k-dialog-body { padding: var(--dialog-padding); } -/** TODO: .k-dialog:has(.k-dialog-footer) .k-dialog-body */ -.k-dialog[data-has-footer="true"] .k-dialog-body { +.k-dialog:has(.k-dialog-footer) .k-dialog-body { padding-bottom: 0; } diff --git a/panel/src/components/Drawers/Elements/Body.vue b/panel/src/components/Drawers/Elements/Body.vue index 1541898fc4..053b5a36ac 100644 --- a/panel/src/components/Drawers/Elements/Body.vue +++ b/panel/src/components/Drawers/Elements/Body.vue @@ -19,7 +19,6 @@ export default {}; background: var(--drawer-color-back); } /* Sticky elements inside drawer */ -/** TODO: .k-drawer-body .k-toolbar:not([data-inline="true"]):has(~ :focus-within) */ .k-drawer-body .k-writer-input:focus-within .k-toolbar:not([data-inline="true"]), diff --git a/panel/src/components/Forms/Blocks/Types/Fields.vue b/panel/src/components/Forms/Blocks/Types/Fields.vue index 5bdce1167e..3f4ed1b12a 100644 --- a/panel/src/components/Forms/Blocks/Types/Fields.vue +++ b/panel/src/components/Forms/Blocks/Types/Fields.vue @@ -78,13 +78,10 @@ export default { diff --git a/panel/src/components/Forms/Field/DateField.vue b/panel/src/components/Forms/Field/DateField.vue index 8d8d9c6a42..7980670857 100644 --- a/panel/src/components/Forms/Field/DateField.vue +++ b/panel/src/components/Forms/Field/DateField.vue @@ -5,7 +5,7 @@ :input="id" :style="$attrs.style" > -
+
diff --git a/panel/src/components/Forms/Field/StructureField.vue b/panel/src/components/Forms/Field/StructureField.vue index adcd3b2799..4ccd8256b6 100644 --- a/panel/src/components/Forms/Field/StructureField.vue +++ b/panel/src/components/Forms/Field/StructureField.vue @@ -559,10 +559,11 @@ export default { .k-structure-field:not([data-disabled="true"]) td.k-table-column { cursor: pointer; } -/** .k-structure-field .k-table:has(+ footer) */ .k-structure-field .k-table + footer { display: flex; justify-content: center; - margin-top: var(--spacing-3); +} +.k-structure-field .k-table:has(+ footer) { + margin-bottom: var(--spacing-3); } diff --git a/panel/src/components/Forms/Input/TogglesInput.vue b/panel/src/components/Forms/Input/TogglesInput.vue index 2f85adca97..da01d391a9 100644 --- a/panel/src/components/Forms/Input/TogglesInput.vue +++ b/panel/src/components/Forms/Input/TogglesInput.vue @@ -11,11 +11,7 @@ :data-labels="labels" :style="{ '--options': columns ?? options.length }" > -
  • +
  • diff --git a/panel/src/components/Forms/Toolbar/Toolbar.vue b/panel/src/components/Forms/Toolbar/Toolbar.vue index 364cddeb84..2be99ea87c 100644 --- a/panel/src/components/Forms/Toolbar/Toolbar.vue +++ b/panel/src/components/Forms/Toolbar/Toolbar.vue @@ -130,9 +130,11 @@ export default { border-end-end-radius: var(--rounded); } -/** TODO: .k-toolbar:not([data-inline="true"]):has(~ :focus-within) */ -:where(.k-textarea-input, .k-writer-input):focus-within - .k-toolbar:not([data-inline="true"]) { +:where(.k-textarea-input, .k-writer-input):not(:focus-within) { + --toolbar-text: var(--color-gray-400); + --toolbar-border: var(--panel-color-back); +} +.k-toolbar:not([data-inline="true"]):has(~ :focus-within) { position: sticky; top: var(--header-sticky-offset); inset-inline: 0; diff --git a/panel/src/components/Forms/Writer/Toolbar.vue b/panel/src/components/Forms/Writer/Toolbar.vue index 013cc7682c..e2a80aa447 100644 --- a/panel/src/components/Forms/Writer/Toolbar.vue +++ b/panel/src/components/Forms/Writer/Toolbar.vue @@ -420,14 +420,15 @@ export default { diff --git a/panel/src/components/Navigation/Browser.vue b/panel/src/components/Navigation/Browser.vue index 1dbc7edc77..2c72fc8505 100644 --- a/panel/src/components/Navigation/Browser.vue +++ b/panel/src/components/Navigation/Browser.vue @@ -109,7 +109,6 @@ export default { box-shadow: var(--shadow); flex-shrink: 0; } -/** TODO: .k-browser-item-image:has(svg) */ .k-browser-item-image.k-icon-frame { box-shadow: none; background: light-dark(var(--color-white), var(--color-black)); diff --git a/panel/src/components/Navigation/Button.vue b/panel/src/components/Navigation/Button.vue index b152362f9a..76b9b8242d 100644 --- a/panel/src/components/Navigation/Button.vue +++ b/panel/src/components/Navigation/Button.vue @@ -3,8 +3,6 @@ :is="component" v-bind="attrs" :class="['k-button', $attrs.class]" - :data-has-icon="Boolean(icon)" - :data-has-text="Boolean(text || $slots.default)" :style="$attrs.style" @click="onClick" > @@ -327,25 +325,22 @@ export default { } /** Icon Buttons **/ -/** TODO: .k-button:not(:has(.k-button-text)) */ -.k-button:not([data-has-text="true"]) { +.k-button:not(:has(.k-button-text)) { --button-padding: 0; aspect-ratio: 1/1; } /** Responsive buttons **/ @container (max-width: 30rem) { - /** TODO: .k-button:is([data-responsive]:has(.k-button-icon)) */ - .k-button[data-responsive="true"][data-has-icon="true"] { + .k-button:is([data-responsive]:has(.k-button-icon)) { --button-padding: 0; aspect-ratio: 1/1; --button-text-display: none; } - .k-button[data-responsive="text"][data-has-text="true"] { + .k-button[data-responsive="text"]:has(.k-button-text) { --button-icon-display: none; } - /** TODO: .k-button:is([data-responsive]:has(.k-button-icon)) .k-button-arrow */ - .k-button[data-responsive="true"][data-has-icon="true"] .k-button-arrow { + .k-button:is([data-responsive]:has(.k-button-icon)) .k-button-arrow { display: none; } } diff --git a/panel/src/components/Navigation/Tag.vue b/panel/src/components/Navigation/Tag.vue index 29c619951e..a2b3e0feca 100644 --- a/panel/src/components/Navigation/Tag.vue +++ b/panel/src/components/Navigation/Tag.vue @@ -2,8 +2,6 @@ -

    +