Teren-app/resources/js/Pages/Settings/Archive/Index.vue
2026-01-02 12:32:20 +01:00

257 lines
7.2 KiB
Vue

<script setup>
import AppLayout from "@/Layouts/AppLayout.vue";
import AppCard from "@/Components/app/ui/card/AppCard.vue";
import CardTitle from "@/Components/ui/card/CardTitle.vue";
import { Alert, AlertDescription, AlertTitle } from "@/Components/ui/alert";
import { useForm, router } from "@inertiajs/vue3";
import { ref } from "vue";
import { Archive } from "lucide-vue-next";
import ArchiveRuleCard from "./Partials/ArchiveRuleCard.vue";
import CreateRuleForm from "./Partials/CreateRuleForm.vue";
import EditRuleForm from "./Partials/EditRuleForm.vue";
const props = defineProps({
settings: Object,
archiveEntities: Array,
actions: Array,
segments: Array,
chainPatterns: Array,
});
const newForm = useForm({
name: "",
description: "",
enabled: true,
strategy: "immediate",
soft: true,
reactivate: false,
focus: "",
related: [],
entities: [],
action_id: null,
decision_id: null,
segment_id: null,
options: { batch_size: 200 },
});
// Editing state & form
const editingSetting = ref(null);
const originalEntityMeta = ref({ columns: ["id"] });
const editForm = useForm({
name: "",
description: "",
enabled: true,
strategy: "immediate",
soft: true,
reactivate: false,
focus: "",
related: [],
entities: [],
action_id: null,
decision_id: null,
segment_id: null,
options: { batch_size: 200 },
});
function submitCreate() {
if (!newForm.focus) {
alert("Select a focus entity.");
return;
}
if (newForm.decision_id && !newForm.action_id) {
alert("Select an action before choosing a decision.");
return;
}
newForm.entities = [
{
table: newForm.focus,
related: newForm.related,
columns: ["id"],
},
];
newForm.post(route("settings.archive.store"), {
preserveScroll: true,
onSuccess: () => {
newForm.focus = "";
newForm.related = [];
newForm.entities = [];
newForm.action_id = null;
newForm.decision_id = null;
newForm.segment_id = null;
newForm.reset();
},
});
}
function toggleEnabled(setting) {
router.put(
route("settings.archive.update", setting.id),
{
...setting,
enabled: !setting.enabled,
},
{
preserveScroll: true,
}
);
}
function startEdit(setting) {
editingSetting.value = setting;
editForm.name = setting.name || "";
editForm.description = setting.description || "";
editForm.enabled = setting.enabled;
editForm.strategy = setting.strategy || "immediate";
editForm.soft = setting.soft;
editForm.reactivate = setting.reactivate ?? false;
editForm.action_id = setting.action_id ?? null;
editForm.decision_id = setting.decision_id ?? null;
editForm.segment_id = setting.segment_id ?? null;
const first = Array.isArray(setting.entities) ? setting.entities[0] : null;
if (first) {
editForm.focus = first.table || "";
editForm.related = first.related || [];
originalEntityMeta.value = {
columns: first.columns || ["id"],
};
} else {
editForm.focus = "";
editForm.related = [];
originalEntityMeta.value = { columns: ["id"] };
}
}
function cancelEdit() {
editingSetting.value = null;
editForm.reset();
}
function submitUpdate() {
if (!editingSetting.value) return;
if (!editForm.focus) {
alert("Select a focus entity.");
return;
}
if (editForm.decision_id && !editForm.action_id) {
alert("Select an action before choosing a decision.");
return;
}
editForm.entities = [
{
table: editForm.focus,
related: editForm.related,
columns: originalEntityMeta.value.columns || ["id"],
},
];
editForm.put(route("settings.archive.update", editingSetting.value.id), {
preserveScroll: true,
onSuccess: () => {
cancelEdit();
},
});
}
function remove(setting) {
if (!confirm("Delete archive rule?")) return;
router.delete(route("settings.archive.destroy", setting.id), {
preserveScroll: true,
});
}
</script>
<template>
<AppLayout title="Archive Settings">
<template #header />
<div class="pt-12">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<Alert variant="default" class="mb-6 border-l-4 border-amber-500">
<AlertTitle class="text-sm font-medium text-amber-800">
Archive rule conditions are temporarily inactive
</AlertTitle>
<AlertDescription class="text-xs text-amber-800 space-y-2 mt-2">
<p>
All enabled rules apply to the focus entity and its selected related tables
without date/other filters. Stored condition JSON is preserved for future
reactivation.
</p>
<p class="font-medium">The "Run Now" action is currently disabled.</p>
<div class="mt-3 bg-white/60 rounded p-3 border border-amber-200">
<p class="font-semibold mb-1 text-amber-900">Chain Path Help</p>
<p class="mb-1">Supported chained related tables (dot notation):</p>
<ul class="list-disc ml-4 space-y-0.5">
<li v-for="cp in chainPatterns" :key="cp">
<code class="px-1 bg-amber-100 rounded text-xs">{{ cp }}</code>
</li>
</ul>
<p class="mt-1 italic">Only these chains are processed; others are ignored.</p>
</div>
</AlertDescription>
</Alert>
<div class="grid gap-6 md:grid-cols-3">
<div class="md:col-span-2 space-y-4">
<AppCard
title=""
padding="none"
class="p-0! gap-0"
header-class="py-3! px-4 gap-0 text-muted-foreground"
>
<template #header>
<div class="flex items-center gap-2">
<Archive :size="18" />
<CardTitle class="uppercase">Archive Rules</CardTitle>
</div>
</template>
<div class="p-4 space-y-4">
<ArchiveRuleCard
v-for="rule in settings.data"
:key="rule.id"
:rule="rule"
@edit="startEdit"
@toggle-enabled="toggleEnabled"
@delete="remove"
/>
<div
v-if="!settings.data.length"
class="text-sm text-muted-foreground text-center py-8"
>
No archive rules defined yet.
</div>
</div>
</AppCard>
</div>
<div>
<CreateRuleForm
v-if="!editingSetting"
:form="newForm"
:archive-entities="archiveEntities"
:actions="actions"
:segments="segments"
@submit="submitCreate"
/>
<EditRuleForm
v-else
:form="editForm"
:setting="editingSetting"
:archive-entities="archiveEntities"
:actions="actions"
:segments="segments"
@submit="submitUpdate"
@cancel="cancelEdit"
/>
</div>
</div>
</div>
</div>
</AppLayout>
</template>
<style scoped>
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
monospace;
}
</style>