fix(KAN-14): preserve template inheritance and project data
This commit is contained in:
@@ -3,7 +3,6 @@ import { Link, useForm } from '@inertiajs/vue3';
|
||||
import { Layers3, LockKeyhole } from 'lucide-vue-next';
|
||||
import { computed } from 'vue';
|
||||
import FormFeedback from '@/components/FormFeedback.vue';
|
||||
import FeedbackState from '@/components/FeedbackState.vue';
|
||||
import InputError from '@/components/InputError.vue';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -12,7 +11,13 @@ import { Label } from '@/components/ui/label';
|
||||
import { useFormProtection } from '@/composables/useFormProtection';
|
||||
import { useLocalization } from '@/composables/useLocalization';
|
||||
import { useProjectTemplateAreas } from '@/composables/useProjectTemplateAreas';
|
||||
import { index, update } from '@/routes/project-templates';
|
||||
import {
|
||||
index,
|
||||
update,
|
||||
store as storeStandalone,
|
||||
} from '@/routes/project-templates';
|
||||
import TemplateConfigurationEditor from '@/components/projects/TemplateConfigurationEditor.vue';
|
||||
import { createTemplateConfiguration } from '@/lib/project-template-configuration';
|
||||
import { show } from '@/routes/projects';
|
||||
import { store } from '@/routes/projects/templates';
|
||||
import type { ProjectDuplicateCopyAreaOption } from '@/types';
|
||||
@@ -22,11 +27,18 @@ import type { ProjectTemplateModel } from '@/types/models/project-template-model
|
||||
|
||||
const props = defineProps<{
|
||||
copyAreaOptions: ProjectDuplicateCopyAreaOption[];
|
||||
project?: ProjectModel;
|
||||
project?: ProjectModel | null;
|
||||
initialConfiguration?: Record<string, unknown>;
|
||||
template?: ProjectTemplateModel;
|
||||
}>();
|
||||
const { t } = useLocalization();
|
||||
const { areaText } = useProjectTemplateAreas();
|
||||
const publishingBase = computed(() =>
|
||||
props.project?.project_template &&
|
||||
!props.project.project_template.is_published
|
||||
? props.project.project_template
|
||||
: null,
|
||||
);
|
||||
const source = computed(() => props.template?.source_project ?? props.project);
|
||||
const linkedCount = computed(() => props.template?.linked_project_count ?? 0);
|
||||
const form = useForm(
|
||||
@@ -34,14 +46,23 @@ const form = useForm(
|
||||
{
|
||||
name:
|
||||
props.template?.name ??
|
||||
t('templates.defaultName', { project: props.project?.name ?? '' }),
|
||||
(props.project
|
||||
? t('templates.defaultName', { project: props.project.name })
|
||||
: ''),
|
||||
slug:
|
||||
props.template?.slug ??
|
||||
`${props.project?.key.toLowerCase()}-template`,
|
||||
publishingBase.value?.slug ??
|
||||
(props.project
|
||||
? `${props.project.key.toLowerCase()}-template`
|
||||
: ''),
|
||||
copy_areas: props.template
|
||||
? [...props.template.copy_areas]
|
||||
: props.copyAreaOptions.map((area) => area.value),
|
||||
confirm_linked_projects_update: false,
|
||||
configuration_snapshot: createTemplateConfiguration(
|
||||
props.template?.configuration_snapshot ??
|
||||
props.initialConfiguration,
|
||||
),
|
||||
},
|
||||
);
|
||||
const protection = useFormProtection(form);
|
||||
@@ -53,13 +74,10 @@ const copyAreasError = computed(
|
||||
)?.[1],
|
||||
);
|
||||
const cancelTarget = computed(() =>
|
||||
props.template ? index() : show(props.project!.id),
|
||||
props.project ? show(props.project.id) : index(),
|
||||
);
|
||||
function submit(): void {
|
||||
if (
|
||||
!source.value ||
|
||||
(linkedCount.value > 0 && !form.confirm_linked_projects_update)
|
||||
) {
|
||||
if (linkedCount.value > 0 && !form.confirm_linked_projects_update) {
|
||||
return;
|
||||
}
|
||||
form.transform((data) =>
|
||||
@@ -67,6 +85,7 @@ function submit(): void {
|
||||
? {
|
||||
name: data.name,
|
||||
copy_areas: data.copy_areas,
|
||||
configuration_snapshot: data.configuration_snapshot,
|
||||
...(linkedCount.value > 0
|
||||
? {
|
||||
confirm_linked_projects_update:
|
||||
@@ -74,10 +93,21 @@ function submit(): void {
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
: { name: data.name, slug: data.slug, copy_areas: data.copy_areas },
|
||||
: {
|
||||
name: data.name,
|
||||
slug: data.slug,
|
||||
copy_areas: data.copy_areas,
|
||||
...(!props.project
|
||||
? { configuration_snapshot: data.configuration_snapshot }
|
||||
: {}),
|
||||
},
|
||||
);
|
||||
protection.submit(
|
||||
props.template ? update(props.template.id) : store(props.project!.id),
|
||||
props.template
|
||||
? update(props.template.id)
|
||||
: props.project
|
||||
? store(props.project.id)
|
||||
: storeStandalone(),
|
||||
{ preserveScroll: true },
|
||||
);
|
||||
}
|
||||
@@ -90,12 +120,6 @@ function submit(): void {
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
<FormFeedback :state="protection.state.value" @retry="submit" />
|
||||
<FeedbackState
|
||||
v-if="!source"
|
||||
state="error"
|
||||
:title="t('templates.missingSource')"
|
||||
:description="t('templates.missingSourceHelp')"
|
||||
/>
|
||||
<div
|
||||
class="gap-page grid min-w-0 items-start lg:grid-cols-[minmax(0,1fr)_18rem]"
|
||||
>
|
||||
@@ -115,7 +139,7 @@ function submit(): void {
|
||||
name="name"
|
||||
required
|
||||
maxlength="255"
|
||||
:disabled="form.processing || !source"
|
||||
:disabled="form.processing"
|
||||
:placeholder="t('templates.namePlaceholder')"
|
||||
:invalid="!!form.errors.name"
|
||||
aria-describedby="name-error"
|
||||
@@ -139,7 +163,11 @@ function submit(): void {
|
||||
name="slug"
|
||||
required
|
||||
maxlength="255"
|
||||
:disabled="!!template || form.processing || !source"
|
||||
:disabled="
|
||||
!!template ||
|
||||
!!publishingBase ||
|
||||
form.processing
|
||||
"
|
||||
:placeholder="t('templates.slugPlaceholder')"
|
||||
:invalid="!!form.errors.slug"
|
||||
aria-describedby="slug-help slug-error"
|
||||
@@ -152,7 +180,7 @@ function submit(): void {
|
||||
>
|
||||
{{
|
||||
t(
|
||||
template
|
||||
template || publishingBase
|
||||
? 'templates.slugLocked'
|
||||
: 'templates.slugHelp',
|
||||
)
|
||||
@@ -166,7 +194,7 @@ function submit(): void {
|
||||
</section>
|
||||
<fieldset
|
||||
class="bg-card min-w-0 rounded-md border p-5"
|
||||
:disabled="form.processing || !source"
|
||||
:disabled="form.processing"
|
||||
aria-describedby="areas-help copy-areas-error"
|
||||
>
|
||||
<legend class="text-title px-1">
|
||||
@@ -231,6 +259,14 @@ function submit(): void {
|
||||
:message="copyAreasError"
|
||||
/>
|
||||
</fieldset>
|
||||
<TemplateConfigurationEditor
|
||||
v-if="template || !project"
|
||||
v-model="form.configuration_snapshot"
|
||||
:areas="form.copy_areas"
|
||||
:options="copyAreaOptions"
|
||||
:errors="form.errors"
|
||||
:disabled="form.processing"
|
||||
/>
|
||||
</div>
|
||||
<aside
|
||||
class="bg-card gap-column grid min-w-0 rounded-md border p-5"
|
||||
@@ -310,7 +346,7 @@ function submit(): void {
|
||||
id="confirm-linked"
|
||||
v-model="form.confirm_linked_projects_update"
|
||||
type="checkbox"
|
||||
:disabled="form.processing || !source"
|
||||
:disabled="form.processing"
|
||||
:aria-invalid="!!form.errors.confirm_linked_projects_update"
|
||||
aria-describedby="linked-help linked-error"
|
||||
class="accent-primary mt-0.5 size-5 shrink-0"
|
||||
@@ -335,8 +371,7 @@ function submit(): void {
|
||||
:loading="form.processing"
|
||||
:loading-label="t('forms.saving')"
|
||||
:disabled="
|
||||
!source ||
|
||||
(linkedCount > 0 && !form.confirm_linked_projects_update)
|
||||
linkedCount > 0 && !form.confirm_linked_projects_update
|
||||
"
|
||||
>{{
|
||||
t(template ? 'templates.saveChanges' : 'templates.saveNew')
|
||||
|
||||
Reference in New Issue
Block a user