Teren-app/resources/js/Pages/Imports/Templates/Partials/UnassignedMappings.vue

254 lines
8.2 KiB
Vue

<script setup>
import { ref } from "vue";
import { useForm } from "@inertiajs/vue3";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/Components/ui/card";
import { Label } from "@/Components/ui/label";
import { Input } from "@/Components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/Components/ui/select";
import { Button } from "@/Components/ui/button";
import { Badge } from "@/Components/ui/badge";
const props = defineProps({
unassigned: { type: Array, default: () => [] },
templateUuid: { type: String, required: true },
entityOptions: { type: Array, default: () => [] },
fieldOptions: { type: Object, default: () => ({}) },
suggestions: { type: Object, default: () => ({}) },
});
const emit = defineEmits(["refresh"]);
const unassignedState = ref({});
function saveUnassigned(m) {
const st = unassignedState.value[m.id] || {};
if (st.entity && st.field) {
m.target_field = `${st.entity}.${st.field}`;
} else {
m.target_field = null;
}
if (st.group) {
m.options = m.options && typeof m.options === "object" ? m.options : {};
m.options.group = st.group;
}
if (st.field === "meta") {
if (st.metaKey && String(st.metaKey).trim() !== "") {
m.options = m.options && typeof m.options === "object" ? m.options : {};
m.options.key = String(st.metaKey).trim();
}
if (st.metaType && String(st.metaType).trim() !== "") {
m.options = m.options && typeof m.options === "object" ? m.options : {};
m.options.type = String(st.metaType).trim();
}
}
const payload = {
source_column: m.source_column,
target_field: m.target_field,
transform: m.transform,
apply_mode: m.apply_mode,
options: m.options || null,
position: m.position,
};
useForm(payload).put(
route("importTemplates.mappings.update", {
template: props.templateUuid,
mapping: m.id,
}),
{
preserveScroll: true,
onSuccess: () => emit("refresh"),
}
);
}
function deleteMapping(m) {
useForm({}).delete(
route("importTemplates.mappings.delete", {
template: props.templateUuid,
mapping: m.id,
}),
{
preserveScroll: true,
onSuccess: () => emit("refresh"),
}
);
}
function applySuggestion(m, suggestion) {
if (!suggestion || !suggestion.entity || !suggestion.field) return;
const state = unassignedState.value[m.id] || {};
state.entity = suggestion.entity;
state.field = suggestion.field;
unassignedState.value[m.id] = state;
saveUnassigned(m);
}
</script>
<template>
<Card v-if="unassigned && unassigned.length > 0" class="border-amber-200">
<CardHeader class="bg-amber-50">
<CardTitle class="text-amber-900">
Nedodeljene preslikave ({{ unassigned.length }})
</CardTitle>
<CardDescription class="text-amber-700">
Te preslikave nimajo dodeljene ciljne entitete in polja
</CardDescription>
</CardHeader>
<CardContent class="p-4 space-y-3">
<div v-for="m in unassigned" :key="m.id" class="p-3 bg-white border rounded-lg">
<div class="space-y-3">
<!-- Source column with suggestion -->
<div class="flex items-start justify-between">
<div>
<Label class="text-xs text-muted-foreground">Izvorno polje</Label>
<div class="font-medium">{{ m.source_column }}</div>
<div v-if="suggestions && suggestions[m.source_column]" class="mt-1">
<Button
size="sm"
variant="link"
class="h-auto p-0 text-xs text-indigo-700"
@click="applySuggestion(m, suggestions[m.source_column])"
>
Predlog: {{ suggestions[m.source_column].entity }}.{{
suggestions[m.source_column].field
}}
</Button>
</div>
</div>
</div>
<!-- Entity and Field selection -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div class="space-y-2">
<Label for="entity">Entiteta</Label>
<Select v-model="(unassignedState[m.id] ||= {}).entity">
<SelectTrigger>
<SelectValue placeholder="(izberi)" />
</SelectTrigger>
<SelectContent>
<SelectItem
v-for="opt in entityOptions"
:key="opt.key"
:value="opt.key"
>
{{ opt.label }}
</SelectItem>
</SelectContent>
</Select>
</div>
<div class="space-y-2">
<Label for="field">Polje</Label>
<Select
v-model="(unassignedState[m.id] ||= {}).field"
:disabled="!(unassignedState[m.id] || {}).entity"
>
<SelectTrigger>
<SelectValue placeholder="(izberi)" />
</SelectTrigger>
<SelectContent>
<SelectItem
v-for="f in fieldOptions[(unassignedState[m.id] || {}).entity] || []"
:key="f"
:value="f"
>
{{ f }}
</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<!-- Transform, Apply Mode, Group -->
<div class="grid grid-cols-1 sm:grid-cols-3 gap-3">
<div class="space-y-2">
<Label>Transform</Label>
<Select v-model="m.transform">
<SelectTrigger>
<SelectValue placeholder="Brez" />
</SelectTrigger>
<SelectContent>
<SelectItem value="trim">trim</SelectItem>
<SelectItem value="upper">upper</SelectItem>
<SelectItem value="lower">lower</SelectItem>
</SelectContent>
</Select>
</div>
<div class="space-y-2">
<Label>Način</Label>
<Select v-model="m.apply_mode">
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="both">both</SelectItem>
<SelectItem value="insert">insert</SelectItem>
<SelectItem value="update">update</SelectItem>
<SelectItem value="keyref">keyref</SelectItem>
</SelectContent>
</Select>
</div>
<div class="space-y-2">
<Label>Skupina</Label>
<Input
v-model="(unassignedState[m.id] ||= {}).group"
placeholder="1, 2, home, work"
/>
</div>
</div>
<!-- Meta fields if applicable -->
<div
v-if="(unassignedState[m.id] || {}).field === 'meta'"
class="grid grid-cols-1 sm:grid-cols-2 gap-3"
>
<div class="space-y-2">
<Label>Meta ključ</Label>
<Input
v-model="(unassignedState[m.id] ||= {}).metaKey"
placeholder="npr.: note, category"
/>
</div>
<div class="space-y-2">
<Label>Meta tip</Label>
<Select v-model="(unassignedState[m.id] ||= {}).metaType">
<SelectTrigger>
<SelectValue placeholder="(auto/string)" />
</SelectTrigger>
<SelectContent>
<SelectItem value="string">string</SelectItem>
<SelectItem value="number">number</SelectItem>
<SelectItem value="date">date</SelectItem>
<SelectItem value="boolean">boolean</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<!-- Actions -->
<div class="flex items-center gap-2 pt-2">
<Button size="sm" @click="saveUnassigned(m)">Shrani</Button>
<Button size="sm" variant="destructive" @click="deleteMapping(m)"
>Izbriši</Button
>
</div>
</div>
</div>
</CardContent>
</Card>
</template>