175 lines
6.5 KiB
Vue
175 lines
6.5 KiB
Vue
<script setup lang="ts">
|
|
import { Head, Link, useForm } from '@inertiajs/vue3';
|
|
import { computed } from 'vue';
|
|
import Heading from '@/components/Heading.vue';
|
|
import InputError from '@/components/InputError.vue';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '@/components/ui/card';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import AppLayout from '@/layouts/AppLayout.vue';
|
|
import {
|
|
index as projectsIndex,
|
|
show as projectShow,
|
|
} from '@/routes/projects/index';
|
|
import {
|
|
create as projectTemplateCreate,
|
|
store as projectTemplateStore,
|
|
} from '@/routes/projects/templates';
|
|
import type { BreadcrumbItem, ProjectTemplatesCreatePageProps } from '@/types';
|
|
|
|
const props = defineProps<ProjectTemplatesCreatePageProps>();
|
|
|
|
const breadcrumbs: BreadcrumbItem[] = [
|
|
{
|
|
title: 'Projects',
|
|
href: projectsIndex(),
|
|
},
|
|
{
|
|
title: props.project.name,
|
|
href: projectShow(props.project.id),
|
|
},
|
|
{
|
|
title: 'Save as new template',
|
|
href: projectTemplateCreate(props.project.id),
|
|
},
|
|
];
|
|
|
|
const form = useForm({
|
|
copy_areas: props.copyAreaOptions.map(
|
|
(copyAreaOption) => copyAreaOption.value,
|
|
),
|
|
name: `${props.project.name} template`,
|
|
slug: `${props.project.key.toLowerCase()}-template`,
|
|
});
|
|
|
|
const copyAreasError = computed(() => {
|
|
return (
|
|
form.errors.copy_areas ??
|
|
Object.entries(form.errors).find(([key]) =>
|
|
key.startsWith('copy_areas.'),
|
|
)?.[1] ??
|
|
''
|
|
);
|
|
});
|
|
|
|
const submit = (): void => {
|
|
form.post(projectTemplateStore.url(props.project.id), {
|
|
preserveScroll: true,
|
|
});
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<AppLayout :breadcrumbs="breadcrumbs">
|
|
<Head :title="`Save ${project.name} as new template`" />
|
|
|
|
<div class="mx-auto flex w-full max-w-3xl flex-1 flex-col gap-6 p-4">
|
|
<div class="space-y-3">
|
|
<Badge variant="outline" class="px-3 py-1">{{
|
|
project.key
|
|
}}</Badge>
|
|
<Heading
|
|
:title="`Save ${project.name} as new template`"
|
|
description="Capture reusable project configuration without copying operational ticket data."
|
|
/>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Template details</CardTitle>
|
|
<CardDescription>
|
|
Pick the configuration groups that should be reusable in
|
|
future projects.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<CardContent>
|
|
<form class="space-y-6" @submit.prevent="submit">
|
|
<div class="grid gap-2">
|
|
<Label for="name">Template name</Label>
|
|
<Input
|
|
id="name"
|
|
v-model="form.name"
|
|
required
|
|
placeholder="Foundation template"
|
|
/>
|
|
<InputError :message="form.errors.name" />
|
|
</div>
|
|
|
|
<div class="grid gap-2">
|
|
<Label for="slug">Template slug</Label>
|
|
<Input
|
|
id="slug"
|
|
v-model="form.slug"
|
|
required
|
|
placeholder="foundation-template"
|
|
/>
|
|
<p class="text-muted-foreground text-sm">
|
|
Slugs are normalized automatically and used to
|
|
identify reusable templates.
|
|
</p>
|
|
<InputError :message="form.errors.slug" />
|
|
</div>
|
|
|
|
<div class="grid gap-3">
|
|
<div>
|
|
<Label>Configuration groups</Label>
|
|
<p class="text-muted-foreground text-sm">
|
|
Only the selected groups will be stored in
|
|
the template.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid gap-3">
|
|
<Label
|
|
v-for="copyAreaOption in copyAreaOptions"
|
|
:key="copyAreaOption.value"
|
|
class="flex cursor-pointer items-start gap-3 rounded-xl border p-4"
|
|
>
|
|
<input
|
|
v-model="form.copy_areas"
|
|
type="checkbox"
|
|
:value="copyAreaOption.value"
|
|
class="mt-1"
|
|
/>
|
|
<div class="space-y-1">
|
|
<div class="font-medium">
|
|
{{ copyAreaOption.label }}
|
|
</div>
|
|
<p
|
|
class="text-muted-foreground text-sm"
|
|
>
|
|
{{ copyAreaOption.description }}
|
|
</p>
|
|
</div>
|
|
</Label>
|
|
</div>
|
|
<InputError :message="copyAreasError" />
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3">
|
|
<Button type="submit" :disabled="form.processing">
|
|
Save new template
|
|
</Button>
|
|
|
|
<Button as-child variant="outline">
|
|
<Link :href="projectShow(project.id)"
|
|
>Cancel</Link
|
|
>
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</AppLayout>
|
|
</template>
|