fix: make project template inheritance granular and safe
This commit is contained in:
@@ -50,10 +50,6 @@ const switchTemplateForm = useForm({
|
||||
)?.id,
|
||||
});
|
||||
|
||||
const resetTemplateForm = useForm({
|
||||
confirmation_key: '',
|
||||
});
|
||||
|
||||
const deleteForm = useForm({
|
||||
confirmation_key: '',
|
||||
});
|
||||
@@ -76,10 +72,6 @@ const canSwitchTemplate = computed(
|
||||
switchTemplateForm.source_template_id !== undefined,
|
||||
);
|
||||
|
||||
const isResetConfirmationValid = computed(
|
||||
() => resetTemplateForm.confirmation_key === props.project.key,
|
||||
);
|
||||
|
||||
const isDeleteConfirmationValid = computed(
|
||||
() => deleteForm.confirmation_key === props.project.key,
|
||||
);
|
||||
@@ -89,19 +81,12 @@ const submitSwitchTemplate = (): void => {
|
||||
return;
|
||||
}
|
||||
|
||||
switchTemplateForm.post(ProjectController.switchTemplate.url(props.project.id), {
|
||||
preserveScroll: true,
|
||||
});
|
||||
};
|
||||
|
||||
const submitResetTemplate = (): void => {
|
||||
if (!isResetConfirmationValid.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
resetTemplateForm.post(ProjectController.resetTemplate.url(props.project.id), {
|
||||
preserveScroll: true,
|
||||
});
|
||||
switchTemplateForm.post(
|
||||
ProjectController.switchTemplate.url(props.project.id),
|
||||
{
|
||||
preserveScroll: true,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const submitDelete = (): void => {
|
||||
@@ -209,56 +194,84 @@ const submitDelete = (): void => {
|
||||
<CardHeader>
|
||||
<CardTitle>Template baseline</CardTitle>
|
||||
<CardDescription>
|
||||
Switch this project to another published template or reset it back to the currently linked template baseline. Both actions can overwrite local configuration.
|
||||
Switch this project to another published template. Use
|
||||
the inheritance panels to reset individual settings to
|
||||
the currently linked template.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent class="space-y-6">
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
<div class="border-border/70 rounded-xl border p-4">
|
||||
<p class="text-muted-foreground text-xs font-semibold uppercase tracking-[0.18em]">
|
||||
<p
|
||||
class="text-muted-foreground text-xs font-semibold uppercase tracking-[0.18em]"
|
||||
>
|
||||
Current linked template
|
||||
</p>
|
||||
<p class="text-foreground mt-2 text-sm font-semibold">
|
||||
{{ currentTemplate?.name ?? 'No linked template' }}
|
||||
<p
|
||||
class="text-foreground mt-2 text-sm font-semibold"
|
||||
>
|
||||
{{
|
||||
currentTemplate?.name ??
|
||||
'No linked template'
|
||||
}}
|
||||
</p>
|
||||
<p class="text-muted-foreground mt-2 text-sm">
|
||||
{{
|
||||
templateState?.inheritsFromTemplate
|
||||
? 'Inherited and overridden areas stay visible after switching or resetting.'
|
||||
? 'Inherited and overridden areas stay visible after switching.'
|
||||
: 'This project currently behaves like a standalone baseline.'
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="border-border/70 rounded-xl border p-4">
|
||||
<p class="text-muted-foreground text-xs font-semibold uppercase tracking-[0.18em]">
|
||||
<p
|
||||
class="text-muted-foreground text-xs font-semibold uppercase tracking-[0.18em]"
|
||||
>
|
||||
Warning
|
||||
</p>
|
||||
<p class="text-foreground mt-2 text-sm font-medium">
|
||||
Template changes can replace board workflow, ticket metadata, repositories, and notifications for copied areas.
|
||||
Switching templates can replace inherited board
|
||||
workflow, ticket metadata, repositories, and
|
||||
notifications.
|
||||
</p>
|
||||
<p class="text-muted-foreground mt-2 text-sm">
|
||||
Confirm each action with the exact project key to avoid accidental overwrites.
|
||||
Confirm each action with the exact project key
|
||||
to avoid accidental overwrites.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 xl:grid-cols-2">
|
||||
<form class="space-y-4 rounded-xl border p-4" @submit.prevent="submitSwitchTemplate">
|
||||
<div class="grid gap-6">
|
||||
<form
|
||||
class="space-y-4 rounded-xl border p-4"
|
||||
@submit.prevent="submitSwitchTemplate"
|
||||
>
|
||||
<div class="space-y-1">
|
||||
<h3 class="text-sm font-semibold">Switch to another template</h3>
|
||||
<h3 class="text-sm font-semibold">
|
||||
Switch to another template
|
||||
</h3>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
Applying a different template replaces the copied areas with that template's current baseline.
|
||||
Applying a different template replaces the
|
||||
copied areas with that template's current
|
||||
baseline.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="source_template_id">Published template</Label>
|
||||
<Label for="source_template_id"
|
||||
>Published template</Label
|
||||
>
|
||||
<select
|
||||
id="source_template_id"
|
||||
v-model="switchTemplateForm.source_template_id"
|
||||
:disabled="switchTemplateForm.processing || availableSwitchTemplates.length === 0"
|
||||
v-model="
|
||||
switchTemplateForm.source_template_id
|
||||
"
|
||||
:disabled="
|
||||
switchTemplateForm.processing ||
|
||||
availableSwitchTemplates.length === 0
|
||||
"
|
||||
class="border-input bg-background shadow-xs focus-visible:border-ring focus-visible:ring-ring/50 rounded-md border px-3 py-2 text-sm outline-none transition-[color,box-shadow] focus-visible:ring-[3px]"
|
||||
>
|
||||
<option :value="undefined" disabled>
|
||||
@@ -272,68 +285,54 @@ const submitDelete = (): void => {
|
||||
{{ template.name }}
|
||||
</option>
|
||||
</select>
|
||||
<InputError :message="switchTemplateForm.errors.source_template_id" />
|
||||
<InputError
|
||||
:message="
|
||||
switchTemplateForm.errors
|
||||
.source_template_id
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="switch_confirmation_key">Confirmation key</Label>
|
||||
<Label for="switch_confirmation_key"
|
||||
>Confirmation key</Label
|
||||
>
|
||||
<Input
|
||||
id="switch_confirmation_key"
|
||||
v-model="switchTemplateForm.confirmation_key"
|
||||
v-model="
|
||||
switchTemplateForm.confirmation_key
|
||||
"
|
||||
:disabled="switchTemplateForm.processing"
|
||||
placeholder="Type the project key exactly"
|
||||
/>
|
||||
<InputError :message="switchTemplateForm.errors.confirmation_key" />
|
||||
<InputError
|
||||
:message="
|
||||
switchTemplateForm.errors
|
||||
.confirmation_key
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div
|
||||
class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"
|
||||
>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
Existing project-specific configuration in copied areas may be replaced or removed.
|
||||
Existing project-specific configuration in
|
||||
copied areas may be replaced or removed.
|
||||
</p>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
:disabled="switchTemplateForm.processing || !canSwitchTemplate"
|
||||
:disabled="
|
||||
switchTemplateForm.processing ||
|
||||
!canSwitchTemplate
|
||||
"
|
||||
>
|
||||
Switch template
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="space-y-4 rounded-xl border p-4" @submit.prevent="submitResetTemplate">
|
||||
<div class="space-y-1">
|
||||
<h3 class="text-sm font-semibold">Reset to current template baseline</h3>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
Re-apply the currently linked template and clear local divergence inside copied areas.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="reset_confirmation_key">Confirmation key</Label>
|
||||
<Input
|
||||
id="reset_confirmation_key"
|
||||
v-model="resetTemplateForm.confirmation_key"
|
||||
:disabled="resetTemplateForm.processing || !currentTemplate"
|
||||
placeholder="Type the project key exactly"
|
||||
/>
|
||||
<InputError :message="resetTemplateForm.errors.confirmation_key" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<p class="text-muted-foreground text-sm">
|
||||
This restores the current template baseline for copied areas and rewinds project-level overrides there.
|
||||
</p>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
:disabled="resetTemplateForm.processing || !isResetConfirmationValid || !currentTemplate"
|
||||
>
|
||||
Reset to baseline
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user