diff --git a/.github/workflows/facades.yml b/.github/workflows/facades.yml index 912ddd24763..d66009ce277 100644 --- a/.github/workflows/facades.yml +++ b/.github/workflows/facades.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -57,17 +57,22 @@ jobs: php -f vendor/bin/facade.php -- \ CraftCms\\Cms\\Support\\Facades\\Announcements \ CraftCms\\Cms\\Support\\Facades\\Deprecator \ + CraftCms\\Cms\\Support\\Facades\\Entries \ CraftCms\\Cms\\Support\\Facades\\EntryTypes \ CraftCms\\Cms\\Support\\Facades\\Fields \ CraftCms\\Cms\\Support\\Facades\\I18N \ CraftCms\\Cms\\Support\\Facades\\ProjectConfig \ CraftCms\\Cms\\Support\\Facades\\Sections \ + CraftCms\\Cms\\Support\\Facades\\SiteGroups \ + CraftCms\\Cms\\Support\\Facades\\Sites \ CraftCms\\Cms\\Support\\Facades\\Structures \ CraftCms\\Cms\\Support\\Facades\\Updates \ - CraftCms\\Cms\\Support\\Facades\\UserGroups + CraftCms\\Cms\\Support\\Facades\\UserGroups \ + CraftCms\\Cms\\Support\\Facades\\UserPermissions \ + CraftCms\\Cms\\Support\\Facades\\Users - name: Commit facade docblocks - uses: stefanzweifel/git-auto-commit-action@v5 + uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: Update facade docblocks file_pattern: src/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 5514030fee3..f16af0316a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,21 @@ ## Unreleased +- User queries now always return active, non-pending users first, unless otherwise specified by `orderBy`. ([#18148](https://github.com/craftcms/cms/issues/18148)) +- The `utils/fix-field-layout-uids` command now checks for duplicate top-level field layout UUIDs. ([#18193](https://github.com/craftcms/cms/pull/18193)) +- Fixed a bug where all plugin settings were being saved to the project config, rather than just posted settings. ([craftcms/commerce#4006](https://github.com/craftcms/commerce/issues/4006)) +- Fixed a bug where custom selects could be positioned incorrectly after the window was resized. ([#18179](https://github.com/craftcms/cms/issues/18179)) - Fixed a bug where Matrix fields’ Entry Types settings were partially interactive when admin changes were disallowed. ([#18145](https://github.com/craftcms/cms/pull/18145)) - Fixed a bug where users could be unable to sign in if an inactive user account existed with the same email address. ([#18148](https://github.com/craftcms/cms/issues/18148)) - Fixed a bug where Content Block fields could appear to be missing their content when viewing a revision. ([#18149](https://github.com/craftcms/cms/issues/18149)) - Fixed a bug where Dropdown and Radio Button fields weren’t handling `:empty:`/`:notempty:` element query params properly for options with blank values. ([#18156](https://github.com/craftcms/cms/issues/18156)) - Fixed a bug where chip icons were getting rounded. ([#18163](https://github.com/craftcms/cms/pull/18163)) - Fixed a bug where object templates that included another template were missing variables. ([#18165](https://github.com/craftcms/cms/issues/18165)) +- Fixed a JavaScript error that could occur if two control panel animations were triggered simultaneously. +- Fixed a bug where it wasn’t possible to copy/paste nested entries within Matrix fields set to the inline-editable blocks view mode, for unpublished owner elements. ([#18185](https://github.com/craftcms/cms/pull/18185)) +- Fixed a bug where custom fields’ checkboxes weren’t getting removed from field layouts’ “Card Attributes” lists when removed from the layout. +- Fixed an SSRF vulnerability. (GHSA-96pq-hxpw-rgh8) +- Fixed an XSS vulnerability. (GHSA-7pr4-wx9w-mqwr) ## 5.8.21 - 2025-12-04 @@ -20,10 +29,10 @@ - Fixed a bug where relation fields weren’t handling `:empty:`/`:notempty:` element query params properly if the field had multiple instances within a field layout. ([#18092](https://github.com/craftcms/cms/pull/18092)) - Fixed a bug where user preferences were being respected for users who formerly had access to the control panel. - Fixed a bug where nested entries could be reordered when their owner element was resaved programmatically. ([#18121](https://github.com/craftcms/cms/pull/18121)) -- Fixed RCE vulnerabilities. (GHSA-255j-qw47-wjh5, GHSA-742x-x762-7383) -- Fixed an SSRF vulnerability. (GHSA-x27p-wfqw-hfcc) -- Fixed a DoS vulnerability. (GHSA-v64r-7wg9-23pr) -- Fixed an information disclosure vulnerability. (GHSA-53vf-c43h-j2x9) +- Fixed RCE vulnerabilities. ([GHSA-255j-qw47-wjh5](https://github.com/craftcms/cms/security/advisories/GHSA-255j-qw47-wjh5), [GHSA-742x-x762-7383](https://github.com/craftcms/cms/security/advisories/GHSA-742x-x762-7383)) +- Fixed an SSRF vulnerability. ([GHSA-x27p-wfqw-hfcc](https://github.com/craftcms/cms/security/advisories/GHSA-x27p-wfqw-hfcc)) +- Fixed a DoS vulnerability. ([GHSA-v64r-7wg9-23pr](https://github.com/craftcms/cms/security/advisories/GHSA-v64r-7wg9-23pr)) +- Fixed an information disclosure vulnerability. ([GHSA-53vf-c43h-j2x9](https://github.com/craftcms/cms/security/advisories/GHSA-53vf-c43h-j2x9)) ## 5.8.20 - 2025-11-18 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 14f5f12ac05..476edd4ce53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,6 +67,55 @@ If you want to help improve Craft’s translations, [sign up to be a translator] If you would like to work on a new core feature or improvement, first create a [GitHub issue](https://github.com/craftcms/cms/issues) for it if there’s not one already. As much as we appreciate community contributions, we are pretty selective about which sorts of features should make it into Craft itself rather than a plugin, so don’t take it the wrong way if we advise you to pursue the idea as a plugin instead. +## Control Panel Front End + +In order to work on the control panel front end, we recommend opening two terminal windows. + +1. Run `npm run dev` in one window to start the Vite development server. +2. Run `npm run dev:cp` in the other window to start the Vite process for the `@craftcms/cp` package. + +With both processes running, you'll be able to work on most aspects of the control panel. + +If getting into the weeds is your thing, more detail on these pieces is provided below. + +### Control Panel Assets + +The assets specific to the control panel live in the `resources` folder. Those are built using a fairly typical Vite setup. To develop assets for the control panel, there are two commands: +```shell +# Run the Vite development server +npm run dev + +# Build assets for production +npm run build +``` + +### `@craftcms/cp` package + +The control panel is largely backed by web components that live in the `@craftcms/cp` package within the `packages/craftcms-cp` directory. Like other packages, it has its own build process that can be run independently of the control panel. +```shell +# Run the build in watch mode. Assets will be rebuilt on every change +npm run dev:cp + +# Run the build for production +npm run build:cp +``` + +In practice, you rarely work on one without the other, so we recommend having two terminal panes open. One running the main control panel assets build and another building the web components. + +### Legacy Bundles + +> [!NOTE] +> Updating the legacy bundles should be a rare occurrence. Avoid when possible. + +All the styles and scripts used to support the control panel up until Craft 5 live in the [yii2-adapter](https://github.com/craftcms/yii2-adapter) package. That package has its own NPM dependencies and build process, but because it's common to have that package symlinked into your Craft 6 project, you're able to run the build scripts via the `build:bundles` command. +```sh +# Build assets for production +npm run build:bundles + +# Run dev server to develop a specific package +npm run dev:bundles -- -- --config-name=cp +``` + ## Pull Requests Pull requests should clearly describe the problem and solution. Include the relevant issue number if there is one. If the pull request fixes a bug, it should include a new test case that demonstrates the issue, if possible. diff --git a/package-lock.json b/package-lock.json index 8a7e9273e89..0dc3fa95b05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@craftcms/cp": "file:packages/craftcms-cp", "@inertiajs/vue3": "^2.2.7", + "@tanstack/vue-table": "^8.21.3", "@vueuse/core": "^14.0.0", "axios": "^1.13.2", "laravel-vite-plugin": "^2.0.1", @@ -6273,6 +6274,19 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/virtual-core": { "version": "3.13.12", "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", @@ -6283,6 +6297,25 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/vue-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/vue-table/-/vue-table-8.21.3.tgz", + "integrity": "sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vue": ">=3.2" + } + }, "node_modules/@testing-library/dom": { "version": "10.4.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", diff --git a/package.json b/package.json index 1442fb8c80a..b5ce4b78bba 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,13 @@ "prebuild": "npm run fix-prettier", "build": "vite build", "dev": "vite", - "build:bundles": "cd yii2-adapter && npm run build", - "dev:bundles": "cd yii2-adapter && npm run dev", - "serve:bundles": "cd yii2-adapter && npm run serve", - "dev:cp": "npm run dev -w @craftcms/cp", - "build:cp": "npm run build -w @craftcms/cp", - "test:cp": "npm run test -w @craftcms/cp", - "storybook:cp": "npm run storybook -w @craftcms/cp", + "build:bundles": "cd ./yii2-adapter && npm run build", + "dev:bundles": "cd ./yii2-adapter && npm run dev", + "serve:bundles": "cd ./yii2-adapter && npm run serve", + "dev:cp": "cd ./packages/craftcms-cp && npm run dev", + "build:cp": "cd ./packages/craftcms-cp && npm run build", + "test:cp": "cd ./packages/craftcms-cp && npm run test", + "storybook:cp": "cd ./packages/craftcms-cp && npm run storybook", "build:all": "npm run build:bundles && npm run build:cp && npm run build" }, "workspaces": [ @@ -53,6 +53,7 @@ "dependencies": { "@craftcms/cp": "file:packages/craftcms-cp", "@inertiajs/vue3": "^2.2.7", + "@tanstack/vue-table": "^8.21.3", "@vueuse/core": "^14.0.0", "axios": "^1.13.2", "laravel-vite-plugin": "^2.0.1", diff --git a/packages/craftcms-cp/src/components/action-item/action-item.ts b/packages/craftcms-cp/src/components/action-item/action-item.ts index bf5a1868057..6c58debfeaf 100644 --- a/packages/craftcms-cp/src/components/action-item/action-item.ts +++ b/packages/craftcms-cp/src/components/action-item/action-item.ts @@ -1,8 +1,8 @@ import {html, LitElement, nothing} from 'lit'; import {property} from 'lit/decorators.js'; import styles from './action-item.styles.js'; -import {Variant, type VariantKey} from '@/types'; -import variantsStyles from '@/styles/variants.styles'; +import {Variant, type VariantKey} from '@src/types'; +import variantsStyles from '@src/styles/variants.styles'; /** * @summary Either a link or button typically used in a menu. @@ -12,7 +12,7 @@ export default class CraftActionItem extends LitElement { @property() icon: string | null = null; @property() href: string | null = null; @property({type: Boolean}) disabled: boolean = false; - @property() variant: VariantKey = Variant.Default; + @property({reflect: true}) variant: VariantKey = Variant.Default; renderBody() { return html` diff --git a/packages/craftcms-cp/src/components/action-menu/action-menu.ts b/packages/craftcms-cp/src/components/action-menu/action-menu.ts index 8db69e187a0..99f6647fd55 100644 --- a/packages/craftcms-cp/src/components/action-menu/action-menu.ts +++ b/packages/craftcms-cp/src/components/action-menu/action-menu.ts @@ -1,7 +1,7 @@ import {css, html, LitElement} from 'lit'; import {OverlayMixin, withDropdownConfig} from '@lion/ui/overlays.js'; import {queryAssignedElements} from 'lit/decorators.js'; -import type CraftActionItem from '@/components/action-item/action-item'; +import type CraftActionItem from '@src/components/action-item/action-item'; import {uuid} from '@lion/ui/core.js'; /** @@ -13,6 +13,8 @@ import {uuid} from '@lion/ui/core.js'; export default class CraftActionMenu extends OverlayMixin(LitElement) { static override styles = css` ::slotted([slot='content']) { + font-size: var(--c-text-base); + font-weight: 400; display: grid; gap: var(--c-spacing-xs); border: 1px solid var(--c-color-neutral-border-subtle); diff --git a/packages/craftcms-cp/src/components/button/button.styles.ts b/packages/craftcms-cp/src/components/button/button.styles.ts index 4208c6cbbf0..d16899f7d7d 100644 --- a/packages/craftcms-cp/src/components/button/button.styles.ts +++ b/packages/craftcms-cp/src/components/button/button.styles.ts @@ -11,7 +11,7 @@ export default css` align-items: center; border-radius: var(--c-button-radius, var(--c-radius-sm)); color: var(--c-button-fg, inherit); - padding-inline: var(--c-button-spacing-inline, var(--c-spacing-lg)); + padding-inline: var(--c-button-spacing-inline, var(--c-spacing-md)); padding-block: 0; width: auto; min-height: var(--c-button-height, var(--c-size-control-md)); @@ -46,6 +46,7 @@ export default css` padding-inline: var(--c-spacing-sm); min-width: var(--c-size-control-sm); min-height: var(--c-size-control-sm); + font-size: 0.9em; craft-icon { font-size: 0.8em; diff --git a/packages/craftcms-cp/src/components/callout/callout.stories.ts b/packages/craftcms-cp/src/components/callout/callout.stories.ts index 1e13be675ba..bde500768f6 100644 --- a/packages/craftcms-cp/src/components/callout/callout.stories.ts +++ b/packages/craftcms-cp/src/components/callout/callout.stories.ts @@ -3,7 +3,7 @@ import type {Meta, StoryObj} from '@storybook/web-components-vite'; import {html} from 'lit'; import './callout.js'; -import {Variant, Appearance} from '@/types'; +import {Appearance, Variant} from '@src/types'; const variants = Object.values(Variant); const appearances = Object.values(Appearance); diff --git a/packages/craftcms-cp/src/components/callout/callout.ts b/packages/craftcms-cp/src/components/callout/callout.ts index 578fb35a0bd..a994836c79a 100644 --- a/packages/craftcms-cp/src/components/callout/callout.ts +++ b/packages/craftcms-cp/src/components/callout/callout.ts @@ -7,8 +7,8 @@ import { type AppearanceKey, Variant, type VariantKey, -} from '@/types/index.js'; -import variantsStyles from '@/styles/variants.styles'; +} from '@src/types/index.js'; +import variantsStyles from '@src/styles/variants.styles.js'; export default class CraftCallout extends LitElement { static override styles: CSSResultGroup = [variantsStyles, styles]; diff --git a/packages/craftcms-cp/src/components/indicator/indicator.stories.ts b/packages/craftcms-cp/src/components/indicator/indicator.stories.ts index dfda3a0a0de..d1184b7ff7f 100644 --- a/packages/craftcms-cp/src/components/indicator/indicator.stories.ts +++ b/packages/craftcms-cp/src/components/indicator/indicator.stories.ts @@ -3,7 +3,7 @@ import type {Meta, StoryObj} from '@storybook/web-components-vite'; import {html} from 'lit'; import './indicator.js'; -import {Variant} from '@/types'; +import {Variant} from '@src/types'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories const meta = { diff --git a/packages/craftcms-cp/src/components/indicator/indicator.ts b/packages/craftcms-cp/src/components/indicator/indicator.ts index 99f9e240c16..7522076f8eb 100644 --- a/packages/craftcms-cp/src/components/indicator/indicator.ts +++ b/packages/craftcms-cp/src/components/indicator/indicator.ts @@ -1,9 +1,8 @@ -import {LitElement, html, css} from 'lit'; +import {css, html, LitElement} from 'lit'; import {property} from 'lit/decorators.js'; -import {Variant, type VariantKey} from '@/types'; +import {Variant, type VariantKey} from '@src/types'; import {classMap} from 'lit/directives/class-map.js'; -import variantsStyles from '@/styles/variants.styles'; -import CraftCombobox from '@/components/combobox/combobox'; +import variantsStyles from '@src/styles/variants.styles'; export default class CraftIndicator extends LitElement { static override styles = [ diff --git a/packages/craftcms-cp/src/components/input-file/input-file.ts b/packages/craftcms-cp/src/components/input-file/input-file.ts index aa02d954729..92cf726f559 100644 --- a/packages/craftcms-cp/src/components/input-file/input-file.ts +++ b/packages/craftcms-cp/src/components/input-file/input-file.ts @@ -1,5 +1,5 @@ import {LionInputFile} from '@lion/ui/input-file.js'; -import {inputStyles} from '@/styles/form.styles'; +import {inputStyles} from '@src/styles/form.styles'; import styles from './input-file.styles.js'; import CraftSelectedFileList from './selected-file-list.js'; import {html} from 'lit'; diff --git a/packages/craftcms-cp/src/components/input/input.ts b/packages/craftcms-cp/src/components/input/input.ts index 8cf77f50126..e66fccfadf8 100644 --- a/packages/craftcms-cp/src/components/input/input.ts +++ b/packages/craftcms-cp/src/components/input/input.ts @@ -1,5 +1,5 @@ import {LionInput} from '@lion/ui/input.js'; -import {inputStyles} from '@/styles/form.styles'; +import {inputStyles} from '@src/styles/form.styles'; import styles from './input.styles.js'; import {property} from 'lit/decorators.js'; diff --git a/packages/craftcms-cp/src/components/nav-item/nav-item.styles.ts b/packages/craftcms-cp/src/components/nav-item/nav-item.styles.ts index 697b402f287..79997ed887b 100644 --- a/packages/craftcms-cp/src/components/nav-item/nav-item.styles.ts +++ b/packages/craftcms-cp/src/components/nav-item/nav-item.styles.ts @@ -4,16 +4,21 @@ export default css` .nav-item { display: grid; gap: var(--c-spacing-md); - grid-template-columns: calc(24rem / 16) 1fr auto; + grid-template-columns: 1fr auto; align-items: center; text-decoration: none; color: inherit; - padding-inline: var(--c-spacing-sm); + padding-inline: var(--c-spacing-md); padding-block: var(--c-spacing-sm); border-radius: var(--c-radius-md); position: relative; } + .nav-item--prefixed { + padding-inline: var(--c-spacing-sm); + grid-template-columns: calc(24rem / 16) 1fr auto; + } + :host([active]) .nav-item { &:before { content: ''; diff --git a/packages/craftcms-cp/src/components/nav-item/nav-item.ts b/packages/craftcms-cp/src/components/nav-item/nav-item.ts index ee6e37a3794..31d2df20e2e 100644 --- a/packages/craftcms-cp/src/components/nav-item/nav-item.ts +++ b/packages/craftcms-cp/src/components/nav-item/nav-item.ts @@ -1,7 +1,8 @@ -import {html, LitElement, css, nothing} from 'lit'; +import {html, LitElement, nothing} from 'lit'; import {styleMap} from 'lit/directives/style-map.js'; import {property, state} from 'lit/decorators.js'; import styles from './nav-item.styles'; +import {classMap} from 'lit/directives/class-map.js'; /** * @@ -65,44 +66,7 @@ export default class CraftNavItem extends LitElement { href="${this.url}" aria-current="${this.active ? 'page' : false}" > - - -
+ ${this.renderPrefix()} ${this.renderSuffix(hasSubnav)}yes/no/true/false/on/off/0/1"})},null,8,xe),e("div",Ve,[c.value.live?(s(),r("ul",_e,[e("li",null,f(c.value.live),1)])):y("",!0)])],40,be),z(e("craft-input",{label:a(m)("Retry Duration"),id:"retry-duration",name:"retryDuration","onUpdate:modelValue":o[1]||(o[1]=d=>a(u).retryDuration=d),"has-feedback-for":c.value?.retryDuration?"error":"",inputmode:"numeric",size:"4",disabled:t.readOnly},[e("div",{slot:"help-text",innerHTML:a(m)("The number of seconds that the Retry-After HTTP header should be set to for 503 responses when the system is offline.")},null,8,Le),c.value?.retryDuration?(s(),r("ul",Te,[e("li",null,f(c.value.retryDuration),1)])):y("",!0)],8,Se),[[C,a(u).retryDuration]]),e("craft-combobox",{label:a(m)("Time Zone"),id:"time-zone",name:"timeZone",".modelValue":a(u).timeZone,onModelValueChanged:n,"has-feedback-for":c.value?.timeZone?"error":"",disabled:t.readOnly,"show-all-on-empty":""},[(s(!0),r(v,null,k(t.timezoneOptions,d=>(s(),r("craft-option",{key:d.value,".choiceValue":d.value},f(d.label)+f(d.data?.hint?` — ${d.data.hint}`:""),41,Ce))),128)),o[10]||(o[10]=e("craft-callout",{slot:"after",variant:"info",appearance:"plain",class:"p-0",icon:"lightbulb"},[w(" This can be set to an environment variable with a value of a "),e("a",{href:"https://www.php.net/manual/en/timezones.php",rel:"noopener",target:"_blank"},"supported time zone"),w(". ")],-1)),c.value?.timeZone?(s(),r("ul",Oe,[e("li",null,f(c.value.timeZone),1)])):y("",!0)],40,ze)]),a(b).edition.value>=a(H).Pro?(s(),r(v,{key:1},[o[11]||(o[11]=e("hr",null,null,-1)),e("div",$e,[V(O,{label:a(m)("Site Icon"),name:"siteIcon",modelValue:a(u).siteIcon,"onUpdate:modelValue":o[2]||(o[2]=d=>a(u).siteIcon=d),"help-text":a(m)("Square SVG file recommended. The logo will be displayed at {size} by {size}.",{size:"32px"}),"thumbnail-size":32,disabled:t.readOnly,error:a(u).errors.siteIcon},null,8,["label","modelValue","help-text","disabled","error"]),V(O,{label:a(m)("Login Page Logo"),modelValue:a(u).siteLogo,"onUpdate:modelValue":o[3]||(o[3]=d=>a(u).siteLogo=d),name:"siteLogo","help-text":a(m)("SVG file recommended. The logo will be displayed at {size} wide.",{size:"288px"}),disabled:t.readOnly,"thumbnail-size":288,error:a(u).errors.siteLogo},null,8,["label","modelValue","help-text","disabled","error"])])],64)):y("",!0)])]),_:1},8,["title"])],32))}}),Ue=L(De,[["__scopeId","data-v-56327788"]]);export{Ue as default};
+import{c as O,o,w as _,A as F,T as M,d as D,C as U,D as B,p as x,E,e as n,G as N,b as f,a as e,t as u,H as Z,B as V,I as z,u as t,F as h,r as g,f as y,J as C,K as $}from"./cp2.js";import{_ as L,u as P,i as d}from"./_plugin-vue_export-helper.js";import{u as R,_ as A,A as G}from"./CalloutReadOnly.vue_vue_type_script_setup_true_lang.js";import{q as H}from"./index.js";import"./legacy.js";const v=a=>({url:v.url(a),method:"post"});v.definition={methods:["post"],url:"/admin/settings/general"};v.url=a=>v.definition.url+H(a);v.post=a=>({url:v.url(a),method:"post"});const q={Solo:0,Team:1,Pro:2,Enterprise:3},K={};function J(a,c){return o(),O(M,{name:"fade"},{default:_(()=>[F(a.$slots,"default",{},void 0,!0)]),_:3})}const j=L(K,[["render",J],["__scopeId","data-v-623c0700"]]),Q=["label","name","button-label","help-text","disabled","multiple",".uploadResponse","has-feedback-for"],W={key:0,class:"error-list",slot:"feedback"},X=D({__name:"FileUpload",props:U({label:{},name:{},buttonLabel:{default:"Select file"},helpText:{},thumbnailSize:{default:120},disabled:{type:Boolean,default:!1},multiple:{type:Boolean,default:!1},error:{default:null}},{modelValue:{},modelModifiers:{}}),emits:["update:modelValue"],setup(a){B(b=>({c33cc0a6:m.value}));const c=E(a,"modelValue"),p=a,m=x(()=>isNaN(Number(p.thumbnailSize))?p.thumbnailSize:`calc(${p.thumbnailSize}rem / 16)`);function S(b){c.value=p.multiple?b.detail?.newFiles:b.detail?.newFiles?.[0]||null}function r(b){c.value=null}const k=x(()=>c.value?(Array.isArray(c.value)?c.value:[c.value]).map(i=>({name:i.name,status:"SUCCESS",downloadUrl:i.url,errorMessage:"",id:i.name})):[]);return(b,i)=>(o(),n("craft-input-file",{label:a.label,name:a.name,"button-label":a.buttonLabel,"help-text":a.helpText,disabled:a.disabled,multiple:a.multiple,".uploadResponse":k.value,onFileRemoved:r,onFileListChanged:S,"has-feedback-for":a.error?"error":"",style:N({"--thumbnail-size":m.value})},[a.error?(o(),n("ul",W,[e("li",null,u(a.error),1)])):f("",!0)],44,Q))}}),I=L(X,[["__scopeId","data-v-e8396b7f"]]),Y={key:0,class:"flex gap-1 items-center text-sm"},ee={key:1,class:"tw:flex tw:gap-1 tw:items-center tw:text-sm"},te={key:0},ae=["loading"],le={slot:"content"},oe={class:"bg-white border border-border-subtle rounded-sm shadow-sm"},ne={class:"grid gap-3 p-5"},se={key:0,variant:"danger",icon:"exclamation-triangle"},ie={slot:"title",class:"tw:font-bold"},re=["label","has-feedback-for","disabled"],de=[".choiceValue",".hint"],ue={slot:"after"},ce={variant:"info",appearance:"plain",class:"p-0",icon:"lightbulb"},me={href:"https://craftcms.com/docs/5.x/configure.html#control-panel-settings"},fe={slot:"feedback"},be={key:0,class:"error-list"},he=["label",".modelValue","has-feedback-for","disabled"],pe={class:"tw:flex tw:items-center tw:gap-1"},ve={class:"tw:flex tw:items-center tw:gap-1"},ye=[".choiceValue"],ge={class:"tw:flex tw:items-center tw:gap-1"},ke=["variant"],we={class:"tw:font-mono"},Ve=["innerHTML"],_e={slot:"feedback"},xe={key:0,class:"error-list"},Se=["label","has-feedback-for","disabled"],Le=["innerHTML"],Te={key:0,class:"error-list",slot:"feedback"},ze=["label",".modelValue","has-feedback-for","disabled"],Ce=[".choiceValue"],Ie={key:0,class:"error-list",slot:"feedback"},Oe={class:"p-4 grid gap-3"},De=D({__name:"SettingsGeneralPage",props:{readOnly:{type:Boolean},system:{},nameSuggestions:{},timezoneOptions:{},systemStatusOptions:{},siteIcon:{},siteLogo:{},saveUrl:{},flash:{},errors:{}},setup(a){const c=a,p=x(()=>c.flash),m=x(()=>c.errors),{app:S}=R(),r=Z({name:c.system.name,live:c.system.live,retryDuration:c.system.retryDuration,timeZone:c.system.timeZone,siteIcon:c.siteIcon,siteLogo:c.siteLogo});function k(i){const l=i.target;l&&(r[l.name]=l.modelValue)}P("keydown",i=>{(i.metaKey||i.ctrlKey)&&i.key==="s"&&(i.preventDefault(),b())});function b(){r.transform(i=>(i.siteIcon!==null&&!(i.siteIcon instanceof File)&&delete i.siteIcon,i.siteLogo!==null&&!(i.siteLogo instanceof File)&&delete i.siteLogo,i)).clearErrors().submit(v())}return(i,l)=>(o(),n("form",{onSubmit:$(b,["prevent"])},[V(G,{title:t(d)("General Settings")},{actions:_(()=>[V(j,null,{default:_(()=>[t(r).recentlySuccessful&&p.value?.success?(o(),n("div",Y,[l[4]||(l[4]=e("craft-icon",{name:"circle-check",style:{color:"var(--c-color-success-bg-emphasis)"}},null,-1)),y(" "+u(p.value.success),1)])):f("",!0),t(r).hasErrors?(o(),n("div",ee,[l[5]||(l[5]=e("craft-icon",{name:"exclamation-triangle",style:{color:"var(--c-color-danger-bg-emphasis)"}},null,-1)),y(" "+u(t(d)("Could not save settings")),1)])):f("",!0)]),_:1}),a.readOnly?f("",!0):(o(),n("craft-button-group",te,[e("craft-button",{type:"submit",variant:"primary",loading:t(r).processing},u(t(d)("Save")),9,ae),e("craft-action-menu",null,[l[7]||(l[7]=e("craft-button",{slot:"invoker",variant:"primary",type:"button",icon:""},[e("craft-icon",{name:"chevron-down"})],-1)),e("div",le,[e("craft-action-item",{onClick:b},[y(u(t(d)("Save and continue editing"))+" ",1),l[6]||(l[6]=e("craft-shortcut",{slot:"suffix",class:"ml-2"},"S",-1))])])])]))]),default:_(()=>[e("div",oe,[a.readOnly?(o(),O(A,{key:0})):f("",!0),e("div",ne,[t(r).hasErrors?(o(),n("craft-callout",se,[e("div",ie,u(t(d)("Could not save settings")),1),e("ul",null,[(o(!0),n(h,null,g(m.value,(s,T)=>(o(),n("li",null,u(s),1))),256))])])):f("",!0),z(e("craft-combobox",{label:t(d)("System Name"),id:"name",name:"name","onUpdate:modelValue":l[0]||(l[0]=s=>t(r).name=s),"has-feedback-for":m.value?.name?"error":"",disabled:a.readOnly,"require-option-match":!1,"show-all-on-empty":""},[(o(!0),n(h,null,g(a.nameSuggestions,(s,T)=>(o(),n(h,{key:T},[(o(!0),n(h,null,g(s.data,w=>(o(),n("craft-option",{key:w.name,".choiceValue":w.name,".hint":w.hint},u(w.name),41,de))),128))],64))),128)),e("div",ue,[e("craft-callout",ce,[y(u(t(d)("This can begin with an environment variable."))+" ",1),e("a",me,u(t(d)("Learn more")),1)])]),e("div",fe,[m.value?.name?(o(),n("ul",be,[e("li",null,u(m.value.name),1)])):f("",!0)])],8,re),[[C,t(r).name]]),e("craft-combobox",{label:t(d)("System Status"),id:"live",name:"live",".modelValue":a.system.live?"1":"0","has-feedback-for":m.value?.live?"error":"",onModelValueChanged:k,disabled:a.readOnly,"show-all-on-empty":""},[e("craft-option",{".choiceValue":"1"},[e("div",pe,[l[8]||(l[8]=e("craft-indicator",{variant:"success"},null,-1)),e("span",null,u(t(d)("Online")),1)])],32),e("craft-option",{".choiceValue":"0"},[e("div",ve,[l[9]||(l[9]=e("craft-indicator",{variant:"danger"},null,-1)),e("span",null,u(t(d)("Offline")),1)])],32),(o(!0),n(h,null,g(a.systemStatusOptions,s=>(o(),n(h,{key:s.label},[s.optgroup?(o(),n(h,{key:0},[],64)):(o(),n("craft-option",{key:1,".choiceValue":s.value},[e("div",ge,[e("craft-indicator",{variant:s.value?"success":"error"},null,8,ke),e("span",we,u(s.label),1)])],40,ye))],64))),128)),e("craft-callout",{slot:"after",variant:"info",appearance:"plain",class:"p-0",icon:"lightbulb",innerHTML:t(d)("This can be set to an environment variable with a boolean value ({examples})",{examples:"yes/no/true/false/on/off/0/1"})},null,8,Ve),e("div",_e,[m.value.live?(o(),n("ul",xe,[e("li",null,u(m.value.live),1)])):f("",!0)])],40,he),z(e("craft-input",{label:t(d)("Retry Duration"),id:"retry-duration",name:"retryDuration","onUpdate:modelValue":l[1]||(l[1]=s=>t(r).retryDuration=s),"has-feedback-for":m.value?.retryDuration?"error":"",inputmode:"numeric",size:"4",disabled:a.readOnly},[e("div",{slot:"help-text",innerHTML:t(d)("The number of seconds that the Retry-After HTTP header should be set to for 503 responses when the system is offline.")},null,8,Le),m.value?.retryDuration?(o(),n("ul",Te,[e("li",null,u(m.value.retryDuration),1)])):f("",!0)],8,Se),[[C,t(r).retryDuration]]),e("craft-combobox",{label:t(d)("Time Zone"),id:"time-zone",name:"timeZone",".modelValue":t(r).timeZone,onModelValueChanged:k,"has-feedback-for":m.value?.timeZone?"error":"",disabled:a.readOnly,"show-all-on-empty":""},[(o(!0),n(h,null,g(a.timezoneOptions,s=>(o(),n("craft-option",{key:s.value,".choiceValue":s.value},u(s.label)+u(s.data?.hint?` — ${s.data.hint}`:""),41,Ce))),128)),l[10]||(l[10]=e("craft-callout",{slot:"after",variant:"info",appearance:"plain",class:"p-0",icon:"lightbulb"},[y(" This can be set to an environment variable with a value of a "),e("a",{href:"https://www.php.net/manual/en/timezones.php",rel:"noopener",target:"_blank"},"supported time zone"),y(". ")],-1)),m.value?.timeZone?(o(),n("ul",Ie,[e("li",null,u(m.value.timeZone),1)])):f("",!0)],40,ze)]),t(S).edition.value>=t(q).Pro?(o(),n(h,{key:1},[l[11]||(l[11]=e("hr",null,null,-1)),e("div",Oe,[V(I,{label:t(d)("Site Icon"),name:"siteIcon",modelValue:t(r).siteIcon,"onUpdate:modelValue":l[2]||(l[2]=s=>t(r).siteIcon=s),"help-text":t(d)("Square SVG file recommended. The logo will be displayed at {size} by {size}.",{size:"32px"}),"thumbnail-size":32,disabled:a.readOnly,error:t(r).errors.siteIcon},null,8,["label","modelValue","help-text","disabled","error"]),V(I,{label:t(d)("Login Page Logo"),modelValue:t(r).siteLogo,"onUpdate:modelValue":l[3]||(l[3]=s=>t(r).siteLogo=s),name:"siteLogo","help-text":t(d)("SVG file recommended. The logo will be displayed at {size} wide.",{size:"288px"}),disabled:a.readOnly,"thumbnail-size":288,error:t(r).errors.siteLogo},null,8,["label","modelValue","help-text","disabled","error"])])],64)):f("",!0)])]),_:1},8,["title"])],32))}}),Ne=L(De,[["__scopeId","data-v-56327788"]]);export{Ne as default};
diff --git a/resources/build/SettingsIndexPage.js b/resources/build/SettingsIndexPage.js
index 43bfc39ea9c..299e403732a 100644
--- a/resources/build/SettingsIndexPage.js
+++ b/resources/build/SettingsIndexPage.js
@@ -1 +1 @@
-import{d as m,c as l,o as t,w as p,a as e,b as f,e as a,F as c,r,t as d,f as y,u as _}from"./cp2.js";import"./legacy.js";import{_ as b,A as v}from"./CalloutReadOnly.vue_vue_type_script_setup_true_lang.js";import{t as g,_ as x}from"./_plugin-vue_export-helper.js";const $={class:"py-3"},k={class:"grid gap-6"},B=["id"],S=["aria-labelledby"],C={class:"settings-grid"},I=["href"],N={class:"settings-content"},V={class:"settings-icon"},w=["name","label"],A=m({__name:"SettingsIndexPage",props:{readOnly:{type:Boolean},settings:{}},setup(n){return(F,L)=>(t(),l(v,{title:_(g)("Settings")},{default:p(()=>[e("div",$,[n.readOnly?(t(),l(b,{key:0})):f("",!0),e("div",k,[(t(!0),a(c,null,r(n.settings,(u,o,i)=>(t(),a("div",{key:o},[e("h2",{id:`category-heading-${i}`,class:"mb-2 text-lg leading-tight"},d(o),9,B),e("nav",{"aria-labelledby":`category-heading-${i}`},[e("ul",C,[(t(!0),a(c,null,r(u,(s,h)=>(t(),a("li",null,[e("a",{href:s.url||`settings/${h}`,class:"settings-item"},[e("div",N,[e("div",V,[e("craft-icon",{name:s.icon,style:{"font-size":"calc(40rem / 16)"},label:`${s.label} - ${_(g)("Settings")}`},null,8,w)]),y(" "+d(s.label),1)])],8,I)]))),256))])],8,S)]))),128))])])]),_:1},8,["title"]))}}),E=x(A,[["__scopeId","data-v-e6c2dce9"]]);export{E as default};
+import{d as m,c as l,o as t,w as p,a as e,b as f,e as a,F as c,r,t as d,f as y,u as _}from"./cp2.js";import"./legacy.js";import{_ as b,A as v}from"./CalloutReadOnly.vue_vue_type_script_setup_true_lang.js";import{i as g,_ as x}from"./_plugin-vue_export-helper.js";const $={class:"py-3"},k={class:"grid gap-6"},B=["id"],S=["aria-labelledby"],C={class:"settings-grid"},I=["href"],N={class:"settings-content"},V={class:"settings-icon"},w=["name","label"],A=m({__name:"SettingsIndexPage",props:{readOnly:{type:Boolean},settings:{}},setup(n){return(F,L)=>(t(),l(v,{title:_(g)("Settings")},{default:p(()=>[e("div",$,[n.readOnly?(t(),l(b,{key:0})):f("",!0),e("div",k,[(t(!0),a(c,null,r(n.settings,(u,i,o)=>(t(),a("div",{key:i},[e("h2",{id:`category-heading-${o}`,class:"mb-2 text-lg leading-tight"},d(i),9,B),e("nav",{"aria-labelledby":`category-heading-${o}`},[e("ul",C,[(t(!0),a(c,null,r(u,(s,h)=>(t(),a("li",null,[e("a",{href:s.url||`settings/${h}`,class:"settings-item"},[e("div",N,[e("div",V,[e("craft-icon",{name:s.icon,style:{"font-size":"calc(40rem / 16)"},label:`${s.label} - ${_(g)("Settings")}`},null,8,w)]),y(" "+d(s.label),1)])],8,I)]))),256))])],8,S)]))),128))])])]),_:1},8,["title"]))}}),E=x(A,[["__scopeId","data-v-e6c2dce9"]]);export{E as default};
diff --git a/resources/build/SettingsSitesIndex.js b/resources/build/SettingsSitesIndex.js
new file mode 100644
index 00000000000..772cd5c0366
--- /dev/null
+++ b/resources/build/SettingsSitesIndex.js
@@ -0,0 +1,4 @@
+import{d as W,L as Ne,s as je,g as Ue,q as ge,m as Xe,M as I,u as w,e as x,o as $,a as v,F as G,r as k,G as $e,c as U,b,B as X,w as A,K as de,A as Ke,t as V,H as We,p as Je,f as q,I as Fe,J as xe,N as Ye,O as Qe}from"./cp2.js";import"./legacy.js";import{_ as Ze,A as be}from"./CalloutReadOnly.vue_vue_type_script_setup_true_lang.js";import{_ as Ie,i as _}from"./_plugin-vue_export-helper.js";import{P as et,M as tt}from"./Modal.js";import{q as De,a as nt}from"./index.js";function ot(){return{accessor:(e,o)=>typeof e=="function"?{...o,accessorFn:e}:{...o,accessorKey:e},display:e=>e,group:e=>e}}function z(e,o){return typeof e=="function"?e(o):e}function P(e,o){return t=>{o.setState(n=>({...n,[e]:z(t,n[e])}))}}function ee(e){return e instanceof Function}function rt(e){return Array.isArray(e)&&e.every(o=>typeof o=="number")}function it(e,o){const t=[],n=r=>{r.forEach(i=>{t.push(i);const l=o(i);l!=null&&l.length&&n(l)})};return n(e),t}function S(e,o,t){let n=[],r;return i=>{let l;t.key&&t.debug&&(l=Date.now());const s=e(i);if(!(s.length!==n.length||s.some((c,f)=>n[f]!==c)))return r;n=s;let d;if(t.key&&t.debug&&(d=Date.now()),r=o(...s),t==null||t.onChange==null||t.onChange(r),t.key&&t.debug&&t!=null&&t.debug()){const c=Math.round((Date.now()-l)*100)/100,f=Math.round((Date.now()-d)*100)/100,g=f/16,a=(p,m)=>{for(p=String(p);p.length|
+ |
+
|---|
|
+ |
+
{{ t('No sites exist for this group yet.') }}
+