@bobbykim/manguito-cms-admin 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{ChangePasswordView-v3tSL_0C.js → ChangePasswordView-Cu5tB24J.js} +1 -1
- package/dist/assets/ContentFormView-CFQEZZid.js +1 -0
- package/dist/assets/{ContentListView-i3MwjmNq.js → ContentListView-BftGcgU1.js} +1 -1
- package/dist/assets/{ContentSettingsView-4cpotfsZ.js → ContentSettingsView-DLYsyUlu.js} +1 -1
- package/dist/assets/{LoginView-BObIe0zr.js → LoginView-CozTK_GW.js} +1 -1
- package/dist/assets/{MediaDetailView-BKTDY6Ne.js → MediaDetailView-ByqqmxcZ.js} +1 -1
- package/dist/assets/{MediaLibraryView-DojOE-wL.js → MediaLibraryView-Ss0vIfJ1.js} +1 -1
- package/dist/assets/TaxonomyFormView-D8FV6n4a.js +1 -0
- package/dist/assets/{TaxonomyListView-Cy3iI1oC.js → TaxonomyListView-C-VzXAxl.js} +1 -1
- package/dist/assets/{UserFormView-B2m4OdJV.js → UserFormView-CGEqYM-x.js} +1 -1
- package/dist/assets/{UserListView-z6weJ8UF.js → UserListView-CZukprIO.js} +1 -1
- package/dist/assets/{field-defaults-DLoPESiE.js → field-defaults-Coq6Ej9B.js} +20 -20
- package/dist/assets/{index-C4qBpxpk.css → index-BYJBLBFc.css} +1 -1
- package/dist/assets/{index-stKCwnA4.js → index-BaJYEgrK.js} +2 -2
- package/dist/assets/{useNotification-BdRk9gQY.js → useNotification-Cmvg0Rzg.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +2 -2
- package/src/components/fields/ParagraphEmbed.vue +4 -10
- package/src/components/fields/ReferenceSelect.vue +49 -5
- package/src/components/fields/__tests__/ReferenceSelect.test.ts +95 -0
- package/src/utils/__tests__/move-item.test.ts +22 -0
- package/src/utils/__tests__/server-errors.test.ts +19 -0
- package/src/utils/move-item.ts +10 -0
- package/src/utils/server-errors.ts +19 -0
- package/src/views/content/ContentFormView.vue +5 -2
- package/src/views/taxonomy/TaxonomyFormView.vue +5 -2
- package/src/views/taxonomy/__tests__/TaxonomyFormView.test.ts +37 -1
- package/dist/assets/ContentFormView-DneaTAaq.js +0 -1
- package/dist/assets/TaxonomyFormView-Chd_LUly.js +0 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// A copy of `list` with the item at `from` moved to `to`, or null when there is
|
|
2
|
+
// nothing to move (the same index, or one outside the list), so a caller can
|
|
3
|
+
// skip emitting an unchanged list.
|
|
4
|
+
export function moveItem<T>(list: readonly T[], from: number, to: number): T[] | null {
|
|
5
|
+
if (from === to || from < 0 || to < 0 || from >= list.length || to >= list.length) return null
|
|
6
|
+
const next = [...list]
|
|
7
|
+
const [moved] = next.splice(from, 1)
|
|
8
|
+
next.splice(to, 0, moved as T)
|
|
9
|
+
return next
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ServerDetail = { field: string; message: string }
|
|
2
|
+
|
|
3
|
+
// A 422's details, split into those a form shows next to one of its fields and
|
|
4
|
+
// the rest: paths inside paragraph items, such as "cards[0].heading", which
|
|
5
|
+
// have no field of their own in the form state, so the form lists them with
|
|
6
|
+
// its error message instead.
|
|
7
|
+
export function splitServerDetails(
|
|
8
|
+
details: ServerDetail[],
|
|
9
|
+
fieldNames: string[],
|
|
10
|
+
): { fieldErrors: ServerDetail[]; other: string[] } {
|
|
11
|
+
const known = new Set(fieldNames)
|
|
12
|
+
const fieldErrors: ServerDetail[] = []
|
|
13
|
+
const other: string[] = []
|
|
14
|
+
for (const d of details) {
|
|
15
|
+
if (known.has(d.field)) fieldErrors.push(d)
|
|
16
|
+
else other.push(d.message)
|
|
17
|
+
}
|
|
18
|
+
return { fieldErrors, other }
|
|
19
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { splitServerDetails } from '../../utils/server-errors'
|
|
2
3
|
import { ref, computed, onMounted, watch } from 'vue'
|
|
3
4
|
import { useRoute, useRouter } from 'vue-router'
|
|
4
5
|
import type { ParsedField } from '@bobbykim/manguito-cms-core'
|
|
@@ -173,8 +174,10 @@ async function doSave(publishedOverride?: boolean) {
|
|
|
173
174
|
|
|
174
175
|
if (!res.ok) {
|
|
175
176
|
const raw = res.error as { code: string; message: string; details?: Array<{ field: string; message: string }> }
|
|
176
|
-
if (raw.code === 'PUBLISH_VALIDATION_ERROR' && raw.details) {
|
|
177
|
-
|
|
177
|
+
if ((raw.code === 'PUBLISH_VALIDATION_ERROR' || raw.code === 'VALIDATION_ERROR') && raw.details) {
|
|
178
|
+
const { fieldErrors, other } = splitServerDetails(raw.details, allFields.value.map((f) => f.name))
|
|
179
|
+
mergeServerErrors(fieldErrors)
|
|
180
|
+
if (other.length > 0) formError.value = [raw.message, ...other].join(' ')
|
|
178
181
|
} else if (raw.code === 'SLUG_CONFLICT') {
|
|
179
182
|
setError('slug', 'This slug is already taken.')
|
|
180
183
|
} else {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { splitServerDetails } from '../../utils/server-errors'
|
|
2
3
|
import { ref, computed, onMounted, watch } from 'vue'
|
|
3
4
|
import { useRoute, useRouter } from 'vue-router'
|
|
4
5
|
import { useApiClient } from '../../composables/useApiClient'
|
|
@@ -112,8 +113,10 @@ async function onSave() {
|
|
|
112
113
|
message: string
|
|
113
114
|
details?: Array<{ field: string; message: string }>
|
|
114
115
|
}
|
|
115
|
-
if (raw.code === 'PUBLISH_VALIDATION_ERROR' && raw.details) {
|
|
116
|
-
|
|
116
|
+
if ((raw.code === 'PUBLISH_VALIDATION_ERROR' || raw.code === 'VALIDATION_ERROR') && raw.details) {
|
|
117
|
+
const { fieldErrors, other } = splitServerDetails(raw.details, allFields.value.map((f) => f.name))
|
|
118
|
+
mergeServerErrors(fieldErrors)
|
|
119
|
+
if (other.length > 0) formError.value = [raw.message, ...other].join(' ')
|
|
117
120
|
} else if (raw.code === 'SLUG_CONFLICT') {
|
|
118
121
|
setError('slug', 'This slug is already taken.')
|
|
119
122
|
} else {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
2
|
import { mount, flushPromises } from '@vue/test-utils'
|
|
3
3
|
import { createPinia, setActivePinia } from 'pinia'
|
|
4
4
|
import type { ParsedField, ParsedTaxonomyType } from '@bobbykim/manguito-cms-core'
|
|
5
5
|
import { useSchemaStore } from '../../../stores/schema'
|
|
6
|
+
import { useAuthStore } from '../../../stores/auth'
|
|
6
7
|
import TaxonomyFormView from '../TaxonomyFormView.vue'
|
|
7
8
|
import ParagraphEmbed from '../../../components/fields/ParagraphEmbed.vue'
|
|
8
9
|
import ReferenceSelect from '../../../components/fields/ReferenceSelect.vue'
|
|
@@ -44,6 +45,10 @@ const tagType = {
|
|
|
44
45
|
|
|
45
46
|
let pinia: ReturnType<typeof createPinia>
|
|
46
47
|
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
vi.unstubAllGlobals()
|
|
50
|
+
})
|
|
51
|
+
|
|
47
52
|
beforeEach(() => {
|
|
48
53
|
pinia = createPinia()
|
|
49
54
|
setActivePinia(pinia)
|
|
@@ -61,6 +66,37 @@ describe('TaxonomyFormView', () => {
|
|
|
61
66
|
expect(w.findComponent(ParagraphEmbed).exists()).toBe(true)
|
|
62
67
|
})
|
|
63
68
|
|
|
69
|
+
it('shows VALIDATION_ERROR details from a save: on the field, or in the banner for a paragraph path', async () => {
|
|
70
|
+
// MUTATION: merge details only for PUBLISH_VALIDATION_ERROR (before #57).
|
|
71
|
+
// The editor then sees only "Some values are not valid", with no field.
|
|
72
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(
|
|
73
|
+
new Response(JSON.stringify({
|
|
74
|
+
ok: false,
|
|
75
|
+
error: {
|
|
76
|
+
code: 'VALIDATION_ERROR',
|
|
77
|
+
message: 'Some values are not valid',
|
|
78
|
+
details: [
|
|
79
|
+
{ field: 'name', message: 'name can be at most 255 characters.' },
|
|
80
|
+
{ field: 'blurb.text', message: 'blurb.text is required.' },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
}), { status: 422, headers: { 'Content-Type': 'application/json' } })
|
|
84
|
+
))
|
|
85
|
+
// An editor allowed to create terms, so the Save button renders.
|
|
86
|
+
useSchemaStore().setRoles([{ name: 'editor', label: 'Editor', hierarchy_level: 1, permissions: ['taxonomy:create'] }] as never)
|
|
87
|
+
useAuthStore().setUser({ id: 'u1', email: 'e@example.com', role: 'editor' })
|
|
88
|
+
const w = mount(TaxonomyFormView, { global: { plugins: [pinia] } })
|
|
89
|
+
await flushPromises()
|
|
90
|
+
const save = w.findAll('button').find((b) => b.text() === 'Save')!
|
|
91
|
+
await save.trigger('click')
|
|
92
|
+
await flushPromises()
|
|
93
|
+
|
|
94
|
+
// The field's own error, and the form's banner, are both alerts.
|
|
95
|
+
const alerts = w.findAll('[role="alert"]').map((a) => a.text())
|
|
96
|
+
expect(alerts).toContain('name can be at most 255 characters.')
|
|
97
|
+
expect(alerts).toContain('Some values are not valid blurb.text is required.')
|
|
98
|
+
})
|
|
99
|
+
|
|
64
100
|
it('gives the paragraph editor its paragraph form', async () => {
|
|
65
101
|
// MUTATION: render with componentFor but drop `v-bind="fieldExtraProps(field)"`.
|
|
66
102
|
// ParagraphEmbed then has no formComponent and cannot render its item.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as e,B as t,E as n,O as r,P as ee,W as i,c as a,ct as o,d as s,g as c,i as l,j as u,l as d,lt as te,m as ne,s as f,t as p,u as m,ut as h,w as re,x as ie}from"./schema-B-RKX_ep.js";import{c as ae,n as oe,s as se,t as ce,u as le}from"./index-stKCwnA4.js";import{i as ue,n as de,r as fe,t as pe}from"./field-defaults-DLoPESiE.js";import{t as me}from"./useNotification-BdRk9gQY.js";import{t as he}from"./content--2XYr_UQ.js";import{t as g}from"./ConfirmDialog-B7nxdDge.js";import{t as ge}from"./useTabIndicator-CvEsGBJh.js";var _e={key:0,class:`flex items-center justify-center py-20`},ve={key:1,class:`py-12 text-center text-sm text-gray-500`},ye={key:2},be={class:`mb-[22px] flex flex-wrap items-start justify-between gap-4`},xe={class:`mb-1.5 text-[11px] font-bold uppercase tracking-[.06em] text-faint`},Se={class:`text-[25px] font-bold tracking-tight text-ink`},Ce={class:`flex shrink-0 flex-wrap items-center gap-[9px]`},we=[`disabled`],Te=[`disabled`],Ee=[`disabled`],De=[`disabled`],Oe={key:0,class:`mb-[18px] rounded-2xl border border-card-border bg-white p-5 shadow-[0_1px_2px_rgba(24,24,48,0.04),0_8px_22px_rgba(24,24,48,0.04)]`},ke={class:`mt-2 flex flex-wrap items-center gap-[10px]`},Ae=[`disabled`],_={key:0,class:`mt-[9px] text-[12.5px] text-[#D9913C]`},v={key:1,class:`mt-1 text-sm text-red-600`,role:`alert`},y=[`data-tab`,`onClick`],b={class:`space-y-5`},x={key:2,class:`mt-4 text-sm text-red-600`,role:`alert`},S=c({__name:`ContentFormView`,setup(c){let S=se(),C=ae(),w=ce(),{can:T}=oe(),{errors:E,validate:D,mergeServerErrors:je,clearErrors:Me,setError:Ne}=ue(),Pe=me(),Fe=p(),O=he(),k=f(()=>S.params.type),A=f(()=>S.params.id),j=f(()=>Fe.contentTypes[k.value]),M=f(()=>j.value?.fields??[]),N=f(()=>j.value?.ui.tabs??[]),P=f(()=>j.value?.only_one===!0),F=f(()=>P.value?`singleton`:A.value?`edit`:`create`),I=t(null),L=t({}),R=t(!1),z=t(``),B=t(!1),V=t(!0),H=t(!1),U=t(``),W=t(!1),G=t(!1),K=t(null),q=t(0),Ie=f(()=>N.value[q.value]?.name??``),J=t(null),{left:Le,width:Re}=ge(J,Ie),Y=f(()=>{if(N.value.length===0)return M.value;let e=N.value[q.value];return e?e.fields.map(e=>M.value.find(t=>t.name===e)).filter(e=>e!==void 0):M.value}),X=f(()=>F.value===`edit`&&R.value&&L.value.slug!==z.value);function Z(e){let t={};P.value||(t.slug=e?.slug??``);for(let n of M.value)n.field_type!==`programmatic`&&(t[n.name]=e?.[n.name]??pe(n));L.value=t,R.value=e?.published===!0,e?.slug&&(z.value=String(e.slug))}function ze(e,t){L.value[e]=t}async function Q(e){let t=await w.get(`/content/${k.value}/${e}`);t.ok?(I.value=t.data,Z(t.data)):U.value=t.error.message}re(async()=>{if(!j.value){V.value=!1;return}F.value===`edit`&&A.value||F.value===`singleton`&&A.value?await Q(A.value):Z(),V.value=!1}),u(A,async(e,t)=>{e!==t&&(V.value=!0,B.value=!1,Me(),e?await Q(e):(I.value=null,Z()),V.value=!1)});async function $(e){H.value=!0,U.value=``;let t={...L.value};e!==void 0&&(t.published=e);let n;if(n=F.value===`create`?await w.post(`/content/${k.value}`,t):F.value===`singleton`?await w.put(`/content/${k.value}`,t):await w.patch(`/content/${k.value}/${A.value}`,t),H.value=!1,!n.ok){let e=n.error;e.code===`PUBLISH_VALIDATION_ERROR`&&e.details?je(e.details):e.code===`SLUG_CONFLICT`?Ne(`slug`,`This slug is already taken.`):U.value=e.message;return}I.value=n.data,R.value=n.data.published===!0,z.value=String(n.data.slug??``),B.value=!1,O.invalidate(k.value),Pe.success(`Saved.`),F.value===`create`&&C.replace({name:`content-edit`,params:{type:k.value,id:String(n.data.id)}})}function Be(){if(D(M.value,L.value)){if(X.value){K.value=()=>$(),W.value=!0;return}$()}}function Ve(){if(D(M.value,L.value,!0)){if(X.value){K.value=()=>$(!0),W.value=!0;return}$(!0)}}function He(){$(!1)}function Ue(){W.value=!1,K.value&&=(K.value(),null)}function We(){W.value=!1,K.value=null}async function Ge(){G.value=!1,H.value=!0;let e=await w.del(`/content/${k.value}/${A.value}`);if(H.value=!1,!e.ok){U.value=e.error.message;return}O.invalidate(k.value),C.push({name:`content-list`,params:{type:k.value}})}let Ke=f(()=>{if(F.value===`create`)return`New ${j.value?.label??``}`;if(F.value===`singleton`)return j.value?.label??``;let e=M.value.find(e=>e.field_type===`text/plain`);return(e?String(I.value?.[e.name]??``):``)||(j.value?.label??``)});return(t,c)=>V.value?(n(),s(`div`,_e,[...c[3]||=[a(`span`,{class:`inline-block h-6 w-6 animate-spin rounded-full border-2 border-indigo-600 border-t-transparent`,"aria-hidden":`true`},null,-1)]])):j.value?(n(),s(`div`,ye,[a(`div`,be,[a(`div`,null,[a(`p`,xe,h(j.value.label),1),a(`h1`,Se,h(Ke.value),1)]),a(`div`,Ce,[i(T)(`content:delete`)&&F.value===`edit`?(n(),s(`button`,{key:0,type:`button`,disabled:H.value,class:`inline-flex items-center gap-1.5 rounded-[10px] border border-[#F3D2D7] bg-white px-[15px] py-2.5 text-[13px] font-semibold text-[#E1495B] transition-colors hover:bg-[#FDF2F4] disabled:cursor-not-allowed disabled:opacity-50`,onClick:c[0]||=e=>G.value=!0},` Delete `,8,we)):m(``,!0),i(T)(`content:edit`)?(n(),s(l,{key:1},[R.value?(n(),s(`button`,{key:0,type:`button`,disabled:H.value,class:`rounded-[10px] border border-[#E4E3EE] bg-white px-4 py-2.5 text-[13px] font-semibold text-[#3D3D52] transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-50`,onClick:He},` Unpublish `,8,Te)):(n(),s(`button`,{key:1,type:`button`,disabled:H.value,class:`rounded-[10px] border border-[#E4E3EE] bg-white px-4 py-2.5 text-[13px] font-semibold text-[#3D3D52] transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-50`,onClick:Ve},` Publish `,8,Ee)),a(`button`,{type:`button`,disabled:H.value,class:`inline-flex items-center gap-1.5 rounded-[10px] bg-indigo-600 px-4 py-2.5 text-[13px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)] disabled:cursor-not-allowed disabled:opacity-50`,onClick:Be},h(H.value?`Saving…`:`Save draft`),9,De)],64)):m(``,!0)])]),P.value?m(``,!0):(n(),s(`div`,Oe,[c[4]||=a(`label`,{for:`slug-field`,class:`block text-[13px] font-semibold text-[#3D3D52]`},[ne(` Slug `),a(`span`,{class:`ml-0.5 text-red-500`,"aria-hidden":`true`},`*`)],-1),a(`div`,ke,[ee(a(`input`,{id:`slug-field`,"onUpdate:modelValue":c[1]||=e=>L.value.slug=e,type:`text`,disabled:H.value||R.value&&!B.value,class:o([`block min-w-[180px] flex-1 rounded-[10px] border px-[13px] py-[11px] font-mono text-sm focus:outline-none focus:ring-2`,i(E).slug?`border-red-300 focus:border-red-400 focus:ring-red-200`:`border-[#E4E3EE] bg-surface focus:border-indigo-400 focus:ring-indigo-200`,(H.value||R.value&&!B.value)&&`cursor-not-allowed bg-gray-100 opacity-70`]),placeholder:`url-slug`},null,10,Ae),[[le,L.value.slug]]),R.value&&!B.value?(n(),s(`button`,{key:0,type:`button`,class:`shrink-0 rounded-[10px] border border-[#E4E3EE] bg-white px-4 py-2.5 text-sm font-semibold text-[#3D3D52] transition-colors hover:bg-surface`,onClick:c[2]||=e=>B.value=!0},` Edit slug `)):m(``,!0)]),R.value?(n(),s(`p`,_,` Changing this slug will break existing links. `)):m(``,!0),i(E).slug?(n(),s(`p`,v,h(i(E).slug),1)):m(``,!0)])),N.value.length>1?(n(),s(`div`,{key:1,ref_key:`tabBarRef`,ref:J,class:`relative mb-[22px] flex gap-0 overflow-x-auto border-b border-card-border`},[(n(!0),s(l,null,r(N.value,(e,t)=>(n(),s(`button`,{key:e.name,"data-tab":e.name,type:`button`,class:o([`mr-6 whitespace-nowrap bg-none px-0.5 py-[11px] text-sm transition-colors`,q.value===t?`font-semibold text-indigo-600`:`font-medium text-faint hover:text-[#8A8A9E]`]),onClick:e=>q.value=t},h(e.label),11,y))),128)),a(`div`,{class:`absolute -bottom-px h-0.5 rounded-full bg-indigo-600 transition-[left,width] duration-300`,style:te({left:`${i(Le)}px`,width:`${i(Re)}px`})},null,4)],512)):m(``,!0),a(`div`,b,[(n(!0),s(l,null,r(Y.value,t=>(n(),d(e(i(de)(t)),ie({key:t.name,field:t,"model-value":L.value[t.name],error:i(E)[t.name],disabled:H.value},{ref_for:!0},i(fe)(t),{"onUpdate:modelValue":e=>ze(t.name,e)}),null,16,[`field`,`model-value`,`error`,`disabled`,`onUpdate:modelValue`]))),128))]),U.value?(n(),s(`p`,x,h(U.value),1)):m(``,!0),W.value?(n(),d(g,{key:3,message:`This item is published. Changing its slug will break existing links. Continue?`,"on-confirm":Ue,"on-cancel":We})):m(``,!0),G.value?(n(),d(g,{key:4,message:`Are you sure you want to delete this item? This action cannot be undone.`,"on-confirm":Ge,"on-cancel":()=>G.value=!1},null,8,[`on-cancel`])):m(``,!0)])):(n(),s(`div`,ve,` Content type not found. `))}});export{S as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as e,B as t,E as n,O as r,W as i,c as a,d as o,g as s,i as c,j as l,l as u,s as d,t as ee,u as f,ut as p,w as m,x as te}from"./schema-B-RKX_ep.js";import{c as ne,n as h,s as g,t as _}from"./index-stKCwnA4.js";import{i as v,n as y,r as b,t as x}from"./field-defaults-DLoPESiE.js";import{t as S}from"./useNotification-BdRk9gQY.js";import{t as re}from"./ConfirmDialog-B7nxdDge.js";import{t as ie}from"./taxonomy-DC-6wyg3.js";function ae(e,t){let n={};for(let r of e)r.field_type!==`programmatic`&&(n[r.name]=t?.[r.name]??x(r));return n}var oe={key:0,class:`flex items-center justify-center py-20`},se={key:1,class:`py-12 text-center text-sm text-gray-500`},ce={key:2},C={class:`mb-6 flex items-start justify-between gap-4`},w={class:`text-xs font-medium uppercase tracking-wide text-gray-400`},T={class:`text-[26px] font-bold tracking-tight text-ink`},E={class:`flex shrink-0 items-center gap-2`},D=[`disabled`],O=[`disabled`],k={class:`space-y-5`},A={key:0,class:`mt-4 text-sm text-red-600`,role:`alert`},j=s({__name:`TaxonomyFormView`,setup(s){let x=g(),j=ne(),M=_(),{can:N}=h(),{errors:P,validate:F,mergeServerErrors:I,clearErrors:L,setError:le}=v(),R=S(),z=ee(),B=ie(),V=d(()=>x.params.type),H=d(()=>x.params.id),U=d(()=>!!H.value),W=d(()=>z.taxonomyTypes[V.value]),G=d(()=>W.value?.fields??[]),K=t(null),q=t({}),J=t(!0),Y=t(!1),X=t(``),Z=t(!1);function Q(e){q.value=ae(G.value,e)}function ue(e,t){q.value[e]=t}async function $(e){let t=await M.get(`/taxonomy/${V.value}/${e}`);t.ok?(K.value=t.data,Q(t.data)):X.value=t.error.message}m(async()=>{if(!W.value){J.value=!1;return}U.value&&H.value?await $(H.value):Q(),J.value=!1}),l(H,async(e,t)=>{e!==t&&(J.value=!0,L(),e?await $(e):(K.value=null,Q()),J.value=!1)});async function de(){if(!F(G.value,q.value))return;Y.value=!0,X.value=``;let e=U.value?await M.patch(`/taxonomy/${V.value}/${H.value}`,q.value):await M.post(`/taxonomy/${V.value}`,q.value);if(Y.value=!1,!e.ok){let t=e.error;t.code===`PUBLISH_VALIDATION_ERROR`&&t.details?I(t.details):t.code===`SLUG_CONFLICT`?le(`slug`,`This slug is already taken.`):X.value=t.message;return}K.value=e.data,B.invalidate(V.value),R.success(`Saved.`),U.value||j.replace({name:`taxonomy-edit`,params:{type:V.value,id:String(e.data.id)}})}async function fe(){Z.value=!1,Y.value=!0;let e=await M.del(`/taxonomy/${V.value}/${H.value}`);if(Y.value=!1,!e.ok){X.value=e.error.message;return}B.invalidate(V.value),j.push({name:`taxonomy-list`,params:{type:V.value}})}let pe=d(()=>{if(!U.value)return`New ${W.value?.label??``}`;let e=G.value.find(e=>e.field_type===`text/plain`);return e?String(K.value?.[e.name]??``):W.value?.label??``});return(t,s)=>J.value?(n(),o(`div`,oe,[...s[1]||=[a(`span`,{class:`inline-block h-6 w-6 animate-spin rounded-full border-2 border-indigo-600 border-t-transparent`,"aria-hidden":`true`},null,-1)]])):W.value?(n(),o(`div`,ce,[a(`div`,C,[a(`div`,null,[a(`p`,w,p(W.value.label),1),a(`h1`,T,p(pe.value),1)]),a(`div`,E,[i(N)(`taxonomy:delete`)&&U.value?(n(),o(`button`,{key:0,type:`button`,disabled:Y.value,class:`rounded-md px-3 py-2 text-sm font-medium text-red-600 ring-1 ring-inset ring-red-300 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50`,onClick:s[0]||=e=>Z.value=!0},` Delete `,8,D)):f(``,!0),(U.value?i(N)(`taxonomy:edit`):i(N)(`taxonomy:create`))?(n(),o(`button`,{key:1,type:`button`,disabled:Y.value,class:`rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)] disabled:cursor-not-allowed disabled:opacity-50`,onClick:de},p(Y.value?`Saving…`:`Save`),9,O)):f(``,!0)])]),a(`div`,k,[(n(!0),o(c,null,r(G.value,t=>(n(),u(e(i(y)(t)),te({key:t.name,field:t,"model-value":q.value[t.name],error:i(P)[t.name],disabled:Y.value},{ref_for:!0},i(b)(t),{"onUpdate:modelValue":e=>ue(t.name,e)}),null,16,[`field`,`model-value`,`error`,`disabled`,`onUpdate:modelValue`]))),128))]),X.value?(n(),o(`p`,A,p(X.value),1)):f(``,!0),Z.value?(n(),u(re,{key:1,message:`Are you sure you want to delete this term? This action cannot be undone.`,"on-confirm":fe,"on-cancel":()=>Z.value=!1},null,8,[`on-cancel`])):f(``,!0)])):(n(),o(`div`,se,` Taxonomy type not found. `))}});export{j as default};
|