160 lines
5.4 KiB
Vue
160 lines
5.4 KiB
Vue
<script setup>
|
|
import Multiselect from "vue-multiselect";
|
|
import { computed } from "vue";
|
|
|
|
const props = defineProps({
|
|
isCompleted: Boolean,
|
|
hasHeader: Boolean,
|
|
delimiterState: Object,
|
|
selectedTemplateOption: Object,
|
|
filteredTemplates: Array,
|
|
templateApplied: Boolean,
|
|
form: Object, // reactive object reference from parent
|
|
});
|
|
const emits = defineEmits([
|
|
"update:hasHeader",
|
|
"update:delimiterMode",
|
|
"update:delimiterCustom",
|
|
"apply-template",
|
|
"preview",
|
|
]);
|
|
|
|
function onHeaderChange(e) {
|
|
emits("update:hasHeader", e.target.value === "true");
|
|
}
|
|
function onDelimiterMode(e) {
|
|
emits("update:delimiterMode", e.target.value);
|
|
}
|
|
function onDelimiterCustom(e) {
|
|
emits("update:delimiterCustom", e.target.value);
|
|
}
|
|
|
|
// Proxy selected template object <-> form.import_template_id (which stores the id)
|
|
const selectedTemplateProxy = computed({
|
|
get() {
|
|
return props.selectedTemplateOption || null;
|
|
},
|
|
set(opt) {
|
|
props.form.import_template_id = opt ? opt.id : null;
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="space-y-4">
|
|
<div class="flex items-start justify-between gap-4">
|
|
<div class="flex-1">
|
|
<label class="block text-sm font-medium text-gray-700">Template</label>
|
|
<Multiselect
|
|
v-model="selectedTemplateProxy"
|
|
:options="filteredTemplates"
|
|
track-by="id"
|
|
label="name"
|
|
placeholder="Izberi predlogo..."
|
|
:searchable="true"
|
|
:allow-empty="true"
|
|
class="mt-1"
|
|
:custom-label="(o) => o.name"
|
|
:disabled="filteredTemplates?.length === 0"
|
|
:show-no-results="true"
|
|
:clear-on-select="false"
|
|
>
|
|
<template #option="{ option }">
|
|
<div class="flex items-center justify-between w-full">
|
|
<div class="flex items-center gap-2">
|
|
<span>{{ option.name }}</span>
|
|
<span v-if="option.source_type" class="ml-2 text-xs text-gray-500"
|
|
>({{ option.source_type }})</span
|
|
>
|
|
</div>
|
|
<span class="text-[10px] px-1.5 py-0.5 rounded bg-gray-100 text-gray-600">{{
|
|
option.client_id ? "Client" : "Global"
|
|
}}</span>
|
|
</div>
|
|
</template>
|
|
<template #singleLabel="{ option }">
|
|
<div class="flex items-center gap-2">
|
|
<span>{{ option.name }}</span>
|
|
<span v-if="option.source_type" class="ml-1 text-xs text-gray-500"
|
|
>({{ option.source_type }})</span
|
|
>
|
|
<span class="text-[10px] px-1.5 py-0.5 rounded bg-gray-100 text-gray-600">{{
|
|
option.client_id ? "Client" : "Global"
|
|
}}</span>
|
|
</div>
|
|
</template>
|
|
<template #noResult>
|
|
<div class="px-2 py-1 text-xs text-gray-500">Ni predlog.</div>
|
|
</template>
|
|
</Multiselect>
|
|
<div v-if="isCompleted" class="mt-2">
|
|
<button
|
|
type="button"
|
|
@click="$emit('preview')"
|
|
class="px-3 py-1.5 bg-indigo-600 text-white rounded text-sm hover:bg-indigo-500 w-full sm:w-auto"
|
|
>
|
|
Ogled CSV
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-if="!isCompleted" class="flex flex-col gap-3">
|
|
<div class="flex flex-col sm:flex-row gap-3">
|
|
<div class="flex-1">
|
|
<label class="block text-xs font-medium text-gray-600">Header row</label>
|
|
<select
|
|
:value="hasHeader"
|
|
@change="onHeaderChange"
|
|
class="mt-1 block w-full border rounded p-2 text-sm"
|
|
>
|
|
<option value="true">Has header</option>
|
|
<option value="false">No header (positional)</option>
|
|
</select>
|
|
</div>
|
|
<div class="flex-1">
|
|
<label class="block text-xs font-medium text-gray-600">Delimiter</label>
|
|
<select
|
|
:value="delimiterState.mode"
|
|
@change="onDelimiterMode"
|
|
class="mt-1 block w-full border rounded p-2 text-sm"
|
|
>
|
|
<option value="auto">Auto-detect</option>
|
|
<option value="comma">Comma ,</option>
|
|
<option value="semicolon">Semicolon ;</option>
|
|
<option value="tab">Tab \t</option>
|
|
<option value="pipe">Pipe |</option>
|
|
<option value="space">Space ␠</option>
|
|
<option value="custom">Custom…</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div v-if="delimiterState.mode === 'custom'" class="flex items-end gap-3">
|
|
<div class="w-40">
|
|
<label class="block text-xs font-medium text-gray-600">Custom delimiter</label>
|
|
<input
|
|
:value="delimiterState.custom"
|
|
@input="onDelimiterCustom"
|
|
maxlength="4"
|
|
placeholder=","
|
|
class="mt-1 block w-full border rounded p-2 text-sm"
|
|
/>
|
|
</div>
|
|
<p class="text-xs text-gray-500">
|
|
Template default: {{ selectedTemplateOption?.meta?.delimiter || "auto" }}
|
|
</p>
|
|
</div>
|
|
<p v-else class="text-xs text-gray-500">
|
|
Template default: {{ selectedTemplateOption?.meta?.delimiter || "auto" }}
|
|
</p>
|
|
</div>
|
|
<button
|
|
v-if="!isCompleted"
|
|
class="px-3 py-1.5 bg-emerald-600 text-white rounded text-sm"
|
|
:disabled="!form.import_template_id"
|
|
@click="$emit('apply-template')"
|
|
>
|
|
{{ templateApplied ? "Ponovno uporabi predlogo" : "Uporabi predlogo" }}
|
|
</button>
|
|
</div>
|
|
</template>
|