-
Notifications
You must be signed in to change notification settings - Fork 694
[6.x] Inertia filesystems #18932
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/inertia-ui
Are you sure you want to change the base?
[6.x] Inertia filesystems #18932
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| <script setup lang="ts"> | ||
| import {t} from '@craftcms/cp'; | ||
| import {computed} from 'vue'; | ||
| import {usePage} from '@inertiajs/vue3'; | ||
| import type {Filesystem} from '@/pages/SettingsFilesystemsEditPage.vue'; | ||
| import VarDump from '@/components/VarDump.vue'; | ||
| import CraftSwitch from '@craftcms/cp/vue/CraftSwitch.vue'; | ||
| import CraftCombobox from '@/components/form/CraftCombobox.vue'; | ||
| import DynamicHtmlRenderer from '@/components/DynamicHtmlRenderer.vue'; | ||
|
|
||
| const hasUrls = defineModel<boolean>('hasUrls'); | ||
| const url = defineModel<string>('url'); | ||
| withDefaults( | ||
| defineProps<{ | ||
| filesystem?: Filesystem; | ||
| }>(), | ||
| { | ||
| filesystem: { | ||
| errors: () => [], | ||
| name: null, | ||
| handle: null, | ||
| oldHandle: null, | ||
| hasUrls: false, | ||
| url: null, | ||
| uid: null, | ||
| rootUrl: null, | ||
| id: null, | ||
| dateCreated: null, | ||
| dateUpdated: null, | ||
| settingsHtml: null, | ||
| rootPath: null, | ||
| path: null, | ||
| }, | ||
| } | ||
| ); | ||
|
|
||
| const page = usePage<{ | ||
| readOnly: boolean; | ||
| baseUrlSuggestions?: Array<any>; | ||
| }>(); | ||
| </script> | ||
|
|
||
| <template> | ||
| <div v-if="filesystem" :id="filesystem.type"> | ||
| <template v-if="filesystem.showHasUrlSetting"> | ||
| <CraftSwitch | ||
| :label="t('Files in this filesystem have public URLs')" | ||
| name="hasUrls" | ||
| id="has-urls" | ||
| v-model="hasUrls" | ||
| :disabled="page.props.readOnly" | ||
| /> | ||
|
|
||
| <template v-if="hasUrls && filesystem.showUrlSetting"> | ||
| <CraftCombobox | ||
| :label="t('Base URL')" | ||
| :help-text="t('The base URL to the files in this filesystem.')" | ||
| v-model="url" | ||
| :options="page.props.baseUrlSuggestions" | ||
| name="url" | ||
| :required="true" | ||
| placeholder="//example.com/path/to/folder" | ||
| data-error-key="url" | ||
| :disabled="page.props.readOnly" | ||
| ></CraftCombobox> | ||
| </template> | ||
| </template> | ||
| <DynamicHtmlRenderer :html="filesystem.settingsHtml"/> | ||
| <!--<div v-html="filesystem.settingsHtml" />--> | ||
| </div> | ||
| </template> | ||
|
|
||
| <style scoped lang="scss"></style> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| <script setup lang="ts"> | ||
| import {computed} from 'vue'; | ||
| import VarDump from '@/components/VarDump.vue'; | ||
|
|
||
| const props = defineProps<{ | ||
| filesystem?: string; | ||
| }>(); | ||
|
|
||
| const fs = computed(() => props.filesystem ? JSON.parse(props.filesystem) : null); | ||
| </script> | ||
|
|
||
| <template> | ||
| <h2>Roundabout LocalFsSettings</h2> | ||
|
|
||
| <VarDump :data="{props}" /> | ||
| </template> | ||
|
|
||
| <style scoped lang="scss"></style> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| <script setup lang="ts"> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might make sense to start putting pages in folders, for example Seb wrote a blog on how Spatie structures Inertia apps and there might be some ideas in there we could use as well. For example if there are components needed just for filesystems we could put them in |
||
| import {t, toHandle} from '@craftcms/cp'; | ||
| import AppLayout from '@/layout/AppLayout.vue'; | ||
| import VarDump from '@/components/VarDump.vue'; | ||
| import type {SelectItem, SelectOption} from '@/types'; | ||
| import Pane from '@/components/Pane.vue'; | ||
| import CraftInput from '@craftcms/cp/vue/CraftInput.vue'; | ||
| import CraftInputHandle from '@craftcms/cp/vue/CraftInputHandle.vue'; | ||
| import Select from '@/components/form/Select.vue'; | ||
| import {useForm} from '@inertiajs/vue3'; | ||
| import {useInputGenerator} from '@/composables/useInputGenerator'; | ||
| import DynamicHtmlRenderer from '@/components/DynamicHtmlRenderer.vue'; | ||
| import FilesystemSettings from '@/components/Filesystems/FilesystemSettings.vue'; | ||
|
|
||
| export type Filesystem = { | ||
| errors: any[]; | ||
| name: string | null; | ||
| handle: string | null; | ||
| oldHandle: any; | ||
| hasUrls: boolean; | ||
| url: any; | ||
| uid: any; | ||
| rootUrl: any; | ||
| id: any; | ||
| dateCreated: any; | ||
| dateUpdated: any; | ||
| settingsHtml: string; | ||
| rootPath: string; | ||
| path: any; | ||
| type: string; | ||
| showHasUrlSetting: boolean; | ||
| showUrlSetting: boolean; | ||
| }; | ||
|
|
||
| const props = defineProps<{ | ||
| oldHandle: string | null; | ||
| filesystem: Filesystem; | ||
| fsOptions: Array<SelectOption>; | ||
| fsInstances: Record<string, Filesystem>; | ||
| fsTypes: Array<string>; | ||
| readOnly: boolean; | ||
| }>(); | ||
|
|
||
| const form = useForm({ | ||
| name: props.filesystem.name ?? '', | ||
| handle: props.filesystem.handle ?? '', | ||
| type: props.filesystem.type ?? '', | ||
| hasUrls: props.filesystem.hasUrls ?? false, | ||
| url: props.filesystem.url ?? '', | ||
| }); | ||
|
|
||
| useInputGenerator( | ||
| () => form.name, | ||
| (v) => (form.handle = toHandle(v)) | ||
| ); | ||
|
|
||
| function handleSubmit() { | ||
| const form = event.target as HTMLFormElement; | ||
|
|
||
| form.transform(() => { | ||
| return { | ||
| ...(new FormData(form)), | ||
| ...form | ||
| } | ||
| }).submit(); | ||
| } | ||
|
|
||
| function getFs(fsType: string): Filesystem | null { | ||
| if (fsType === form.type) { | ||
| return props.filesystem; | ||
| } | ||
|
|
||
| return props.fsInstances[fsType] ?? null; | ||
| } | ||
| </script> | ||
|
|
||
| <template> | ||
| <AppLayout> | ||
| <Pane appearance="raised"> | ||
| <div class="grid gap-3"> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably good to have a |
||
| <CraftInput | ||
| v-model="form.name" | ||
| :label="t('Name')" | ||
| id="name" | ||
| name="name" | ||
| :autofocus="true" | ||
| :required="true" | ||
| :error="form.errors?.name" | ||
| data-error-key="name" | ||
| :disabled="readOnly" | ||
| /> | ||
|
|
||
| <CraftInputHandle | ||
| :label="t('Handle')" | ||
| id="handle" | ||
| name="handle" | ||
| v-model="form.handle" | ||
| :required="true" | ||
| :error="form.errors?.handle" | ||
| data-error-key="handle" | ||
| :disabled="readOnly" | ||
| /> | ||
|
|
||
| <hr /> | ||
|
|
||
| <template v-if="fsOptions.length"> | ||
| <Select | ||
| id="type" | ||
| name="type" | ||
| :label="t('Filesystem Type')" | ||
| :help-text="t('What type of filesystem is this?')" | ||
| :options="fsOptions" | ||
| v-model="form.type" | ||
| :disabled="readOnly" | ||
| /> | ||
| </template> | ||
|
|
||
| <template v-for="fsType in fsTypes"> | ||
| <FilesystemSettings | ||
| v-model:has-urls="form.hasUrls" | ||
| v-model:url="form.url" | ||
| :filesystem="fsInstances[fsType]" | ||
| /> | ||
| </template> | ||
| </div> | ||
| </Pane> | ||
| </AppLayout> | ||
| </template> | ||
|
|
||
| <style scoped lang="scss"></style> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,23 @@ | ||
| {% from "_includes/forms" import autosuggestField %} | ||
|
|
||
| <craft-input | ||
| label="{{ "Base Path"|t('app') }}" | ||
| :help-text="{{ "The base folder path that should be used as the root of the filesystem."|t('app') }}" | ||
| name="path" | ||
| ></craft-input> | ||
|
|
||
| {{ autosuggestField({ | ||
| label: "Base Path"|t('app'), | ||
| instructions: "The base folder path that should be used as the root of the filesystem."|t('app'), | ||
| id: 'path', | ||
| class: 'ltr', | ||
| name: 'path', | ||
| suggestEnvVars: true, | ||
| suggestAliases: true, | ||
| value: filesystem.path, | ||
| required: true, | ||
| placeholder: "/path/to/folder"|t('app'), | ||
| errors: filesystem.errors.get('path'), | ||
| data: {'error-key': 'path'}, | ||
| disabled: readOnly, | ||
| label: "Base Path"|t('app'), | ||
| instructions: "The base folder path that should be used as the root of the filesystem."|t('app'), | ||
| id: 'path', | ||
| class: 'ltr', | ||
| name: 'path', | ||
| suggestEnvVars: true, | ||
| suggestAliases: true, | ||
| value: filesystem.path, | ||
| required: true, | ||
| placeholder: "/path/to/folder"|t('app'), | ||
| errors: filesystem.errors.get('path'), | ||
| data: {'error-key': 'path'}, | ||
| disabled: readOnly, | ||
| }) }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace CraftCms\Cms\Cp; | ||
|
|
||
| class JsonResource extends \Illuminate\Http\Resources\Json\JsonResource | ||
| { | ||
| #[\Override] | ||
| public static $wrap = false; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we always have to provide this or could we fall back to what's provided in
namefor example and only need to provide this when it's different than the input name?