Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions resources/js/bootstrap/cp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import AssetIndexes from '@/components/utilities/AssetIndexes/AssetIndexes.vue';
import SystemMessages from '@/components/utilities/SystemMessages/SystemMessages.vue';
import DeprecationErrorsToolbar from '@/components/utilities/DeprecationErrors/DeprecationErrorsToolbar.vue';
import {setTranslations} from '@craftcms/cp/utilities/translate.ts.mjs';
import LocalFsSettings from '@/components/Filesystems/LocalFsSettings.vue';

let bootedCallbacks: Array<(instance: any) => void> = [];
let bootingCallbacks: Array<(instance: any) => void> = [];
Expand Down Expand Up @@ -98,6 +99,9 @@ const Cp = {
app.component('ProjectConfig', ProjectConfig);
app.component('AssetIndexes', AssetIndexes);
app.component('SystemMessages', SystemMessages);
app.component('LocalFsSettings', LocalFsSettings);

// @TODO Register plugin components
},
});

Expand Down
73 changes: 73 additions & 0 deletions resources/js/components/Filesystems/FilesystemSettings.vue
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"
Copy link
Copy Markdown
Contributor

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 name for example and only need to provide this when it's different than the input name?

:disabled="page.props.readOnly"
></CraftCombobox>
</template>
</template>
<DynamicHtmlRenderer :html="filesystem.settingsHtml"/>
<!--<div v-html="filesystem.settingsHtml" />-->
</div>
</template>

<style scoped lang="scss"></style>
18 changes: 18 additions & 0 deletions resources/js/components/Filesystems/LocalFsSettings.vue
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>
130 changes: 130 additions & 0 deletions resources/js/pages/SettingsFilesystemsEditPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<script setup lang="ts">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to start putting pages in folders, for example pages/settings/filesystems/EditFilesystemPage.vue

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 pages/settings/filesystems/components

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">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably good to have a <FormFields> wrapper that defines the spacing, just so it's consistent everywhere and if it has to change it's only in 1 file, or have <Pane> be a grid by default

<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>
32 changes: 19 additions & 13 deletions resources/templates/_components/fs/Local/settings.twig
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,
}) }}
11 changes: 11 additions & 0 deletions src/Cp/JsonResource.php
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;

Check failure on line 10 in src/Cp/JsonResource.php

View workflow job for this annotation

GitHub Actions / Code Quality / Phpstan

Static property CraftCms\Cms\Cp\JsonResource::$wrap (string|null) does not accept default value of type false.
}
2 changes: 1 addition & 1 deletion src/Entry/Resources/EntryTypeResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
namespace CraftCms\Cms\Entry\Resources;

use CraftCms\Cms\Cp\Icons;
use CraftCms\Cms\Cp\JsonResource;
use CraftCms\Cms\Entry\Data\EntryType;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

/** @mixin EntryType */
class EntryTypeResource extends JsonResource
Expand Down
14 changes: 11 additions & 3 deletions src/Filesystem/Filesystems/Local.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use CraftCms\Cms\Support\Env;
use CraftCms\Cms\Support\Facades\Security;
use CraftCms\Cms\Support\File;
use CraftCms\Cms\Support\Html;
use CraftCms\Cms\View\TemplateMode;
use Override;

Expand Down Expand Up @@ -124,10 +125,17 @@ public function getReadOnlySettingsHtml(): ?string

private function settingsHtml(bool $readOnly): string
{
return template('_components/fs/Local/settings', [
'filesystem' => $this,
return Html::tag('LocalFsSettings', attributes: [
// ':filesystem' => json_encode([
// 'name' => $this->name,
// 'handle' => $this->handle,
// ]),
'readOnly' => $readOnly,
], TemplateMode::Cp);
]);
// return template('_components/fs/Local/settings', [
// 'filesystem' => $this,
// 'readOnly' => $readOnly,
// ], TemplateMode::Cp);
}

#[Override]
Expand Down
2 changes: 1 addition & 1 deletion src/Filesystem/Resources/FsResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

namespace CraftCms\Cms\Filesystem\Resources;

use CraftCms\Cms\Cp\JsonResource;
use CraftCms\Cms\Filesystem\Filesystems\Filesystem;
use CraftCms\Cms\Filesystem\Filesystems\MissingFs;
use CraftCms\Cms\Support\Arr;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

/**
* @mixin Filesystem
Expand Down
2 changes: 1 addition & 1 deletion src/Gql/Resources/GqlTokenResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace CraftCms\Cms\Gql\Resources;

use CraftCms\Cms\Cp\JsonResource;
use CraftCms\Cms\Gql\Data\GqlToken;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

/**
* @mixin GqlToken
Expand Down
Loading
Loading