updated document
This commit is contained in:
parent
23f2011e33
commit
ec6456cf23
|
|
@ -13,11 +13,15 @@
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
class ContractDocumentGenerationController extends Controller
|
class ContractDocumentGenerationController extends Controller
|
||||||
{
|
{
|
||||||
public function __invoke(Request $request, Contract $contract): Response
|
public function __invoke(Request $request, Contract $contract): Response|RedirectResponse
|
||||||
{
|
{
|
||||||
|
// Inertia requests include the X-Inertia header and should receive redirects or Inertia responses, not JSON
|
||||||
|
$isInertia = (bool) $request->header('X-Inertia');
|
||||||
|
$wantsJson = ! $isInertia && ($request->expectsJson() || $request->wantsJson());
|
||||||
if (Gate::denies('read')) { // baseline read permission required to generate
|
if (Gate::denies('read')) { // baseline read permission required to generate
|
||||||
abort(403);
|
abort(403);
|
||||||
}
|
}
|
||||||
|
|
@ -50,11 +54,18 @@ public function __invoke(Request $request, Contract $contract): Response
|
||||||
// For custom tokens: pass overrides via request bag; service already reads request()->input('custom') if present.
|
// For custom tokens: pass overrides via request bag; service already reads request()->input('custom') if present.
|
||||||
$result = $renderer->render($template, $contract, Auth::user());
|
$result = $renderer->render($template, $contract, Auth::user());
|
||||||
} catch (\App\Services\Documents\Exceptions\UnresolvedTokensException $e) {
|
} catch (\App\Services\Documents\Exceptions\UnresolvedTokensException $e) {
|
||||||
|
if ($wantsJson) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'message' => 'Unresolved tokens detected.',
|
'message' => 'Unresolved tokens detected.',
|
||||||
'tokens' => $e->unresolved ?? [],
|
'tokens' => $e->unresolved ?? [],
|
||||||
], 422);
|
], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return back with validation-like errors so Inertia can surface them via onError
|
||||||
|
return back()->withErrors([
|
||||||
|
'document' => 'Unresolved tokens detected.',
|
||||||
|
])->with('unresolved_tokens', $e->unresolved ?? []);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
try {
|
try {
|
||||||
logger()->error('ContractDocumentGenerationController generation failed', [
|
logger()->error('ContractDocumentGenerationController generation failed', [
|
||||||
|
|
@ -66,12 +77,18 @@ public function __invoke(Request $request, Contract $contract): Response
|
||||||
} catch (\Throwable $logEx) {
|
} catch (\Throwable $logEx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($wantsJson) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'message' => 'Generation failed.',
|
'message' => 'Generation failed.',
|
||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return back()->withErrors([
|
||||||
|
'document' => 'Generation failed.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$doc = new Document;
|
$doc = new Document;
|
||||||
$doc->fill([
|
$doc->fill([
|
||||||
'uuid' => (string) Str::uuid(),
|
'uuid' => (string) Str::uuid(),
|
||||||
|
|
@ -130,6 +147,7 @@ public function __invoke(Request $request, Contract $contract): Response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($wantsJson) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => 'ok',
|
'status' => 'ok',
|
||||||
'document_uuid' => $doc->uuid,
|
'document_uuid' => $doc->uuid,
|
||||||
|
|
@ -143,4 +161,18 @@ public function __invoke(Request $request, Contract $contract): Response
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flash some lightweight info if needed by the UI; Inertia will GET the page after redirect
|
||||||
|
return back()->with([
|
||||||
|
'doc_generated' => [
|
||||||
|
'uuid' => $doc->uuid,
|
||||||
|
'path' => $doc->path,
|
||||||
|
'template' => [
|
||||||
|
'slug' => $template->slug,
|
||||||
|
'version' => $template->version,
|
||||||
|
],
|
||||||
|
'stats' => $result['stats'] ?? null,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,10 +136,6 @@ public function resolve(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If still not allowed, permit tokens explicitly scanned/stored on the template
|
|
||||||
if (! $isAllowed && $templateTokens) {
|
|
||||||
$isAllowed = in_array($token, $templateTokens, true);
|
|
||||||
}
|
|
||||||
if (! $isAllowed) {
|
if (! $isAllowed) {
|
||||||
if ($policy === 'fail') {
|
if ($policy === 'fail') {
|
||||||
throw new \RuntimeException("Nedovoljen stolpec token: $token");
|
throw new \RuntimeException("Nedovoljen stolpec token: $token");
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ const groups = computed(() => {
|
||||||
<label class="block font-medium mb-1">Nov slug</label>
|
<label class="block font-medium mb-1">Nov slug</label>
|
||||||
<input
|
<input
|
||||||
v-model="uploadForm.slug"
|
v-model="uploadForm.slug"
|
||||||
:disabled="selectedSlug"
|
:disabled="!!selectedSlug"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-bordered input-sm w-full"
|
class="input input-bordered input-sm w-full"
|
||||||
placeholder="opomin"
|
placeholder="opomin"
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ const onAddActivity = (c) => emit("add-activity", c);
|
||||||
// CaseObject dialog state
|
// CaseObject dialog state
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { router, useForm } from "@inertiajs/vue3";
|
import { router, useForm } from "@inertiajs/vue3";
|
||||||
import axios from "axios";
|
import DialogModal from "@/Components/DialogModal.vue";
|
||||||
// Document generation state/dialog
|
// Document generation state/dialog
|
||||||
const generating = ref({}); // contract_uuid => boolean
|
const generating = ref({}); // contract_uuid => boolean
|
||||||
const generatedDocs = ref({}); // contract_uuid => { uuid, path }
|
const generatedDocs = ref({}); // contract_uuid => { uuid, path }
|
||||||
|
|
@ -173,22 +173,37 @@ const personAddressSource = ref("case_person"); // for person.person_address.*
|
||||||
const clientAddress = computed(() => {
|
const clientAddress = computed(() => {
|
||||||
const addr = props.client?.person?.addresses?.[0] || null;
|
const addr = props.client?.person?.addresses?.[0] || null;
|
||||||
return addr
|
return addr
|
||||||
? { address: addr.address || "", post_code: addr.post_code || "", city: addr.city || "" }
|
? {
|
||||||
|
address: addr.address || "",
|
||||||
|
post_code: addr.post_code || "",
|
||||||
|
city: addr.city || "",
|
||||||
|
}
|
||||||
: { address: "", post_code: "", city: "" };
|
: { address: "", post_code: "", city: "" };
|
||||||
});
|
});
|
||||||
const casePersonAddress = computed(() => {
|
const casePersonAddress = computed(() => {
|
||||||
const addr = props.client_case?.person?.addresses?.[0] || null;
|
const addr = props.client_case?.person?.addresses?.[0] || null;
|
||||||
return addr
|
return addr
|
||||||
? { address: addr.address || "", post_code: addr.post_code || "", city: addr.city || "" }
|
? {
|
||||||
|
address: addr.address || "",
|
||||||
|
post_code: addr.post_code || "",
|
||||||
|
city: addr.city || "",
|
||||||
|
}
|
||||||
: { address: "", post_code: "", city: "" };
|
: { address: "", post_code: "", city: "" };
|
||||||
});
|
});
|
||||||
|
|
||||||
const customTokenList = computed(() => (templateTokens.value || []).filter((t) => t.startsWith("custom.")));
|
const customTokenList = computed(() =>
|
||||||
|
(templateTokens.value || []).filter((t) => t.startsWith("custom."))
|
||||||
|
);
|
||||||
|
|
||||||
function openGenerateDialog(c) {
|
function openGenerateDialog(c) {
|
||||||
generateFor.value = c;
|
generateFor.value = c;
|
||||||
// Prefer a template that actually has tokens; fallback to the first available
|
// Prefer a template that actually has tokens; fallback to the first available
|
||||||
const first = (props.templates || []).find(t => Array.isArray(t?.tokens) && t.tokens.length > 0) || (props.templates || [])[0] || null;
|
const first =
|
||||||
|
(props.templates || []).find(
|
||||||
|
(t) => Array.isArray(t?.tokens) && t.tokens.length > 0
|
||||||
|
) ||
|
||||||
|
(props.templates || [])[0] ||
|
||||||
|
null;
|
||||||
selectedTemplateSlug.value = first?.slug || null;
|
selectedTemplateSlug.value = first?.slug || null;
|
||||||
templateTokens.value = Array.isArray(first?.tokens) ? first.tokens : [];
|
templateTokens.value = Array.isArray(first?.tokens) ? first.tokens : [];
|
||||||
templateCustomDefaults.value = (first?.meta && first.meta.custom_defaults) || {};
|
templateCustomDefaults.value = (first?.meta && first.meta.custom_defaults) || {};
|
||||||
|
|
@ -225,8 +240,14 @@ async function submitGenerate() {
|
||||||
generating.value[c.uuid] = true;
|
generating.value[c.uuid] = true;
|
||||||
generationError.value[c.uuid] = null;
|
generationError.value[c.uuid] = null;
|
||||||
try {
|
try {
|
||||||
const clientAddr = clientAddressSource.value === "case_person" ? casePersonAddress.value : clientAddress.value;
|
const clientAddr =
|
||||||
const personAddr = personAddressSource.value === "case_person" ? casePersonAddress.value : clientAddress.value;
|
clientAddressSource.value === "case_person"
|
||||||
|
? casePersonAddress.value
|
||||||
|
: clientAddress.value;
|
||||||
|
const personAddr =
|
||||||
|
personAddressSource.value === "case_person"
|
||||||
|
? casePersonAddress.value
|
||||||
|
: clientAddress.value;
|
||||||
const token_overrides = {
|
const token_overrides = {
|
||||||
"client.person.person_address.address": clientAddr.address,
|
"client.person.person_address.address": clientAddr.address,
|
||||||
"client.person.person_address.post_code": clientAddr.post_code,
|
"client.person.person_address.post_code": clientAddr.post_code,
|
||||||
|
|
@ -240,33 +261,27 @@ async function submitGenerate() {
|
||||||
template_version: tpl.version,
|
template_version: tpl.version,
|
||||||
custom: { ...customInputs.value },
|
custom: { ...customInputs.value },
|
||||||
token_overrides,
|
token_overrides,
|
||||||
unresolved_policy: 'fail',
|
unresolved_policy: "fail",
|
||||||
};
|
};
|
||||||
const { data } = await axios.post(
|
await router.post(
|
||||||
route("contracts.generate-document", { contract: c.uuid }),
|
route("contracts.generate-document", { contract: c.uuid }),
|
||||||
payload
|
payload,
|
||||||
);
|
{
|
||||||
if (data.status === "ok") {
|
preserveScroll: true,
|
||||||
generatedDocs.value[c.uuid] = { uuid: data.document_uuid, path: data.path };
|
onSuccess: () => {
|
||||||
// if no tokens were found/replaced, surface a gentle warning inline
|
// Close dialog and refresh documents list
|
||||||
const stats = data.stats || null;
|
|
||||||
// Show warning only when zero tokens were found in the template (most common real issue)
|
|
||||||
if (stats && stats.tokensFound === 0) {
|
|
||||||
generationError.value[c.uuid] = "Opozorilo: V predlogi niso bili najdeni tokeni.";
|
|
||||||
} else {
|
|
||||||
generationError.value[c.uuid] = null;
|
generationError.value[c.uuid] = null;
|
||||||
}
|
|
||||||
showGenerateDialog.value = false;
|
showGenerateDialog.value = false;
|
||||||
router.reload({ only: ["documents"] });
|
router.reload({ only: ["documents"] });
|
||||||
} else {
|
},
|
||||||
generationError.value[c.uuid] = data.message || "Napaka pri generiranju.";
|
onError: () => {
|
||||||
}
|
// Typically 422 validation-like errors
|
||||||
} catch (e) {
|
|
||||||
if (e?.response?.status === 422) {
|
|
||||||
generationError.value[c.uuid] = "Manjkajoči tokeni v predlogi.";
|
generationError.value[c.uuid] = "Manjkajoči tokeni v predlogi.";
|
||||||
} else {
|
},
|
||||||
generationError.value[c.uuid] = "Neuspešno generiranje.";
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
generationError.value[c.uuid] = "Neuspešno generiranje.";
|
||||||
} finally {
|
} finally {
|
||||||
generating.value[c.uuid] = false;
|
generating.value[c.uuid] = false;
|
||||||
}
|
}
|
||||||
|
|
@ -739,7 +754,7 @@ const closePaymentsDialog = () => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="w-full px-3 py-2 text-left text-sm text-gray-700 hover:bg-gray-50 flex items-center gap-2"
|
class="w-full px-3 py-2 text-left text-sm text-gray-700 hover:bg-gray-50 flex items-center gap-2"
|
||||||
:disabled="generating[c.uuid] || !templates || templates.length===0"
|
:disabled="generating[c.uuid] || !templates || templates.length === 0"
|
||||||
@click="openGenerateDialog(c)"
|
@click="openGenerateDialog(c)"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
|
@ -747,7 +762,13 @@ const closePaymentsDialog = () => {
|
||||||
class="h-4 w-4 text-gray-600"
|
class="h-4 w-4 text-gray-600"
|
||||||
:class="generating[c.uuid] ? 'animate-spin' : ''"
|
:class="generating[c.uuid] ? 'animate-spin' : ''"
|
||||||
/>
|
/>
|
||||||
<span>{{ generating[c.uuid] ? 'Generiranje...' : (templates && templates.length ? 'Generiraj dokument' : 'Ni predlog') }}</span>
|
<span>{{
|
||||||
|
generating[c.uuid]
|
||||||
|
? "Generiranje..."
|
||||||
|
: templates && templates.length
|
||||||
|
? "Generiraj dokument"
|
||||||
|
: "Ni predlog"
|
||||||
|
}}</span>
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
v-if="generatedDocs[c.uuid]?.path"
|
v-if="generatedDocs[c.uuid]?.path"
|
||||||
|
|
@ -941,15 +962,23 @@ const closePaymentsDialog = () => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Generate document dialog -->
|
<!-- Generate document dialog -->
|
||||||
<div v-if="showGenerateDialog" class="fixed inset-0 z-50 flex items-center justify-center bg-black/30">
|
<DialogModal :show="showGenerateDialog" max-width="4xl" @close="closeGenerateDialog">
|
||||||
<div class="bg-white rounded-lg shadow-lg p-4 w-full max-w-lg">
|
<template #title>Generiraj dokument</template>
|
||||||
<div class="text-base font-medium text-gray-900 mb-2">Generiraj dokument</div>
|
<template #content>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700">Predloga</label>
|
<label class="block text-sm font-medium text-gray-700">Predloga</label>
|
||||||
<select v-model="selectedTemplateSlug" @change="onTemplateChange" class="mt-1 w-full rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500">
|
<select
|
||||||
<option v-if="!templates || templates.length===0" :value="null" disabled>Ni aktivnih predlog</option>
|
v-model="selectedTemplateSlug"
|
||||||
<option v-for="t in templates" :key="t.slug" :value="t.slug">{{ t.name }} ({{ t.version }})</option>
|
@change="onTemplateChange"
|
||||||
|
class="mt-1 w-full rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
<option v-if="!templates || templates.length === 0" :value="null" disabled>
|
||||||
|
Ni aktivnih predlog
|
||||||
|
</option>
|
||||||
|
<option v-for="t in templates" :key="t.slug" :value="t.slug">
|
||||||
|
{{ t.name }} ({{ t.version }})
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -970,15 +999,36 @@ const closePaymentsDialog = () => {
|
||||||
<div class="mt-2 grid grid-cols-3 gap-2 text-sm">
|
<div class="mt-2 grid grid-cols-3 gap-2 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-gray-500">Naslov</div>
|
<div class="text-gray-500">Naslov</div>
|
||||||
<div class="text-gray-900 truncate">{{ (clientAddressSource==='case_person'?casePersonAddress:clientAddress).address || '-' }}</div>
|
<div class="text-gray-900 truncate">
|
||||||
|
{{
|
||||||
|
(clientAddressSource === "case_person"
|
||||||
|
? casePersonAddress
|
||||||
|
: clientAddress
|
||||||
|
).address || "-"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-gray-500">Pošta</div>
|
<div class="text-gray-500">Pošta</div>
|
||||||
<div class="text-gray-900 truncate">{{ (clientAddressSource==='case_person'?casePersonAddress:clientAddress).post_code || '-' }}</div>
|
<div class="text-gray-900 truncate">
|
||||||
|
{{
|
||||||
|
(clientAddressSource === "case_person"
|
||||||
|
? casePersonAddress
|
||||||
|
: clientAddress
|
||||||
|
).post_code || "-"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-gray-500">Kraj</div>
|
<div class="text-gray-500">Kraj</div>
|
||||||
<div class="text-gray-900 truncate">{{ (clientAddressSource==='case_person'?casePersonAddress:clientAddress).city || '-' }}</div>
|
<div class="text-gray-900 truncate">
|
||||||
|
{{
|
||||||
|
(clientAddressSource === "case_person"
|
||||||
|
? casePersonAddress
|
||||||
|
: clientAddress
|
||||||
|
).city || "-"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -997,15 +1047,36 @@ const closePaymentsDialog = () => {
|
||||||
<div class="mt-2 grid grid-cols-3 gap-2 text-sm">
|
<div class="mt-2 grid grid-cols-3 gap-2 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-gray-500">Naslov</div>
|
<div class="text-gray-500">Naslov</div>
|
||||||
<div class="text-gray-900 truncate">{{ (personAddressSource==='case_person'?casePersonAddress:clientAddress).address || '-' }}</div>
|
<div class="text-gray-900 truncate">
|
||||||
|
{{
|
||||||
|
(personAddressSource === "case_person"
|
||||||
|
? casePersonAddress
|
||||||
|
: clientAddress
|
||||||
|
).address || "-"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-gray-500">Pošta</div>
|
<div class="text-gray-500">Pošta</div>
|
||||||
<div class="text-gray-900 truncate">{{ (personAddressSource==='case_person'?casePersonAddress:clientAddress).post_code || '-' }}</div>
|
<div class="text-gray-900 truncate">
|
||||||
|
{{
|
||||||
|
(personAddressSource === "case_person"
|
||||||
|
? casePersonAddress
|
||||||
|
: clientAddress
|
||||||
|
).post_code || "-"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-gray-500">Kraj</div>
|
<div class="text-gray-500">Kraj</div>
|
||||||
<div class="text-gray-900 truncate">{{ (personAddressSource==='case_person'?casePersonAddress:clientAddress).city || '-' }}</div>
|
<div class="text-gray-900 truncate">
|
||||||
|
{{
|
||||||
|
(personAddressSource === "case_person"
|
||||||
|
? casePersonAddress
|
||||||
|
: clientAddress
|
||||||
|
).city || "-"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1014,23 +1085,35 @@ const closePaymentsDialog = () => {
|
||||||
<div v-if="customTokenList.length" class="pt-2">
|
<div v-if="customTokenList.length" class="pt-2">
|
||||||
<div class="text-sm font-medium text-gray-700 mb-1">Dodatna polja</div>
|
<div class="text-sm font-medium text-gray-700 mb-1">Dodatna polja</div>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div v-for="tok in customTokenList" :key="tok" class="grid grid-cols-3 gap-2 items-start">
|
<div
|
||||||
|
v-for="tok in customTokenList"
|
||||||
|
:key="tok"
|
||||||
|
class="grid grid-cols-3 gap-2 items-start"
|
||||||
|
>
|
||||||
<div class="col-span-1 text-sm text-gray-600">{{ tok }}</div>
|
<div class="col-span-1 text-sm text-gray-600">{{ tok }}</div>
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<template v-if="templateCustomTypes[tok.replace(/^custom\./,'')] === 'text'">
|
<template
|
||||||
|
v-if="templateCustomTypes[tok.replace(/^custom\./, '')] === 'text'"
|
||||||
|
>
|
||||||
<textarea
|
<textarea
|
||||||
class="w-full rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 text-sm"
|
class="w-full rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 text-sm"
|
||||||
rows="3"
|
rows="3"
|
||||||
v-model="customInputs[tok.replace(/^custom\./,'')]"
|
v-model="customInputs[tok.replace(/^custom\./, '')]"
|
||||||
:placeholder="templateCustomDefaults[tok.replace(/^custom\./,'')] ?? 'privzeta vrednost'"
|
:placeholder="
|
||||||
|
templateCustomDefaults[tok.replace(/^custom\./, '')] ??
|
||||||
|
'privzeta vrednost'
|
||||||
|
"
|
||||||
></textarea>
|
></textarea>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500"
|
class="w-full rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500"
|
||||||
v-model="customInputs[tok.replace(/^custom\./,'')]"
|
v-model="customInputs[tok.replace(/^custom\./, '')]"
|
||||||
:placeholder="templateCustomDefaults[tok.replace(/^custom\./,'')] ?? 'privzeta vrednost'"
|
:placeholder="
|
||||||
|
templateCustomDefaults[tok.replace(/^custom\./, '')] ??
|
||||||
|
'privzeta vrednost'
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1038,11 +1121,24 @@ const closePaymentsDialog = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 flex justify-end gap-2">
|
<div v-if="generationError[generateFor?.uuid]" class="mt-3 text-sm text-rose-600">
|
||||||
<button class="px-4 py-2 rounded bg-gray-200 hover:bg-gray-300" @click="closeGenerateDialog">Prekliči</button>
|
{{ generationError[generateFor?.uuid] }}
|
||||||
<button class="px-4 py-2 rounded bg-indigo-600 text-white hover:bg-indigo-700" :disabled="!selectedTemplateSlug || generating[generateFor?.uuid]" @click="submitGenerate">Generiraj</button>
|
|
||||||
</div>
|
|
||||||
<div v-if="generationError[generateFor?.uuid]" class="mt-2 text-sm text-rose-600">{{ generationError[generateFor?.uuid] }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded bg-gray-200 hover:bg-gray-300 mr-2"
|
||||||
|
@click="closeGenerateDialog"
|
||||||
|
>
|
||||||
|
Prekliči
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded bg-indigo-600 text-white hover:bg-indigo-700"
|
||||||
|
:disabled="!selectedTemplateSlug || generating[generateFor?.uuid]"
|
||||||
|
@click="submitGenerate"
|
||||||
|
>
|
||||||
|
Generiraj
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</DialogModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user