254 lines
8.2 KiB
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>
|