@webx-ui/module-catalog 0.8.9 → 0.9.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/CategoriesPage-B6GBTzvN.js +279 -0
- package/dist/CategoriesPage-B6GBTzvN.js.map +1 -0
- package/dist/CategoryEditorPage-y6EFmOof.js +232 -0
- package/dist/CategoryEditorPage-y6EFmOof.js.map +1 -0
- package/dist/DeletedPage-TGTyQbzn.js +214 -0
- package/dist/DeletedPage-TGTyQbzn.js.map +1 -0
- package/dist/ExchangeImportPage-C6cSg7Cr.js +603 -0
- package/dist/ExchangeImportPage-C6cSg7Cr.js.map +1 -0
- package/dist/ExchangePage-9RrRcSiS.js +544 -0
- package/dist/ExchangePage-9RrRcSiS.js.map +1 -0
- package/dist/ExchangeProfilePage-BUnh9_D7.js +321 -0
- package/dist/ExchangeProfilePage-BUnh9_D7.js.map +1 -0
- package/dist/ExchangeProfilesPage-T6G3HHD8.js +180 -0
- package/dist/ExchangeProfilesPage-T6G3HHD8.js.map +1 -0
- package/dist/ProductEditorPage-Bfp6ZV3d.js +262 -0
- package/dist/ProductEditorPage-Bfp6ZV3d.js.map +1 -0
- package/dist/ProductsPage-BBmw9W4m.js +963 -0
- package/dist/ProductsPage-BBmw9W4m.js.map +1 -0
- package/dist/index-BTEbHnJ5.js +2571 -0
- package/dist/index-BTEbHnJ5.js.map +1 -0
- package/dist/index.d.ts +67 -9
- package/dist/index.js +46 -6056
- package/dist/index.js.map +1 -1
- package/dist/paths-DvfRnXtl.js +15 -0
- package/dist/paths-DvfRnXtl.js.map +1 -0
- package/dist/style.css +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { defineComponent as Q, ref as w, computed as s, onMounted as U, resolveComponent as X, openBlock as r, createElementBlock as Y, createVNode as V, unref as l, withCtx as n, createBlock as i, createTextVNode as d, toDisplayString as p, withModifiers as Z, createCommentVNode as ee, createElementVNode as ae, normalizeClass as te } from "vue";
|
|
2
|
+
import { useRouter as le } from "vue-router";
|
|
3
|
+
import { useAdmin as oe, useTranslate as ne, useErrorText as se, rowMenuWidth as re, WxListScreen as ie, WxRowMenu as ce } from "@webx-ui/module-admin";
|
|
4
|
+
import { createModal as ue, WxTable as de, WxBadge as M, WxText as A, toast as c, confirm as pe } from "@webx-ui/core";
|
|
5
|
+
import { c as ge, u as me, a as he, g as ye, f as fe, _ as be } from "./index-BTEbHnJ5.js";
|
|
6
|
+
import { l as ve } from "./paths-DvfRnXtl.js";
|
|
7
|
+
const _e = { class: "wx-catalog-categories" }, ke = /* @__PURE__ */ Q({
|
|
8
|
+
__name: "CategoriesPage",
|
|
9
|
+
props: {
|
|
10
|
+
base: { default: "/catalog" }
|
|
11
|
+
},
|
|
12
|
+
setup(R) {
|
|
13
|
+
const m = R, h = oe(), x = ge(h), C = me(h), y = le();
|
|
14
|
+
he();
|
|
15
|
+
const a = ne("webx-catalog"), f = se(), g = w([]), T = w(!0), W = w(!1), b = w(""), q = ue(ye), v = s(() => h.can("catalog.manage")), $ = s(() => h.can("catalog.delete")), z = s(() => b.value.trim() === ""), O = s(() => {
|
|
16
|
+
const e = b.value.trim().toLowerCase();
|
|
17
|
+
return fe(g.value).filter(
|
|
18
|
+
(t) => t.name.toLowerCase().includes(e) || (t.slug ?? "").toLowerCase().includes(e)
|
|
19
|
+
).map((t) => ({ ...t, children: [] }));
|
|
20
|
+
}), P = s(() => z.value ? g.value : O.value), F = s(() => [
|
|
21
|
+
{ key: "name", label: a("category.name"), minWidth: 200 },
|
|
22
|
+
{ key: "slug", label: a("category.slug"), width: 200, hideBelow: 620 },
|
|
23
|
+
{ key: "products_count", label: a("panel.column-products"), width: 110, align: "right" },
|
|
24
|
+
{ key: "state", label: a("panel.column-state"), width: 150, hideBelow: 760 },
|
|
25
|
+
{ key: "actions", label: "", width: re, align: "right" }
|
|
26
|
+
]), I = s(
|
|
27
|
+
() => z.value ? {
|
|
28
|
+
childrenKey: "children",
|
|
29
|
+
defaultExpandAll: !0,
|
|
30
|
+
draggable: v.value,
|
|
31
|
+
allowDrop: (e, t) => e.id !== t.id
|
|
32
|
+
} : void 0
|
|
33
|
+
);
|
|
34
|
+
function B(e) {
|
|
35
|
+
g.value = e.map(S);
|
|
36
|
+
}
|
|
37
|
+
function S(e) {
|
|
38
|
+
return { ...e, children: (e.children ?? []).map(S) };
|
|
39
|
+
}
|
|
40
|
+
async function _(e = !0) {
|
|
41
|
+
T.value = !0;
|
|
42
|
+
try {
|
|
43
|
+
B(await C.load(e)), W.value = !0;
|
|
44
|
+
} catch (t) {
|
|
45
|
+
c.danger(f(t));
|
|
46
|
+
} finally {
|
|
47
|
+
T.value = !1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function K(e) {
|
|
51
|
+
b.value = e.search;
|
|
52
|
+
}
|
|
53
|
+
function N(e) {
|
|
54
|
+
y.push(`${m.base}/categories/${e.id}`);
|
|
55
|
+
}
|
|
56
|
+
async function D(e) {
|
|
57
|
+
const t = await q({ parent: e?.id ?? null });
|
|
58
|
+
t && (C.drop(), y.push(`${m.base}/categories/${t.category.id}`));
|
|
59
|
+
}
|
|
60
|
+
async function j(e) {
|
|
61
|
+
const t = e.parent?.id ?? null, o = (e.parent ? e.parent.children ?? [] : g.value)[e.index + 1]?.id ?? null;
|
|
62
|
+
try {
|
|
63
|
+
const k = await x.moveCategory(e.row.id, t, o);
|
|
64
|
+
C.take(k), B(k), c.success(a("panel.category-moved"));
|
|
65
|
+
} catch (k) {
|
|
66
|
+
c.danger(f(k)), await _();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function E(e, t) {
|
|
70
|
+
try {
|
|
71
|
+
await x.saveCategory(e.id, { is_published: t }), c.success(a(t ? "panel.category-published" : "panel.category-unpublished")), await _();
|
|
72
|
+
} catch (u) {
|
|
73
|
+
c.danger(f(u));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function G(e) {
|
|
77
|
+
if (await pe({
|
|
78
|
+
title: a("panel.delete-category-title", { name: e.name }),
|
|
79
|
+
message: a("panel.delete-category-text"),
|
|
80
|
+
confirmText: a("panel.delete"),
|
|
81
|
+
cancelText: a("panel.cancel"),
|
|
82
|
+
tone: "danger"
|
|
83
|
+
}))
|
|
84
|
+
try {
|
|
85
|
+
await x.removeCategory(e.id), c.success(a("panel.category-deleted")), await _();
|
|
86
|
+
} catch (u) {
|
|
87
|
+
c.danger(f(u));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function L(e) {
|
|
91
|
+
return { path: `${m.base}/products`, query: { "f.category": String(e.id) } };
|
|
92
|
+
}
|
|
93
|
+
function H(e) {
|
|
94
|
+
const t = [
|
|
95
|
+
{ key: "open", icon: "edit", label: a("panel.open"), run: () => N(e) },
|
|
96
|
+
{
|
|
97
|
+
key: "products",
|
|
98
|
+
icon: "list",
|
|
99
|
+
label: a("panel.show-products"),
|
|
100
|
+
run: () => {
|
|
101
|
+
y.push(L(e));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
return e.url && e.visible && t.push({ key: "site", icon: "link", label: a("panel.open-on-site"), href: e.url }), v.value && t.push(
|
|
106
|
+
{ key: "add", icon: "plus", label: a("panel.add-child"), run: () => {
|
|
107
|
+
D(e);
|
|
108
|
+
} },
|
|
109
|
+
e.is_published ? {
|
|
110
|
+
key: "unpublish",
|
|
111
|
+
icon: "eye-off",
|
|
112
|
+
label: a("panel.unpublish"),
|
|
113
|
+
run: () => {
|
|
114
|
+
E(e, !1);
|
|
115
|
+
}
|
|
116
|
+
} : {
|
|
117
|
+
key: "publish",
|
|
118
|
+
icon: "eye",
|
|
119
|
+
label: a("panel.publish"),
|
|
120
|
+
run: () => {
|
|
121
|
+
E(e, !0);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
), $.value && t.push({
|
|
125
|
+
key: "delete",
|
|
126
|
+
icon: "trash",
|
|
127
|
+
label: a("panel.delete"),
|
|
128
|
+
danger: !0,
|
|
129
|
+
run: () => {
|
|
130
|
+
G(e);
|
|
131
|
+
}
|
|
132
|
+
}), t;
|
|
133
|
+
}
|
|
134
|
+
U(() => {
|
|
135
|
+
_(!1);
|
|
136
|
+
});
|
|
137
|
+
const J = s(() => {
|
|
138
|
+
const e = [];
|
|
139
|
+
return v.value && e.push({
|
|
140
|
+
key: "new",
|
|
141
|
+
label: a("panel.new-category"),
|
|
142
|
+
icon: "plus",
|
|
143
|
+
primary: !0,
|
|
144
|
+
run: () => {
|
|
145
|
+
D(null);
|
|
146
|
+
}
|
|
147
|
+
}), $.value && e.push({
|
|
148
|
+
key: "deleted",
|
|
149
|
+
label: a("module.deleted"),
|
|
150
|
+
icon: "trash",
|
|
151
|
+
menu: !0,
|
|
152
|
+
run: () => {
|
|
153
|
+
y.push({ path: `${m.base}/deleted`, query: { type: "categories" } });
|
|
154
|
+
}
|
|
155
|
+
}), e;
|
|
156
|
+
});
|
|
157
|
+
return (e, t) => {
|
|
158
|
+
const u = X("router-link");
|
|
159
|
+
return r(), Y("div", _e, [
|
|
160
|
+
V(l(ie), {
|
|
161
|
+
title: l(a)("module.categories"),
|
|
162
|
+
subtitle: v.value && g.value.length > 0 ? l(a)("panel.category-order") : void 0,
|
|
163
|
+
actions: J.value
|
|
164
|
+
}, {
|
|
165
|
+
default: n(() => [
|
|
166
|
+
(r(), i(l(de), {
|
|
167
|
+
key: W.value ? "tree" : "waiting",
|
|
168
|
+
data: P.value,
|
|
169
|
+
columns: F.value,
|
|
170
|
+
"row-key": "id",
|
|
171
|
+
tree: I.value,
|
|
172
|
+
searchable: "",
|
|
173
|
+
clickable: "",
|
|
174
|
+
hover: "",
|
|
175
|
+
flush: "",
|
|
176
|
+
layout: "fixed",
|
|
177
|
+
loading: T.value,
|
|
178
|
+
"cards-below": 0,
|
|
179
|
+
"search-placeholder": l(a)("panel.search-categories"),
|
|
180
|
+
"empty-text": b.value ? l(a)("panel.empty-search") : l(a)("panel.empty-categories"),
|
|
181
|
+
"aria-label": l(a)("module.categories"),
|
|
182
|
+
onRowClick: N,
|
|
183
|
+
onStateChange: K,
|
|
184
|
+
onNodeDrop: j
|
|
185
|
+
}, {
|
|
186
|
+
"cell-name": n(({ row: o }) => [
|
|
187
|
+
ae("span", {
|
|
188
|
+
class: te(["wx-catalog-categories__name", { "is-hidden": !o.visible }])
|
|
189
|
+
}, p(o.name), 3)
|
|
190
|
+
]),
|
|
191
|
+
"cell-slug": n(({ row: o }) => [
|
|
192
|
+
o.slug ? (r(), i(l(A), {
|
|
193
|
+
key: 0,
|
|
194
|
+
mono: "",
|
|
195
|
+
size: "sm",
|
|
196
|
+
tone: "muted",
|
|
197
|
+
truncate: ""
|
|
198
|
+
}, {
|
|
199
|
+
default: n(() => [
|
|
200
|
+
d(" /" + p(l(ve)(o.url) ?? o.slug), 1)
|
|
201
|
+
]),
|
|
202
|
+
_: 2
|
|
203
|
+
}, 1024)) : ee("", !0)
|
|
204
|
+
]),
|
|
205
|
+
"cell-products_count": n(({ row: o }) => [
|
|
206
|
+
o.products_count > 0 ? (r(), i(u, {
|
|
207
|
+
key: 0,
|
|
208
|
+
class: "wx-catalog-categories__count",
|
|
209
|
+
to: L(o),
|
|
210
|
+
onClick: t[0] || (t[0] = Z(() => {
|
|
211
|
+
}, ["stop"]))
|
|
212
|
+
}, {
|
|
213
|
+
default: n(() => [
|
|
214
|
+
d(p(o.products_count), 1)
|
|
215
|
+
]),
|
|
216
|
+
_: 2
|
|
217
|
+
}, 1032, ["to"])) : (r(), i(l(A), {
|
|
218
|
+
key: 1,
|
|
219
|
+
size: "sm",
|
|
220
|
+
tone: "muted"
|
|
221
|
+
}, {
|
|
222
|
+
default: n(() => [...t[1] || (t[1] = [
|
|
223
|
+
d("0", -1)
|
|
224
|
+
])]),
|
|
225
|
+
_: 1
|
|
226
|
+
}))
|
|
227
|
+
]),
|
|
228
|
+
"cell-state": n(({ row: o }) => [
|
|
229
|
+
o.is_published ? o.visible ? (r(), i(l(M), {
|
|
230
|
+
key: 2,
|
|
231
|
+
type: "success",
|
|
232
|
+
dot: "",
|
|
233
|
+
size: "sm"
|
|
234
|
+
}, {
|
|
235
|
+
default: n(() => [
|
|
236
|
+
d(p(l(a)("states.published")), 1)
|
|
237
|
+
]),
|
|
238
|
+
_: 1
|
|
239
|
+
})) : (r(), i(l(M), {
|
|
240
|
+
key: 1,
|
|
241
|
+
type: "warning",
|
|
242
|
+
dot: "",
|
|
243
|
+
size: "sm",
|
|
244
|
+
title: l(a)("panel.category-hidden")
|
|
245
|
+
}, {
|
|
246
|
+
default: n(() => [
|
|
247
|
+
d(p(l(a)("states.published")), 1)
|
|
248
|
+
]),
|
|
249
|
+
_: 1
|
|
250
|
+
}, 8, ["title"])) : (r(), i(l(M), {
|
|
251
|
+
key: 0,
|
|
252
|
+
dot: "",
|
|
253
|
+
size: "sm"
|
|
254
|
+
}, {
|
|
255
|
+
default: n(() => [
|
|
256
|
+
d(p(l(a)("states.unpublished")), 1)
|
|
257
|
+
]),
|
|
258
|
+
_: 1
|
|
259
|
+
}))
|
|
260
|
+
]),
|
|
261
|
+
"cell-actions": n(({ row: o }) => [
|
|
262
|
+
V(l(ce), {
|
|
263
|
+
actions: H(o),
|
|
264
|
+
label: o.name
|
|
265
|
+
}, null, 8, ["actions", "label"])
|
|
266
|
+
]),
|
|
267
|
+
_: 1
|
|
268
|
+
}, 8, ["data", "columns", "tree", "loading", "search-placeholder", "empty-text", "aria-label"]))
|
|
269
|
+
]),
|
|
270
|
+
_: 1
|
|
271
|
+
}, 8, ["title", "subtitle", "actions"])
|
|
272
|
+
]);
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}), $e = /* @__PURE__ */ be(ke, [["__scopeId", "data-v-23a492be"]]);
|
|
276
|
+
export {
|
|
277
|
+
$e as default
|
|
278
|
+
};
|
|
279
|
+
//# sourceMappingURL=CategoriesPage-B6GBTzvN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CategoriesPage-B6GBTzvN.js","sources":["../src/CategoriesPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport { useRouter } from 'vue-router'\nimport {\n rowMenuWidth,\n useAdmin,\n useErrorText,\n useTranslate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n toast,\n WxBadge,\n WxTable,\n WxText,\n type TableColumn,\n type TableNodeDropEvent,\n type TableState,\n type TableTreeOptions,\n} from '@webx-ui/core'\nimport CategoryCreateDialog from './CategoryCreateDialog.vue'\nimport { createCatalogApi } from './api'\nimport { useCatalogMessages } from './i18n'\nimport { lastSegment } from './paths'\nimport { flatten, useCategoryTree } from './store'\nimport type { CategoryDetail, CategoryNode } from './types'\n\n/**\n * The shelves of the catalogue: the whole tree at once, with how many products each holds\n * (§6.1), dragged into place.\n *\n * Whole, not a level at a time as the pages are: a catalogue has dozens of categories, not\n * thousands, and the counts are one query for all of them on the server. A drag moves a category\n * and everything under it; the addresses do not move with it — they are flat (decision 23) — so\n * no drop is ever questioned, unlike a page's.\n *\n * Publication is here as well as on the form, because taking a branch off the site is a thing\n * done to the tree: an unpublished category hides everything below it (§6.3), and the rows under\n * it say so.\n *\n * A search puts the tree away and lists the matches flat — a branch drawn for one match deep\n * inside it tells the reader nothing they asked about.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/catalog' })\n\nconst context = useAdmin()\nconst api = createCatalogApi(context)\nconst tree = useCategoryTree(context)\nconst router = useRouter()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\nconst message = useErrorText()\n\nconst rows = ref<CategoryNode[]>([])\nconst loading = ref(true)\n/*\n * The tree opens every branch on its first render, and only then — so the table is mounted once\n * there is a tree to open, not on the empty one it would otherwise start from.\n */\nconst loaded = ref(false)\nconst search = ref('')\n\nconst create = createModal<CategoryDetail, { parent: number | null }>(CategoryCreateDialog)\n\nconst canManage = computed(() => context.can('catalog.manage'))\nconst canDelete = computed(() => context.can('catalog.delete'))\nconst asTree = computed(() => search.value.trim() === '')\n\nconst matches = computed(() => {\n const term = search.value.trim().toLowerCase()\n\n return flatten(rows.value)\n .filter(\n (node) =>\n node.name.toLowerCase().includes(term) || (node.slug ?? '').toLowerCase().includes(term),\n )\n .map((node) => ({ ...node, children: [] }))\n})\n\nconst data = computed(() => (asTree.value ? rows.value : matches.value))\n\nconst columns = computed<TableColumn<CategoryNode>[]>(() => [\n { key: 'name', label: t('category.name'), minWidth: 200 },\n { key: 'slug', label: t('category.slug'), width: 200, hideBelow: 620 },\n { key: 'products_count', label: t('panel.column-products'), width: 110, align: 'right' },\n { key: 'state', label: t('panel.column-state'), width: 150, hideBelow: 760 },\n { key: 'actions', label: '', width: rowMenuWidth, align: 'right' },\n])\n\nconst treeOptions = computed<TableTreeOptions<CategoryNode> | undefined>(() =>\n asTree.value\n ? {\n childrenKey: 'children',\n defaultExpandAll: true,\n draggable: canManage.value,\n allowDrop: (drag, drop) => drag.id !== drop.id,\n }\n : undefined,\n)\n\n/** A copy: the table rearranges what it is given, and the cache is every picker's. */\nfunction show(nodes: CategoryNode[]): void {\n rows.value = nodes.map(plain)\n}\n\nfunction plain(node: CategoryNode): CategoryNode {\n return { ...node, children: (node.children ?? []).map(plain) }\n}\n\nasync function load(force = true): Promise<void> {\n loading.value = true\n\n try {\n show(await tree.load(force))\n loaded.value = true\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nfunction onState(state: TableState): void {\n search.value = state.search\n}\n\nfunction open(node: CategoryNode): void {\n void router.push(`${props.base}/categories/${node.id}`)\n}\n\nasync function add(parent: CategoryNode | null): Promise<void> {\n const detail = await create({ parent: parent?.id ?? null })\n\n if (!detail) return\n\n tree.drop()\n void router.push(`${props.base}/categories/${detail.category.id}`)\n}\n\n/**\n * The table has already put the row where it was dropped; the server is told the same thing in\n * its own terms — under which parent, before which sibling — and answers with the whole tree,\n * which is drawn as it says rather than as the drop left it.\n */\nasync function dropped(event: TableNodeDropEvent<CategoryNode>): Promise<void> {\n const parent = event.parent?.id ?? null\n const siblings = event.parent ? (event.parent.children ?? []) : rows.value\n const before = siblings[event.index + 1]?.id ?? null\n\n try {\n const answer = await api.moveCategory(event.row.id, parent, before)\n\n tree.take(answer)\n show(answer)\n toast.success(t('panel.category-moved'))\n } catch (error) {\n toast.danger(message(error))\n await load()\n }\n}\n\nasync function publish(node: CategoryNode, on: boolean): Promise<void> {\n try {\n await api.saveCategory(node.id, { is_published: on })\n toast.success(on ? t('panel.category-published') : t('panel.category-unpublished'))\n await load()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function remove(node: CategoryNode): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-category-title', { name: node.name }),\n message: t('panel.delete-category-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeCategory(node.id)\n toast.success(t('panel.category-deleted'))\n await load()\n } catch (error) {\n // Not empty: the server's sentence says how many products or subcategories are in the way.\n toast.danger(message(error))\n }\n}\n\nfunction productsOf(node: CategoryNode) {\n return { path: `${props.base}/products`, query: { 'f.category': String(node.id) } }\n}\n\nfunction actionsFor(node: CategoryNode): RowAction[] {\n const actions: RowAction[] = [\n { key: 'open', icon: 'edit', label: t('panel.open'), run: () => open(node) },\n {\n key: 'products',\n icon: 'list',\n label: t('panel.show-products'),\n run: () => void router.push(productsOf(node)),\n },\n ]\n\n if (node.url && node.visible) {\n actions.push({ key: 'site', icon: 'link', label: t('panel.open-on-site'), href: node.url })\n }\n\n if (canManage.value) {\n actions.push(\n { key: 'add', icon: 'plus', label: t('panel.add-child'), run: () => void add(node) },\n node.is_published\n ? {\n key: 'unpublish',\n icon: 'eye-off',\n label: t('panel.unpublish'),\n run: () => void publish(node, false),\n }\n : {\n key: 'publish',\n icon: 'eye',\n label: t('panel.publish'),\n run: () => void publish(node, true),\n },\n )\n }\n\n if (canDelete.value) {\n actions.push({\n key: 'delete',\n icon: 'trash',\n label: t('panel.delete'),\n danger: true,\n run: () => void remove(node),\n })\n }\n\n return actions\n}\n\nonMounted(() => void load(false))\n\nconst actions = computed<ScreenAction[]>(() => {\n const leads: ScreenAction[] = []\n\n if (canManage.value) {\n leads.push({\n key: 'new',\n label: t('panel.new-category'),\n icon: 'plus',\n primary: true,\n run: () => void add(null),\n })\n }\n\n if (canDelete.value) {\n leads.push({\n key: 'deleted',\n label: t('module.deleted'),\n icon: 'trash',\n menu: true,\n run: () => void router.push({ path: `${props.base}/deleted`, query: { type: 'categories' } }),\n })\n }\n\n return leads\n})\n</script>\n\n<template>\n <div class=\"wx-catalog-categories\">\n <wx-list-screen\n :title=\"t('module.categories')\"\n :subtitle=\"canManage && rows.length > 0 ? t('panel.category-order') : undefined\"\n :actions=\"actions\"\n >\n <wx-table\n :key=\"loaded ? 'tree' : 'waiting'\"\n :data=\"data\"\n :columns=\"columns\"\n row-key=\"id\"\n :tree=\"treeOptions\"\n searchable\n clickable\n hover\n flush\n layout=\"fixed\"\n :loading=\"loading\"\n :cards-below=\"0\"\n :search-placeholder=\"t('panel.search-categories')\"\n :empty-text=\"search ? t('panel.empty-search') : t('panel.empty-categories')\"\n :aria-label=\"t('module.categories')\"\n @row-click=\"open\"\n @state-change=\"onState\"\n @node-drop=\"dropped\"\n >\n <template #cell-name=\"{ row }\">\n <span class=\"wx-catalog-categories__name\" :class=\"{ 'is-hidden': !row.visible }\">\n {{ row.name }}\n </span>\n </template>\n\n <template #cell-slug=\"{ row }\">\n <wx-text v-if=\"row.slug\" mono size=\"sm\" tone=\"muted\" truncate>\n /{{ lastSegment(row.url) ?? row.slug }}\n </wx-text>\n </template>\n\n <template #cell-products_count=\"{ row }\">\n <router-link\n v-if=\"row.products_count > 0\"\n class=\"wx-catalog-categories__count\"\n :to=\"productsOf(row)\"\n @click.stop\n >\n {{ row.products_count }}\n </router-link>\n <wx-text v-else size=\"sm\" tone=\"muted\">0</wx-text>\n </template>\n\n <template #cell-state=\"{ row }\">\n <wx-badge v-if=\"!row.is_published\" dot size=\"sm\">{{ t('states.unpublished') }}</wx-badge>\n <wx-badge\n v-else-if=\"!row.visible\"\n type=\"warning\"\n dot\n size=\"sm\"\n :title=\"t('panel.category-hidden')\"\n >\n {{ t('states.published') }}\n </wx-badge>\n <wx-badge v-else type=\"success\" dot size=\"sm\">{{ t('states.published') }}</wx-badge>\n </template>\n\n <template #cell-actions=\"{ row }\">\n <wx-row-menu :actions=\"actionsFor(row)\" :label=\"row.name\" />\n </template>\n </wx-table>\n </wx-list-screen>\n </div>\n</template>\n\n<style scoped>\n.wx-catalog-categories {\n min-width: 0;\n}\n\n.wx-catalog-categories__name {\n font-weight: var(--wx-font-weight-medium);\n}\n\n/* Hidden by a parent: still here to be arranged, but plainly not what a visitor sees. */\n.wx-catalog-categories__name.is-hidden {\n color: var(--wx-text-muted);\n}\n\n.wx-catalog-categories__count {\n color: var(--wx-color-primary);\n font-variant-numeric: tabular-nums;\n text-decoration: none;\n}\n\n.wx-catalog-categories__count:hover {\n text-decoration: underline;\n}\n</style>\n"],"names":["props","__props","context","useAdmin","api","createCatalogApi","tree","useCategoryTree","router","useRouter","useCatalogMessages","t","useTranslate","message","useErrorText","rows","ref","loading","loaded","search","create","createModal","CategoryCreateDialog","canManage","computed","canDelete","asTree","matches","term","flatten","node","data","columns","rowMenuWidth","treeOptions","drag","drop","show","nodes","plain","load","force","error","toast","onState","state","open","add","parent","detail","dropped","event","before","answer","publish","on","remove","confirm","productsOf","actionsFor","actions","onMounted","leads","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","WxListScreen","_createBlock","WxTable","_withCtx","row","_createElementVNode","_normalizeClass","_toDisplayString","WxText","_component_router_link","_createTextVNode","_cache","WxBadge","WxRowMenu"],"mappings":"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"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { defineComponent as te, computed as o, ref as u, watch as le, onMounted as oe, onBeforeUnmount as re, openBlock as c, createElementBlock as w, Fragment as T, createVNode as s, unref as t, withCtx as n, createBlock as _, createTextVNode as g, toDisplayString as p, createCommentVNode as z, renderList as ne } from "vue";
|
|
2
|
+
import { useRoute as se, useRouter as ue, onBeforeRouteLeave as ce } from "vue-router";
|
|
3
|
+
import { useAdmin as ie, useTranslate as de, useErrorText as ve, provideHistorySubject as ge, provideRecordAddress as pe, useBodyKeys as fe, WxScreenHead as me, WxScreen as ye, WxSaveState as be } from "@webx-ui/module-admin";
|
|
4
|
+
import { useLocales as xe, localizedValue as ke, confirm as F, WxSkeleton as H, WxCard as he, WxBadge as I, WxBreadcrumb as we, WxBreadcrumbItem as V, WxActionBar as _e, WxButton as Ce, toast as f } from "@webx-ui/core";
|
|
5
|
+
import { c as Be, u as Se, a as We, h as Ee, i as Te, _ as Ve } from "./index-BTEbHnJ5.js";
|
|
6
|
+
import { l as J } from "./paths-DvfRnXtl.js";
|
|
7
|
+
const Le = /* @__PURE__ */ te({
|
|
8
|
+
name: "WxCatalogCategoryEditor",
|
|
9
|
+
__name: "CategoryEditorPage",
|
|
10
|
+
props: {
|
|
11
|
+
base: { default: "/catalog" }
|
|
12
|
+
},
|
|
13
|
+
setup(U) {
|
|
14
|
+
const L = U, x = ie(), C = Be(x), m = Se(x), q = se(), B = ue(), G = xe();
|
|
15
|
+
We();
|
|
16
|
+
const a = de("webx-catalog"), S = ve(), N = o(() => Number(q.params.id)), y = o(() => `${L.base}/categories`), l = u(null), $ = u(void 0), i = u({}), k = u(""), W = u(!0), v = u(!1), E = u({}), h = o(() => x.can("catalog.manage")), Q = o(() => x.can("catalog.delete")), A = o(() => !h.value || v.value), D = o(() => JSON.stringify(i.value)), b = o(() => k.value !== "" && D.value !== k.value), X = o(() => v.value ? "saving" : b.value ? "unsaved" : "saved"), K = o(() => {
|
|
17
|
+
const e = i.value.name;
|
|
18
|
+
return ke(e, G.active.value, l.value?.name ?? "") || a("panel.untitled");
|
|
19
|
+
}), Y = o(() => {
|
|
20
|
+
const e = J(l.value?.url);
|
|
21
|
+
return e === null ? void 0 : `/${e}/`;
|
|
22
|
+
}), Z = o(
|
|
23
|
+
() => l.value ? Ee(m.nodes.value ?? [], l.value.id).slice(1).reverse() : []
|
|
24
|
+
);
|
|
25
|
+
Te({ category: l, locked: A, facetsFrom: $ }), ge({ id: o(() => l.value?.id ?? null) }), pe({
|
|
26
|
+
values: i,
|
|
27
|
+
prefix: u(""),
|
|
28
|
+
path: o(() => J(l.value?.url)),
|
|
29
|
+
moving: () => a("panel.address-moving")
|
|
30
|
+
});
|
|
31
|
+
function R(e) {
|
|
32
|
+
l.value = e.category, $.value = e.facets_from, i.value = e.values, k.value = JSON.stringify(e.values);
|
|
33
|
+
}
|
|
34
|
+
async function M() {
|
|
35
|
+
W.value = !0;
|
|
36
|
+
try {
|
|
37
|
+
const [e] = await Promise.all([C.category(N.value), m.load().catch(() => [])]);
|
|
38
|
+
R(e);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
f.danger(S(e)), B.push(y.value);
|
|
41
|
+
} finally {
|
|
42
|
+
W.value = !1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function O() {
|
|
46
|
+
if (!(!l.value || v.value || !h.value)) {
|
|
47
|
+
v.value = !0, E.value = {};
|
|
48
|
+
try {
|
|
49
|
+
R(await C.saveCategory(l.value.id, i.value)), m.drop(), m.load().catch(() => {
|
|
50
|
+
}), f.success(a("panel.saved"));
|
|
51
|
+
} catch (e) {
|
|
52
|
+
const r = e.body;
|
|
53
|
+
r?.errors && Object.keys(r.errors).length > 0 ? (E.value = r.errors, f.danger(a("panel.save-failed"))) : f.danger(S(e));
|
|
54
|
+
} finally {
|
|
55
|
+
v.value = !1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function ee() {
|
|
60
|
+
const e = l.value;
|
|
61
|
+
if (!(!e || !await F({
|
|
62
|
+
title: a("panel.delete-category-title", { name: e.name }),
|
|
63
|
+
message: a("panel.delete-category-text"),
|
|
64
|
+
confirmText: a("panel.delete"),
|
|
65
|
+
cancelText: a("panel.cancel"),
|
|
66
|
+
tone: "danger"
|
|
67
|
+
})))
|
|
68
|
+
try {
|
|
69
|
+
await C.removeCategory(e.id), m.drop(), f.success(a("panel.category-deleted")), k.value = D.value, B.push(y.value);
|
|
70
|
+
} catch (d) {
|
|
71
|
+
f.danger(S(d));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function P(e) {
|
|
75
|
+
b.value && e.preventDefault();
|
|
76
|
+
}
|
|
77
|
+
function j(e) {
|
|
78
|
+
(e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "s" && (e.preventDefault(), b.value && O());
|
|
79
|
+
}
|
|
80
|
+
fe(j), le(N, () => {
|
|
81
|
+
M();
|
|
82
|
+
}), oe(() => {
|
|
83
|
+
M(), window.addEventListener("beforeunload", P);
|
|
84
|
+
}), re(() => {
|
|
85
|
+
window.removeEventListener("beforeunload", P);
|
|
86
|
+
}), ce(async () => !b.value || !h.value ? !0 : await F({
|
|
87
|
+
title: a("panel.leave-title"),
|
|
88
|
+
message: a("panel.leave-text"),
|
|
89
|
+
confirmText: a("panel.leave"),
|
|
90
|
+
cancelText: a("panel.cancel"),
|
|
91
|
+
tone: "danger"
|
|
92
|
+
}));
|
|
93
|
+
const ae = o(() => {
|
|
94
|
+
const e = l.value, r = [];
|
|
95
|
+
return e && (e.url && e.visible && r.push({ key: "site", label: a("panel.open-on-site"), icon: "link", href: e.url }), r.push({
|
|
96
|
+
key: "products",
|
|
97
|
+
label: a("panel.show-products"),
|
|
98
|
+
icon: "list",
|
|
99
|
+
menu: !0,
|
|
100
|
+
run: () => {
|
|
101
|
+
B.push({
|
|
102
|
+
path: `${L.base}/products`,
|
|
103
|
+
query: { "f.category": String(e.id) }
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}), Q.value && r.push({
|
|
107
|
+
key: "delete",
|
|
108
|
+
label: a("panel.delete"),
|
|
109
|
+
icon: "trash",
|
|
110
|
+
danger: !0,
|
|
111
|
+
menu: !0,
|
|
112
|
+
run: () => {
|
|
113
|
+
ee();
|
|
114
|
+
}
|
|
115
|
+
})), r;
|
|
116
|
+
});
|
|
117
|
+
return (e, r) => (c(), w("div", {
|
|
118
|
+
class: "wx-catalog-category-editor",
|
|
119
|
+
onKeydown: j
|
|
120
|
+
}, [
|
|
121
|
+
W.value || !l.value ? (c(), w(T, { key: 0 }, [
|
|
122
|
+
s(t(H), {
|
|
123
|
+
class: "wx-catalog-category-editor__ghost",
|
|
124
|
+
title: "",
|
|
125
|
+
rows: 1
|
|
126
|
+
}),
|
|
127
|
+
s(t(he), null, {
|
|
128
|
+
default: n(() => [
|
|
129
|
+
s(t(H), { rows: 6 })
|
|
130
|
+
]),
|
|
131
|
+
_: 1
|
|
132
|
+
})
|
|
133
|
+
], 64)) : (c(), w(T, { key: 1 }, [
|
|
134
|
+
s(t(me), {
|
|
135
|
+
divider: "",
|
|
136
|
+
back: y.value,
|
|
137
|
+
"back-label": t(a)("module.categories"),
|
|
138
|
+
title: K.value,
|
|
139
|
+
subtitle: Y.value,
|
|
140
|
+
actions: ae.value
|
|
141
|
+
}, {
|
|
142
|
+
trail: n(() => [
|
|
143
|
+
s(t(we), {
|
|
144
|
+
size: "sm",
|
|
145
|
+
label: t(a)("panel.category-trail")
|
|
146
|
+
}, {
|
|
147
|
+
default: n(() => [
|
|
148
|
+
s(t(V), {
|
|
149
|
+
as: "router-link",
|
|
150
|
+
to: y.value
|
|
151
|
+
}, {
|
|
152
|
+
default: n(() => [
|
|
153
|
+
g(p(t(a)("module.categories")), 1)
|
|
154
|
+
]),
|
|
155
|
+
_: 1
|
|
156
|
+
}, 8, ["to"]),
|
|
157
|
+
(c(!0), w(T, null, ne(Z.value, (d) => (c(), _(t(V), {
|
|
158
|
+
key: d.id,
|
|
159
|
+
as: "router-link",
|
|
160
|
+
to: `${y.value}/${d.id}`
|
|
161
|
+
}, {
|
|
162
|
+
default: n(() => [
|
|
163
|
+
g(p(d.name), 1)
|
|
164
|
+
]),
|
|
165
|
+
_: 2
|
|
166
|
+
}, 1032, ["to"]))), 128)),
|
|
167
|
+
s(t(V), { current: "" }, {
|
|
168
|
+
default: n(() => [
|
|
169
|
+
g(p(K.value), 1)
|
|
170
|
+
]),
|
|
171
|
+
_: 1
|
|
172
|
+
})
|
|
173
|
+
]),
|
|
174
|
+
_: 1
|
|
175
|
+
}, 8, ["label"])
|
|
176
|
+
]),
|
|
177
|
+
"title-after": n(() => [
|
|
178
|
+
l.value.is_published ? l.value.visible ? z("", !0) : (c(), _(t(I), {
|
|
179
|
+
key: 1,
|
|
180
|
+
type: "warning",
|
|
181
|
+
dot: ""
|
|
182
|
+
}, {
|
|
183
|
+
default: n(() => [
|
|
184
|
+
g(p(t(a)("panel.category-hidden")), 1)
|
|
185
|
+
]),
|
|
186
|
+
_: 1
|
|
187
|
+
})) : (c(), _(t(I), {
|
|
188
|
+
key: 0,
|
|
189
|
+
dot: ""
|
|
190
|
+
}, {
|
|
191
|
+
default: n(() => [
|
|
192
|
+
g(p(t(a)("states.unpublished")), 1)
|
|
193
|
+
]),
|
|
194
|
+
_: 1
|
|
195
|
+
}))
|
|
196
|
+
]),
|
|
197
|
+
_: 1
|
|
198
|
+
}, 8, ["back", "back-label", "title", "subtitle", "actions"]),
|
|
199
|
+
s(t(ye), {
|
|
200
|
+
modelValue: i.value,
|
|
201
|
+
"onUpdate:modelValue": r[0] || (r[0] = (d) => i.value = d),
|
|
202
|
+
name: "catalog.category-form",
|
|
203
|
+
errors: E.value,
|
|
204
|
+
disabled: A.value
|
|
205
|
+
}, null, 8, ["modelValue", "errors", "disabled"]),
|
|
206
|
+
h.value ? (c(), _(t(_e), { key: 0 }, {
|
|
207
|
+
state: n(() => [
|
|
208
|
+
s(t(be), { state: X.value }, null, 8, ["state"])
|
|
209
|
+
]),
|
|
210
|
+
default: n(() => [
|
|
211
|
+
s(t(Ce), {
|
|
212
|
+
type: "primary",
|
|
213
|
+
loading: v.value,
|
|
214
|
+
disabled: !b.value,
|
|
215
|
+
onClick: O
|
|
216
|
+
}, {
|
|
217
|
+
default: n(() => [
|
|
218
|
+
g(p(t(a)("panel.save")), 1)
|
|
219
|
+
]),
|
|
220
|
+
_: 1
|
|
221
|
+
}, 8, ["loading", "disabled"])
|
|
222
|
+
]),
|
|
223
|
+
_: 1
|
|
224
|
+
})) : z("", !0)
|
|
225
|
+
], 64))
|
|
226
|
+
], 32));
|
|
227
|
+
}
|
|
228
|
+
}), Me = /* @__PURE__ */ Ve(Le, [["__scopeId", "data-v-45d5817b"]]);
|
|
229
|
+
export {
|
|
230
|
+
Me as default
|
|
231
|
+
};
|
|
232
|
+
//# sourceMappingURL=CategoryEditorPage-y6EFmOof.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CategoryEditorPage-y6EFmOof.js","sources":["../src/CategoryEditorPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'\nimport {\n provideHistorySubject,\n provideRecordAddress,\n useAdmin,\n useBodyKeys,\n useErrorText,\n useTranslate,\n WxSaveState,\n WxScreen,\n WxScreenHead,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n localizedValue,\n toast,\n useLocales,\n WxActionBar,\n WxBadge,\n WxBreadcrumb,\n WxBreadcrumbItem,\n WxButton,\n WxCard,\n WxSkeleton,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport type { ScreenModel } from '@webx-ui/schema'\nimport { createCatalogApi } from './api'\nimport { provideCatalogCategoryEditor } from './editor'\nimport { useCatalogMessages } from './i18n'\nimport { lastSegment } from './paths'\nimport { ancestry, useCategoryTree } from './store'\nimport type { CategoryDetail, CategoryRow } from './types'\n\n/**\n * One category of the catalogue: a head, `catalog.category-form` under it, and one button.\n *\n * The shared category editor of the panel (`WxCategoryEditorPage`) is for flat lists with a\n * prefix; this one sits in a tree, at the root of the site (§4), and its trail is the branch it\n * hangs from. The «Filters» tab reads which category this is from here, to say whose setting it\n * inherits (§6.2).\n */\ndefineOptions({ name: 'WxCatalogCategoryEditor' })\n\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/catalog' })\n\nconst context = useAdmin()\nconst api = createCatalogApi(context)\nconst tree = useCategoryTree(context)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst id = computed(() => Number(route.params.id))\nconst list = computed(() => `${props.base}/categories`)\n\nconst category = ref<CategoryRow | null>(null)\nconst facetsFrom = ref<CategoryDetail['facets_from']>(undefined)\nconst values = ref<ScreenModel>({})\nconst snapshot = ref('')\n\nconst loading = ref(true)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nconst canManage = computed(() => context.can('catalog.manage'))\nconst canDelete = computed(() => context.can('catalog.delete'))\nconst locked = computed(() => !canManage.value || saving.value)\n\nconst current = computed(() => JSON.stringify(values.value))\nconst dirty = computed(() => snapshot.value !== '' && current.value !== snapshot.value)\n\nconst state = computed<'saving' | 'unsaved' | 'saved'>(() => {\n if (saving.value) return 'saving'\n\n return dirty.value ? 'unsaved' : 'saved'\n})\n\n/** The name follows the field rather than the answer: a rename shows at the top as it is typed. */\nconst title = computed(() => {\n const written = values.value.name as LocalizedValue | string | null | undefined\n\n return (\n localizedValue(written, locales.active.value, category.value?.name ?? '') || t('panel.untitled')\n )\n})\n\n/** Where it answers, as a reader would type it: `/laptops/`. */\nconst address = computed(() => {\n const segment = lastSegment(category.value?.url)\n\n return segment === null ? undefined : `/${segment}/`\n})\n\n/** The categories above this one, from the top down. */\nconst parents = computed(() =>\n category.value\n ? ancestry(tree.nodes.value ?? [], category.value.id)\n .slice(1)\n .reverse()\n : [],\n)\n\nprovideCatalogCategoryEditor({ category, locked, facetsFrom })\nprovideHistorySubject({ id: computed(() => category.value?.id ?? null) })\n\n/* The address of a category is flat at the root of the site at any depth (decision 23). */\nprovideRecordAddress({\n values,\n prefix: ref(''),\n path: computed(() => lastSegment(category.value?.url)),\n moving: () => t('panel.address-moving'),\n})\n\nfunction take(detail: CategoryDetail): void {\n category.value = detail.category\n facetsFrom.value = detail.facets_from\n values.value = detail.values\n snapshot.value = JSON.stringify(detail.values)\n}\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n const [detail] = await Promise.all([api.category(id.value), tree.load().catch(() => [])])\n\n take(detail)\n } catch (error) {\n toast.danger(message(error))\n void router.push(list.value)\n } finally {\n loading.value = false\n }\n}\n\nasync function save(): Promise<void> {\n if (!category.value || saving.value || !canManage.value) return\n\n saving.value = true\n errors.value = {}\n\n try {\n take(await api.saveCategory(category.value.id, values.value))\n // A name, a publication or an address: every picker of the catalogue shows one of them.\n tree.drop()\n void tree.load().catch(() => undefined)\n toast.success(t('panel.saved'))\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors && Object.keys(body.errors).length > 0) {\n errors.value = body.errors\n toast.danger(t('panel.save-failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n\nasync function remove(): Promise<void> {\n const row = category.value\n\n if (!row) return\n\n const agreed = await confirm({\n title: t('panel.delete-category-title', { name: row.name }),\n message: t('panel.delete-category-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removeCategory(row.id)\n tree.drop()\n toast.success(t('panel.category-deleted'))\n snapshot.value = current.value\n void router.push(list.value)\n } catch (error) {\n // \"Not empty: products in it: 12\" — the server's sentence is the one worth reading here.\n toast.danger(message(error))\n }\n}\n\n/* The browser's own guard: it cannot wait for a request, so all it can do is ask. */\nfunction leaveGuard(event: BeforeUnloadEvent): void {\n if (dirty.value) event.preventDefault()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 's') {\n event.preventDefault()\n if (dirty.value) void save()\n }\n}\n\nuseBodyKeys(onKeydown)\n\nwatch(id, () => void load())\n\nonMounted(() => {\n void load()\n window.addEventListener('beforeunload', leaveGuard)\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('beforeunload', leaveGuard)\n})\n\nonBeforeRouteLeave(async () => {\n if (!dirty.value || !canManage.value) return true\n\n return await confirm({\n title: t('panel.leave-title'),\n message: t('panel.leave-text'),\n confirmText: t('panel.leave'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n})\n\nconst actions = computed<ScreenAction[]>(() => {\n const row = category.value\n const leads: ScreenAction[] = []\n\n if (!row) return leads\n\n // A hidden category answers 404; a link to that would be a link to an error page.\n if (row.url && row.visible) {\n leads.push({ key: 'site', label: t('panel.open-on-site'), icon: 'link', href: row.url })\n }\n\n leads.push({\n key: 'products',\n label: t('panel.show-products'),\n icon: 'list',\n menu: true,\n run: () =>\n void router.push({\n path: `${props.base}/products`,\n query: { 'f.category': String(row.id) },\n }),\n })\n\n if (canDelete.value) {\n leads.push({\n key: 'delete',\n label: t('panel.delete'),\n icon: 'trash',\n danger: true,\n menu: true,\n run: () => void remove(),\n })\n }\n\n return leads\n})\n</script>\n\n<template>\n <div class=\"wx-catalog-category-editor\" @keydown=\"onKeydown\">\n <template v-if=\"loading || !category\">\n <wx-skeleton class=\"wx-catalog-category-editor__ghost\" title :rows=\"1\" />\n <wx-card><wx-skeleton :rows=\"6\" /></wx-card>\n </template>\n\n <template v-else>\n <wx-screen-head\n divider\n :back=\"list\"\n :back-label=\"t('module.categories')\"\n :title=\"title\"\n :subtitle=\"address\"\n :actions=\"actions\"\n >\n <template #trail>\n <wx-breadcrumb size=\"sm\" :label=\"t('panel.category-trail')\">\n <wx-breadcrumb-item :as=\"'router-link'\" :to=\"list\">\n {{ t('module.categories') }}\n </wx-breadcrumb-item>\n <wx-breadcrumb-item\n v-for=\"parent in parents\"\n :key=\"parent.id\"\n :as=\"'router-link'\"\n :to=\"`${list}/${parent.id}`\"\n >\n {{ parent.name }}\n </wx-breadcrumb-item>\n <wx-breadcrumb-item current>{{ title }}</wx-breadcrumb-item>\n </wx-breadcrumb>\n </template>\n\n <template #title-after>\n <wx-badge v-if=\"!category.is_published\" dot>{{ t('states.unpublished') }}</wx-badge>\n <wx-badge v-else-if=\"!category.visible\" type=\"warning\" dot>\n {{ t('panel.category-hidden') }}\n </wx-badge>\n </template>\n </wx-screen-head>\n\n <wx-screen\n v-model=\"values\"\n name=\"catalog.category-form\"\n :errors=\"errors\"\n :disabled=\"locked\"\n />\n\n <wx-action-bar v-if=\"canManage\">\n <template #state>\n <wx-save-state :state=\"state\" />\n </template>\n\n <wx-button type=\"primary\" :loading=\"saving\" :disabled=\"!dirty\" @click=\"save\">\n {{ t('panel.save') }}\n </wx-button>\n </wx-action-bar>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-catalog-category-editor {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n container-type: inline-size;\n}\n\n.wx-catalog-category-editor__ghost {\n max-width: 420px;\n}\n</style>\n"],"names":["props","__props","context","useAdmin","api","createCatalogApi","tree","useCategoryTree","route","useRoute","router","useRouter","locales","useLocales","useCatalogMessages","t","useTranslate","message","useErrorText","id","computed","list","category","ref","facetsFrom","values","snapshot","loading","saving","errors","canManage","canDelete","locked","current","dirty","state","title","written","localizedValue","address","segment","lastSegment","parents","ancestry","provideCatalogCategoryEditor","provideHistorySubject","provideRecordAddress","take","detail","load","error","toast","save","body","remove","row","confirm","leaveGuard","event","onKeydown","useBodyKeys","watch","onMounted","onBeforeUnmount","onBeforeRouteLeave","actions","leads","_createElementBlock","_Fragment","_createVNode","_unref","WxSkeleton","WxCard","WxScreenHead","WxBreadcrumb","WxBreadcrumbItem","_renderList","parent","_createBlock","_createTextVNode","_toDisplayString","WxBadge","WxScreen","$event","WxActionBar","WxSaveState","WxButton"],"mappings":"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"}
|