@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.
@@ -0,0 +1,2571 @@
1
+ import { computed as P, ref as M, defineComponent as Y, useModel as Le, onMounted as de, openBlock as h, createBlock as U, unref as l, mergeProps as wt, mergeModels as Qe, provide as Ze, inject as et, watch as kt, createElementBlock as W, Fragment as H, createElementVNode as N, createVNode as _, withCtx as f, createTextVNode as A, toDisplayString as S, createCommentVNode as j, normalizeClass as Ne, getCurrentScope as _t, onScopeDispose as $t, readonly as Tt, useTemplateRef as ye, nextTick as Te, isRef as Ce, withKeys as le, withModifiers as pe, renderList as me, onBeforeUnmount as tt, h as Ct, defineAsyncComponent as ee } from "vue";
2
+ import { useAdmin as Q, readCookie as St, useRecordAddress as Pt, useTranslate as te, useChunkedUpload as Vt, useErrorText as Se, uploadFingerprint as ke, unfinishedUploads as At, forgetUnfinishedUpload as Et, WxRowMenu as Wt, useCategoryEditor as Ut, categoryRoutes as Mt } from "@webx-ui/module-admin";
3
+ import { WxTreeSelect as at, WxSkeleton as lt, WxAlert as _e, WxSwitch as je, WxText as X, WxSortableList as ot, toast as B, useModal as Pe, WxDialog as Ve, WxFormItem as oe, WxInput as ge, WxSpace as Ae, WxButton as D, useLocales as xe, WxProgress as De, createModal as It, WxBadge as $e, WxUpload as Rt, WxCard as Ft, confirm as Be, localizedValue as Lt, WxSelect as Nt, WxCheckboxGroup as Ge, WxSegmented as zt } from "@webx-ui/core";
4
+ const Ot = {
5
+ module: {
6
+ title: "Products",
7
+ group: "Catalog",
8
+ products: "Products",
9
+ categories: "Categories",
10
+ dictionaries: "Dictionaries",
11
+ deleted: "Deleted",
12
+ product: "Product",
13
+ category: "Category"
14
+ },
15
+ states: {
16
+ published: "Published",
17
+ unpublished: "Unpublished",
18
+ deleted: "Deleted"
19
+ },
20
+ product: {
21
+ name: "Name",
22
+ slug: "Address",
23
+ sku: "Article number",
24
+ barcode: "Barcode",
25
+ summary: "Summary",
26
+ description: "Description",
27
+ category_id: "Main category",
28
+ category: "Main category",
29
+ categories: "Additional categories",
30
+ price: "Price",
31
+ old_price: "Old price",
32
+ unit: "Unit",
33
+ priority: "Priority",
34
+ is_published: "Published",
35
+ images: "Pictures",
36
+ "no-category": "No category"
37
+ },
38
+ category: {
39
+ name: "Name",
40
+ slug: "Address",
41
+ description: "Text",
42
+ cover: "Picture",
43
+ cover_id: "Picture",
44
+ is_published: "Published",
45
+ parent: "Parent category",
46
+ facets: "Filters"
47
+ },
48
+ units: {
49
+ pcs: "pcs",
50
+ kg: "kg",
51
+ g: "g",
52
+ m: "m",
53
+ m2: "m²",
54
+ m3: "m³",
55
+ l: "l",
56
+ pack: "pack",
57
+ set: "set"
58
+ },
59
+ panel: {
60
+ create: "Create",
61
+ cancel: "Cancel",
62
+ save: "Save",
63
+ saved: "Saved.",
64
+ "save-failed": "Not saved: what is wrong is said under the fields in red.",
65
+ untitled: "Untitled",
66
+ open: "Open",
67
+ "open-on-site": "Open on the site",
68
+ publish: "Publish",
69
+ unpublish: "Take off the site",
70
+ delete: "Delete",
71
+ restore: "Restore",
72
+ "leave-title": "Leave without saving?",
73
+ "leave-text": "What you changed is not on the server.",
74
+ leave: "Leave",
75
+ "address-moving": "The address is changing. The old one keeps working and leads to the new one.",
76
+ "new-product": "New product",
77
+ "search-products": "Search by name or article number",
78
+ "empty-products": "No products yet.",
79
+ "empty-products-help": "A product lives in one main category and any number of others.",
80
+ "empty-search": "Nothing matches that.",
81
+ "search-corrected": "Showing results for :corrected.",
82
+ "search-instead": "Search instead for :q",
83
+ outgrown: "The catalogue has outgrown the database engine, and filters and search will slow down. Live products: :live, the engine is meant for :limit. Install module-catalog-manticore.",
84
+ "fell-back": "The search index is not answering: the list comes from the database, and the search finds words as typed.",
85
+ "view-all": "All",
86
+ "view-published": "Published",
87
+ "view-unpublished": "Unpublished",
88
+ "view-no-category": "No category",
89
+ "column-product": "Product",
90
+ "column-state": "State",
91
+ "column-updated": "Changed",
92
+ invisible: "Published, but no category of it is on the site, so nobody sees it.",
93
+ sort: "Order",
94
+ "sort-default": "By priority, then newest",
95
+ "range-from": "From",
96
+ "range-to": "To",
97
+ any: "Any",
98
+ selected: "Selected: :count",
99
+ "select-clear": "Clear the selection",
100
+ "bulk-actions": "Actions",
101
+ "select-all-found": "Select everything found: :count",
102
+ "selected-all": "Selected everything found: :count",
103
+ "bulk-apply": "Apply",
104
+ "bulk-param-empty": "Nothing — takes it off",
105
+ "bulk-confirm-title": "Apply «:action»?",
106
+ "bulk-confirm-text": "Products it applies to: :count",
107
+ "bulk-running": "Running in the background. Done :done of :total",
108
+ "bulk-done": "Done. Products: :count",
109
+ "bulk-refused": "Refused: :count",
110
+ "bulk-stopped": "The run stopped. Done so far: :count",
111
+ "bulk-errors": "What was refused",
112
+ "bulk-close": "Close",
113
+ "bulk-nothing": "None of the selected products fit this action.",
114
+ "product-trail": "Where this product sits",
115
+ "delete-product-title": "Delete “:name”?",
116
+ "delete-product-text": "It goes to «Deleted» and comes off the site. Its address leads to its category from then on.",
117
+ "product-deleted": "The product is in «Deleted».",
118
+ "product-restored": "The product is back.",
119
+ "product-restored-bare": "The product is back without a category and unpublished: its category is deleted.",
120
+ "product-published": "The product is on the site.",
121
+ "product-unpublished": "The product is off the site.",
122
+ "sku-open": "Open that product",
123
+ "sku-open-deleted": "Find it in «Deleted»",
124
+ "gallery-add": "Add pictures",
125
+ "gallery-hint": "JPEG, PNG, WebP or GIF. The first picture is the main one.",
126
+ "gallery-url": "Upload from an address",
127
+ "gallery-url-add": "Fetch",
128
+ "gallery-empty": "No pictures yet.",
129
+ "gallery-main": "Main",
130
+ "gallery-alt": "Alternative text",
131
+ "gallery-alt-help": "What the picture shows, for search engines and screen readers.",
132
+ "gallery-title": "Title",
133
+ "gallery-order": "Drag to change the order. The first picture is the main one.",
134
+ "gallery-failed": "The picture was not added.",
135
+ "gallery-remove-title": "Delete this picture?",
136
+ "gallery-remove-text": "The file is deleted from the disk at once.",
137
+ "gallery-removed": "The picture is deleted.",
138
+ "gallery-reorder-failed": "The new order was not saved.",
139
+ "gallery-captions-failed": "The captions were not saved.",
140
+ "gallery-locked": "Pictures are added to a product you may edit.",
141
+ "gallery-add-video": "Add pictures or videos",
142
+ "gallery-hint-video": "JPEG, PNG, WebP or GIF pictures, MP4 or WebM videos. The first picture is the main one.",
143
+ "gallery-wrong-type": "Only JPEG, PNG, WebP and GIF pictures go into the gallery.",
144
+ "gallery-wrong-type-video": "Only JPEG, PNG, WebP and GIF pictures and MP4 and WebM videos go into the gallery.",
145
+ "gallery-url-hint": "The address of a JPEG, PNG, WebP or GIF picture.",
146
+ "gallery-url-hint-video": "The address of a picture, a YouTube link, or a direct link to an MP4 or WebM file.",
147
+ "video-badge": "Has a video",
148
+ "video-open": "Open the video",
149
+ "video-attach": "Attach",
150
+ "video-attach-file": "Attach a video file…",
151
+ "video-attach-link": "Attach a YouTube link…",
152
+ "video-attached": "The video is attached.",
153
+ "video-remove": "Remove the video",
154
+ "video-remove-title": "Remove the video?",
155
+ "video-remove-file-text": "The video file is deleted from the disk at once. The picture stays.",
156
+ "video-remove-link-text": "The link to the video is dropped. The picture stays.",
157
+ "video-removed": "The video is removed.",
158
+ "video-link-title": "Attach a video by its link",
159
+ "video-link": "Link",
160
+ "video-link-help": "A YouTube link, or a direct link to an MP4 or WebM file.",
161
+ "video-link-wrong": "This is neither a YouTube link nor a link to an MP4 or WebM file.",
162
+ "video-queued": "The video is downloading on the server. It appears in the gallery when it is done — open the product again then.",
163
+ "video-wrong-type": "Only MP4 and WebM videos.",
164
+ "video-too-large": "The video is larger than :max.",
165
+ "video-unreadable": "The browser cannot open this video, so there is no frame for a cover. Add a picture and attach the video to it.",
166
+ "video-placeholder": "A plain cover. For a frame of the video: add a picture, attach the same link to it and delete this row.",
167
+ "video-waiting": "Waits for the video before it.",
168
+ "video-poster": "Taking a frame for the cover…",
169
+ "video-attaching": "Attaching the video…",
170
+ "video-uploading": "Uploading :name",
171
+ "video-sent": ":sent of :total",
172
+ "video-left": "Time left: :time",
173
+ "video-paused": "Paused",
174
+ "video-offline": "Offline — continues when the connection is back",
175
+ "video-pause": "Pause",
176
+ "video-resume": "Resume",
177
+ "video-retry": "Try again",
178
+ "video-dismiss": "Dismiss",
179
+ "video-unfinished": "The upload of :name did not finish: :sent of :total. Choose the same file to continue.",
180
+ "video-choose-again": "Choose the file…",
181
+ "video-forget": "Forget",
182
+ "video-other-file": "That is another file. Choose :name (:size) to continue.",
183
+ "video-leave-title": "Leave during the upload?",
184
+ "video-leave-text": "The video stops going up. Choose the same file on this product again to continue where it stopped.",
185
+ "new-category": "New category",
186
+ "add-child": "Add a subcategory",
187
+ "search-categories": "Search by name or address",
188
+ "empty-categories": "No categories yet.",
189
+ "empty-categories-help": "Categories are the shelves of the catalogue; each has an address of its own at the root of the site.",
190
+ "column-products": "Products",
191
+ "category-hidden": "Hidden: a category above it is unpublished.",
192
+ "category-order": "Drag to move a category. Its address stays the same.",
193
+ "category-moved": "The category is moved.",
194
+ "category-trail": "Where this category sits",
195
+ "field-parent": "Inside",
196
+ "parent-root": "At the top level",
197
+ "show-products": "Show its products",
198
+ "delete-category-title": "Delete “:name”?",
199
+ "delete-category-text": "It goes to «Deleted», and its address answers that it is gone.",
200
+ "category-deleted": "The category is in «Deleted».",
201
+ "category-restored": "The category is back.",
202
+ "category-published": "The category is on the site.",
203
+ "category-unpublished": "The category and everything under it is off the site.",
204
+ "pick-category": "Choose a category",
205
+ "pick-categories": "Choose categories",
206
+ "category-gone": "deleted",
207
+ "facets-own": "Own setting",
208
+ "facets-own-help": "Which filters this category shows, and in which order.",
209
+ "facets-inherited": "As in “:name”",
210
+ "facets-default": "All filters, in their default order",
211
+ "facets-inherited-help": "Switch it on to choose for this category. Categories under it take the setting unless they have their own.",
212
+ "facets-empty": "No filters are installed.",
213
+ "facets-failed": "The list of filters did not load.",
214
+ "facets-shown": "Shown",
215
+ "facets-unknown": "Its module is not installed",
216
+ "deleted-search": "Search by name",
217
+ "deleted-empty": "Nothing is deleted.",
218
+ "deleted-help": "A deleted product keeps its pictures and comes back under its old address.",
219
+ "column-deleted": "Deleted",
220
+ "column-parent": "Was inside",
221
+ "restore-bare": "Comes back without a category",
222
+ "exchange-title": "Exchange",
223
+ "exchange-help": "Products in and out as CSV or XLSX files. Every run stays here with what it did.",
224
+ "exchange-import": "Import",
225
+ "exchange-export": "Export",
226
+ "exchange-profiles": "Profiles",
227
+ "exchange-empty": "Nothing has been imported or exported yet.",
228
+ "exchange-column-run": "Run",
229
+ "exchange-column-status": "Status",
230
+ "exchange-column-result": "Result",
231
+ "exchange-column-started": "Started",
232
+ "exchange-check": "Check",
233
+ "exchange-check-help": "A check: nothing was written.",
234
+ "exchange-status-queued": "Waiting",
235
+ "exchange-status-running": "Running",
236
+ "exchange-status-done": "Done",
237
+ "exchange-status-stopped": "Stopped",
238
+ "exchange-status-failed": "Failed",
239
+ "exchange-stopped-help": "Too many errors: the run stopped. What was written before stays, and products absent from the file were left alone.",
240
+ "exchange-failed-help": "The run broke off. What was written before stays.",
241
+ "exchange-progress": "Rows: :done of :total",
242
+ "exchange-created": "Created: :count",
243
+ "exchange-updated": "Updated: :count",
244
+ "exchange-skipped": "Skipped: :count",
245
+ "exchange-errors-count": "Errors: :count",
246
+ "exchange-absent": "Taken off the site: :count",
247
+ "exchange-exported": "Products: :count",
248
+ "exchange-source": "File",
249
+ "exchange-profile": "Profile",
250
+ "exchange-who": "Started by",
251
+ "exchange-errors": "Errors",
252
+ "exchange-errors-more": "Only the first errors are here. The file has all of them.",
253
+ "exchange-errors-csv": "Download all errors as CSV",
254
+ "exchange-error-row": "Row",
255
+ "exchange-error-column": "Column",
256
+ "exchange-error-value": "Value",
257
+ "exchange-error-message": "Reason",
258
+ "exchange-error-whole-row": "the row",
259
+ "exchange-file": "Download the file",
260
+ "exchange-file-gone": "The file is no longer kept.",
261
+ "exchange-journal": "Changes in the journal",
262
+ "exchange-journal-title": "What the run changed",
263
+ "exchange-journal-empty": "Nothing changed.",
264
+ "exchange-journal-more": "Show more",
265
+ "exchange-import-title": "Import products",
266
+ "exchange-import-help": "A CSV or XLSX file whose first row names the columns.",
267
+ "exchange-step-file": "File",
268
+ "exchange-step-file-help": "CSV or XLSX",
269
+ "exchange-step-mapping": "Columns",
270
+ "exchange-step-mapping-help": "What goes where",
271
+ "exchange-step-settings": "Settings",
272
+ "exchange-step-settings-help": "How to write it",
273
+ "exchange-source-upload": "Upload",
274
+ "exchange-source-url": "By address",
275
+ "exchange-choose-file": "Choose a file",
276
+ "exchange-file-help": "A large file goes up in pieces and carries on after a dropped connection.",
277
+ "exchange-url": "Address of the file",
278
+ "exchange-url-help": "The server downloads it itself. A price list of a supplier, for one.",
279
+ "exchange-read": "Read the file",
280
+ "exchange-reread": "Read again",
281
+ "exchange-uploading": "Uploading",
282
+ "exchange-pause": "Pause",
283
+ "exchange-resume": "Resume",
284
+ "exchange-cancel": "Cancel",
285
+ "exchange-read-as": "Read as",
286
+ "exchange-encoding": "Encoding",
287
+ "exchange-delimiter": "Separator",
288
+ "exchange-delimiter-tab": "Tab",
289
+ "exchange-detect": "Detect",
290
+ "exchange-map-file": "Column of the file",
291
+ "exchange-map-catalog": "Column of the catalogue",
292
+ "exchange-map-skip": "Do not import",
293
+ "exchange-map-key": "Key",
294
+ "exchange-map-key-missing": "The key column «:key» is not among the columns of the file. Map it or choose another key in the settings.",
295
+ "exchange-map-empty": "The file has no header row.",
296
+ "exchange-map-sample": "First rows",
297
+ "exchange-map-mapped": "Columns to import: :count",
298
+ "exchange-back": "Back",
299
+ "exchange-next": "Next",
300
+ "exchange-run": "Run the import",
301
+ "exchange-run-check": "Check without writing",
302
+ "exchange-check-first": "This profile has not run yet: check the file first.",
303
+ "exchange-save-profile": "Save as profile",
304
+ "exchange-profile-name": "Name of the profile",
305
+ "exchange-profile-saved": "The profile is saved.",
306
+ "exchange-use-profile": "Profile",
307
+ "exchange-use-profile-none": "Map the columns by hand",
308
+ "exchange-started": "The import has started.",
309
+ "exchange-checked": "The check has started.",
310
+ "exchange-export-title": "Export products",
311
+ "exchange-export-selected": "Products: :count",
312
+ "exchange-export-all": "The whole catalogue, except «Deleted».",
313
+ "exchange-export-columns": "Columns",
314
+ "exchange-export-columns-help": "In the order the file will have them.",
315
+ "exchange-export-languages": "Translations",
316
+ "exchange-export-languages-help": "A translated column gets one more column per language: name@de.",
317
+ "exchange-export-start": "Export",
318
+ "exchange-export-started": "The export has started. The file will be in «Exchange».",
319
+ "exchange-export-none": "Choose at least one column.",
320
+ "exchange-export-pick": "Choose the columns here",
321
+ "exchange-format": "Format",
322
+ "exchange-profiles-title": "Exchange profiles",
323
+ "exchange-profiles-help": "Saved columns and settings, to bring in the same file again in one step.",
324
+ "exchange-profiles-empty": "No profiles yet.",
325
+ "exchange-new-import-profile": "New import profile",
326
+ "exchange-new-export-profile": "New export profile",
327
+ "exchange-profile-new": "New profile",
328
+ "exchange-profile-direction": "Direction",
329
+ "exchange-profile-last-run": "Last run",
330
+ "exchange-profile-mapping": "Columns of the file",
331
+ "exchange-profile-mapping-help": "The header a file has, and the column of the catalogue it goes into.",
332
+ "exchange-profile-header": "Header in the file",
333
+ "exchange-profile-add": "Add a column",
334
+ "exchange-profile-remove": "Remove",
335
+ "exchange-profile-run": "Import with it",
336
+ "exchange-profile-delete-title": "Delete «:name»?",
337
+ "exchange-profile-delete-text": "The runs made with it stay in the list.",
338
+ "exchange-profile-deleted": "The profile is deleted.",
339
+ "exchange-save": "Save",
340
+ "exchange-delete": "Delete",
341
+ "exchange-profile-edit": "Edit",
342
+ "exchange-profile-up": "Move up",
343
+ "exchange-profile-down": "Move down"
344
+ }
345
+ }, He = /* @__PURE__ */ new WeakSet();
346
+ function ce() {
347
+ try {
348
+ const { i18n: e } = Q();
349
+ He.has(e) || (e.defaults("webx-catalog", Ot), He.add(e));
350
+ } catch {
351
+ }
352
+ }
353
+ const nt = "catalog";
354
+ function jt(e) {
355
+ const t = new URLSearchParams();
356
+ e.q && t.set("q", e.q), e.q && e.typed && t.set("typed", "1"), e.state && t.set("state", e.state), e.sort && e.sort !== "default" && t.set("sort", e.sort), e.page && e.page > 1 && t.set("page", String(e.page)), e.per_page && t.set("per_page", String(e.per_page));
357
+ for (const [o, r] of Object.entries(e.facets ?? {}))
358
+ if (r === !0)
359
+ t.set(`facets[${o}][]`, "1");
360
+ else if (Array.isArray(r))
361
+ for (const a of r) t.append(`facets[${o}][]`, String(a));
362
+ else
363
+ r.min != null && t.set(`facets[${o}][min]`, String(r.min)), r.max != null && t.set(`facets[${o}][max]`, String(r.max));
364
+ return t;
365
+ }
366
+ function Dt(e, t, o, r) {
367
+ const a = new FormData();
368
+ return a.append("file", o), new Promise((i, n) => {
369
+ const s = new XMLHttpRequest();
370
+ s.open("POST", t), s.responseType = "json", s.withCredentials = !0, s.setRequestHeader("Accept", "application/json"), s.setRequestHeader("X-Requested-With", "XMLHttpRequest"), s.setRequestHeader("X-Webx-Locale", e.i18n.state.locale);
371
+ const v = St("XSRF-TOKEN");
372
+ v && s.setRequestHeader("X-XSRF-TOKEN", v), s.upload.addEventListener("progress", (c) => {
373
+ c.lengthComputable && r?.(Math.round(c.loaded / c.total * 100));
374
+ }), s.addEventListener("load", () => {
375
+ const c = s.response;
376
+ if (s.status >= 200 && s.status < 300 && c?.data) {
377
+ i(c.data);
378
+ return;
379
+ }
380
+ n(
381
+ Object.assign(new Error(c?.message ?? "Upload failed"), {
382
+ status: s.status,
383
+ body: c
384
+ })
385
+ );
386
+ }), s.addEventListener("error", () => n(new Error("Upload failed"))), s.send(a);
387
+ });
388
+ }
389
+ function ne(e) {
390
+ const t = `${e.apiPath}/${nt}`, o = (a) => a.data, r = (a, i) => i.size > 0 ? `${a}?${i}` : a;
391
+ return {
392
+ products: (a = {}) => e.http.get(r(`${t}/products`, jt(a))),
393
+ product: (a) => e.http.get(`${t}/products/${a}`).then(o),
394
+ createProduct: (a) => e.http.post(`${t}/products`, { values: a }).then(o),
395
+ saveProduct: (a, i) => e.http.put(`${t}/products/${a}`, { values: i }).then(o),
396
+ removeProduct: (a) => e.http.delete(`${t}/products/${a}`).then(() => {
397
+ }),
398
+ restoreProduct: (a) => e.http.post(`${t}/products/${a}/restore`, {}).then(o),
399
+ addImage: (a, i, n) => typeof i == "string" ? e.http.post(`${t}/products/${a}/images`, { url: i }).then(o) : Dt(e, `${t}/products/${a}/images`, i, n),
400
+ saveImages: (a, i) => e.http.put(`${t}/products/${a}/images`, {
401
+ images: i.map(({ id: n, alt: s, title: v }) => ({ id: n, alt: s, title: v }))
402
+ }).then(o),
403
+ removeImage: (a, i) => e.http.delete(`${t}/products/${a}/images/${i}`).then(() => {
404
+ }),
405
+ fetchImage: (a, i) => e.http.post(`${t}/products/${a}/images`, { url: i }).then(o),
406
+ attachVideo: (a, i, n) => e.http.post(`${t}/products/${a}/images/${i}/video`, n).then(o),
407
+ detachVideo: (a, i) => e.http.delete(`${t}/products/${a}/images/${i}/video`).then(o),
408
+ categories: () => e.http.get(`${t}/categories`).then(o),
409
+ category: (a) => e.http.get(`${t}/categories/${a}`).then(o),
410
+ createCategory: (a, i) => e.http.post(`${t}/categories`, { values: a, parent_id: i }).then(o),
411
+ saveCategory: (a, i) => e.http.put(`${t}/categories/${a}`, { values: i }).then(o),
412
+ moveCategory: (a, i, n) => e.http.post(`${t}/categories/${a}/move`, {
413
+ parent_id: i,
414
+ before_id: n
415
+ }).then(o),
416
+ removeCategory: (a) => e.http.delete(`${t}/categories/${a}`).then(() => {
417
+ }),
418
+ restoreCategory: (a) => e.http.post(`${t}/categories/${a}/restore`, {}).then(o),
419
+ facets: () => e.http.get(`${t}/facets`).then((a) => ({ facets: a.data, sorts: a.meta?.sorts ?? [] })),
420
+ bulkActions: () => e.http.get(`${t}/bulk`).then(o),
421
+ startBulk: (a, i, n) => e.http.post(`${t}/bulk`, { action: a, params: i, selection: n }).then(o),
422
+ bulkRun: (a) => e.http.get(`${t}/bulk/${a}`).then(o),
423
+ deleted: ((a, i = {}) => {
424
+ const n = new URLSearchParams({ type: a });
425
+ return i.q && n.set("q", i.q), i.page && i.page > 1 && n.set("page", String(i.page)), i.per_page && n.set("per_page", String(i.per_page)), e.http.get(`${t}/deleted?${n}`);
426
+ })
427
+ };
428
+ }
429
+ const Xe = /* @__PURE__ */ new WeakMap();
430
+ function rt(e) {
431
+ let t = Xe.get(e);
432
+ return t || (t = {
433
+ tree: { value: M(null), pending: null },
434
+ facets: { value: M(null), pending: null }
435
+ }, Xe.set(e, t)), t;
436
+ }
437
+ function it(e, t, o) {
438
+ if (!o && e.value.value !== null) return Promise.resolve(e.value.value);
439
+ if (!o && e.pending) return e.pending;
440
+ const r = t().then((a) => (e.pending === r && (e.value.value = a), a)).finally(() => {
441
+ e.pending === r && (e.pending = null);
442
+ });
443
+ return e.pending = r, r;
444
+ }
445
+ function st(e) {
446
+ const t = rt(e).tree, o = ne(e);
447
+ return {
448
+ nodes: t.value,
449
+ load: (r = !1) => it(t, () => o.categories(), r),
450
+ take: (r) => {
451
+ t.pending = null, t.value.value = r;
452
+ },
453
+ drop: () => {
454
+ t.pending = null, t.value.value = null;
455
+ }
456
+ };
457
+ }
458
+ function Bt(e) {
459
+ const t = rt(e).facets, o = ne(e);
460
+ return {
461
+ facets: P(() => t.value.value?.facets ?? null),
462
+ sorts: P(() => t.value.value?.sorts ?? []),
463
+ load: () => it(
464
+ t,
465
+ () => o.facets().then((r) => ({
466
+ sorts: r.sorts,
467
+ facets: r.facets.map((a) => ({
468
+ ...a,
469
+ kind: String(a.kind).toLowerCase()
470
+ }))
471
+ })),
472
+ !1
473
+ )
474
+ };
475
+ }
476
+ function ut(e) {
477
+ return e.flatMap((t) => [t, ...ut(t.children ?? [])]);
478
+ }
479
+ function ll(e, t) {
480
+ const o = new Map(ut(e).map((i) => [i.id, i])), r = [];
481
+ let a = o.get(t);
482
+ for (; a; )
483
+ r.push(a), a = a.parent_id === null ? void 0 : o.get(a.parent_id);
484
+ return r;
485
+ }
486
+ const Gt = /* @__PURE__ */ Y({
487
+ name: "WxCatalogCategoryField",
488
+ inheritAttrs: !1,
489
+ __name: "CategoryField",
490
+ props: /* @__PURE__ */ Qe({
491
+ multiple: { type: Boolean, default: !1 }
492
+ }, {
493
+ modelValue: { default: null },
494
+ modelModifiers: {}
495
+ }),
496
+ emits: ["update:modelValue"],
497
+ setup(e) {
498
+ const t = e, o = Le(e, "modelValue"), r = Q(), a = st(r), i = Pt();
499
+ ce();
500
+ const n = te("webx-catalog"), s = P(() => {
501
+ const d = i?.values.value.category_id;
502
+ return typeof d == "number" ? d : null;
503
+ }), v = P(() => {
504
+ const d = (g) => g.map((k) => ({
505
+ ...k,
506
+ locked: t.multiple && k.id === s.value,
507
+ children: d(k.children ?? [])
508
+ }));
509
+ return d(a.nodes.value ?? []);
510
+ }), c = P({
511
+ get: () => t.multiple ? Array.isArray(o.value) ? o.value : [] : typeof o.value == "number" ? o.value : null,
512
+ set: (d) => {
513
+ if (t.multiple) {
514
+ const g = (Array.isArray(d) ? d : []).map(Number);
515
+ o.value = g.filter((k) => k !== s.value);
516
+ return;
517
+ }
518
+ o.value = d == null || Array.isArray(d) ? null : Number(d);
519
+ }
520
+ });
521
+ return de(() => {
522
+ a.load().catch(() => {
523
+ });
524
+ }), (d, g) => (h(), U(l(at), wt(d.$attrs, {
525
+ modelValue: c.value,
526
+ "onUpdate:modelValue": g[0] || (g[0] = (k) => c.value = k),
527
+ class: "wx-catalog-category",
528
+ nodes: v.value,
529
+ multiple: t.multiple,
530
+ "check-strictly": t.multiple,
531
+ "node-key": "id",
532
+ "label-key": "name",
533
+ "children-key": "children",
534
+ "disabled-key": "locked",
535
+ "show-path": !t.multiple,
536
+ separator: " / ",
537
+ filterable: "",
538
+ clearable: "",
539
+ "default-expand-all": "",
540
+ teleport: "",
541
+ placeholder: t.multiple ? l(n)("panel.pick-categories") : l(n)("panel.pick-category")
542
+ }), null, 16, ["modelValue", "nodes", "multiple", "check-strictly", "show-path", "placeholder"]));
543
+ }
544
+ }), dt = /* @__PURE__ */ Symbol("wx-catalog-product");
545
+ function ol(e) {
546
+ Ze(dt, e);
547
+ }
548
+ function Ht() {
549
+ return et(dt, null);
550
+ }
551
+ const ct = /* @__PURE__ */ Symbol("wx-catalog-category");
552
+ function nl(e) {
553
+ Ze(ct, e);
554
+ }
555
+ function Xt() {
556
+ return et(ct, null);
557
+ }
558
+ const qt = { class: "wx-catalog-facets" }, Kt = { class: "wx-catalog-facets__own" }, Jt = {
559
+ key: 0,
560
+ class: "wx-catalog-facets__inherited"
561
+ }, Yt = /* @__PURE__ */ Y({
562
+ name: "WxCatalogFacetsField",
563
+ __name: "FacetsField",
564
+ props: {
565
+ modelValue: { default: null },
566
+ modelModifiers: {}
567
+ },
568
+ emits: ["update:modelValue"],
569
+ setup(e) {
570
+ const t = Le(e, "modelValue"), o = Q(), r = ne(o), a = Bt(o), i = Xt();
571
+ ce();
572
+ const n = te("webx-catalog"), s = M(!0), v = M(!1), c = M(null), d = P(() => a.facets.value ?? []), g = P(() => new Map(d.value.map((V) => [V.key, V.label]))), k = P(() => Array.isArray(t.value)), p = P(() => i?.locked.value ?? !1);
573
+ function m(V) {
574
+ const T = new Set(V.map((b) => b.key));
575
+ return [
576
+ ...V.map((b) => ({ key: b.key, visible: b.visible })),
577
+ ...d.value.filter((b) => !T.has(b.key)).map((b) => ({ key: b.key, visible: !1 }))
578
+ ];
579
+ }
580
+ const $ = P(
581
+ () => c.value === null ? d.value.map((V) => ({ key: V.key, visible: !0 })) : m(c.value.rows)
582
+ ), z = P({
583
+ get: () => m(t.value ?? []).map((V) => ({
584
+ ...V,
585
+ label: g.value.get(V.key) ?? V.key,
586
+ known: g.value.has(V.key)
587
+ })),
588
+ set: (V) => {
589
+ t.value = V.map((T) => ({ key: T.key, visible: T.visible }));
590
+ }
591
+ }), O = P(
592
+ () => $.value.filter((V) => V.visible && g.value.has(V.key)).map((V) => g.value.get(V.key)).join(", ")
593
+ );
594
+ function L(V) {
595
+ t.value = V ? $.value.map((T) => ({ ...T })) : null;
596
+ }
597
+ function G(V, T) {
598
+ z.value = z.value.map(
599
+ (b) => b.key === V ? { ...b, visible: !!T } : b
600
+ );
601
+ }
602
+ async function Z(V) {
603
+ const T = i?.facetsFrom.value;
604
+ if (c.value = null, T === null) return;
605
+ if (T !== void 0) {
606
+ const I = await r.category(T.id);
607
+ Array.isArray(I.values.facets) && (c.value = { name: T.name, rows: I.values.facets });
608
+ return;
609
+ }
610
+ let b = V;
611
+ for (; b !== null; ) {
612
+ const I = await r.category(b), re = I.values.facets;
613
+ if (Array.isArray(re)) {
614
+ c.value = { name: I.category.name, rows: re };
615
+ return;
616
+ }
617
+ b = I.category.parent_id;
618
+ }
619
+ }
620
+ async function q() {
621
+ s.value = !0, v.value = !1;
622
+ try {
623
+ await Promise.all([a.load(), Z(i?.category.value?.parent_id ?? null)]);
624
+ } catch {
625
+ v.value = !0;
626
+ } finally {
627
+ s.value = !1;
628
+ }
629
+ }
630
+ return kt(
631
+ () => [i?.category.value?.parent_id, JSON.stringify(i?.facetsFrom.value)],
632
+ (V, T) => {
633
+ (V[0] !== T[0] || V[1] !== T[1]) && q();
634
+ }
635
+ ), de(q), (V, T) => (h(), W("div", qt, [
636
+ s.value ? (h(), U(l(lt), {
637
+ key: 0,
638
+ rows: 3
639
+ })) : v.value ? (h(), U(l(_e), {
640
+ key: 1,
641
+ type: "warning",
642
+ variant: "soft",
643
+ description: l(n)("panel.facets-failed")
644
+ }, null, 8, ["description"])) : (h(), W(H, { key: 2 }, [
645
+ N("div", Kt, [
646
+ _(l(je), {
647
+ "model-value": k.value,
648
+ disabled: p.value,
649
+ label: l(n)("panel.facets-own"),
650
+ "onUpdate:modelValue": L
651
+ }, null, 8, ["model-value", "disabled", "label"]),
652
+ _(l(X), {
653
+ size: "sm",
654
+ tone: "muted"
655
+ }, {
656
+ default: f(() => [
657
+ A(S(k.value ? l(n)("panel.facets-own-help") : l(n)("panel.facets-inherited-help")), 1)
658
+ ]),
659
+ _: 1
660
+ })
661
+ ]),
662
+ k.value ? (h(), U(l(ot), {
663
+ key: 1,
664
+ modelValue: z.value,
665
+ "onUpdate:modelValue": T[0] || (T[0] = (b) => z.value = b),
666
+ size: "sm",
667
+ "item-key": "key",
668
+ "item-label": "label",
669
+ disabled: p.value,
670
+ "empty-text": l(n)("panel.facets-empty")
671
+ }, {
672
+ default: f(({ item: b }) => [
673
+ N("span", {
674
+ class: Ne(["wx-catalog-facets__name", { "is-off": !b.visible }])
675
+ }, S(b.label), 3),
676
+ b.known ? j("", !0) : (h(), U(l(X), {
677
+ key: 0,
678
+ size: "sm",
679
+ tone: "muted"
680
+ }, {
681
+ default: f(() => [
682
+ A(S(l(n)("panel.facets-unknown")), 1)
683
+ ]),
684
+ _: 1
685
+ }))
686
+ ]),
687
+ actions: f(({ item: b }) => [
688
+ _(l(je), {
689
+ size: "sm",
690
+ "model-value": b.visible,
691
+ disabled: p.value || !b.known,
692
+ "aria-label": `${l(n)("panel.facets-shown")}: ${b.label}`,
693
+ "onUpdate:modelValue": (I) => G(b.key, I)
694
+ }, null, 8, ["model-value", "disabled", "aria-label", "onUpdate:modelValue"])
695
+ ]),
696
+ _: 1
697
+ }, 8, ["modelValue", "disabled", "empty-text"])) : (h(), W("div", Jt, [
698
+ _(l(X), { weight: "medium" }, {
699
+ default: f(() => [
700
+ A(S(c.value ? l(n)("panel.facets-inherited", { name: c.value.name }) : l(n)("panel.facets-default")), 1)
701
+ ]),
702
+ _: 1
703
+ }),
704
+ O.value ? (h(), U(l(X), {
705
+ key: 0,
706
+ size: "sm",
707
+ tone: "muted"
708
+ }, {
709
+ default: f(() => [
710
+ A(S(O.value), 1)
711
+ ]),
712
+ _: 1
713
+ })) : d.value.length === 0 ? (h(), U(l(X), {
714
+ key: 1,
715
+ size: "sm",
716
+ tone: "muted"
717
+ }, {
718
+ default: f(() => [
719
+ A(S(l(n)("panel.facets-empty")), 1)
720
+ ]),
721
+ _: 1
722
+ })) : j("", !0)
723
+ ]))
724
+ ], 64))
725
+ ]));
726
+ }
727
+ }), he = (e, t) => {
728
+ const o = e.__vccOpts || e;
729
+ for (const [r, a] of t)
730
+ o[r] = a;
731
+ return o;
732
+ }, Qt = /* @__PURE__ */ he(Yt, [["__scopeId", "data-v-4ca00a4d"]]);
733
+ class pt extends Error {
734
+ constructor(t) {
735
+ super(t), this.name = "VideoUnreadable";
736
+ }
737
+ }
738
+ const Zt = {
739
+ createVideo: () => document.createElement("video"),
740
+ createCanvas: () => document.createElement("canvas"),
741
+ createUrl: (e) => URL.createObjectURL(e),
742
+ revokeUrl: (e) => URL.revokeObjectURL(e)
743
+ };
744
+ function ea(e) {
745
+ return !Number.isFinite(e) || e <= 0 ? 0 : Math.min(1, e / 10);
746
+ }
747
+ function qe(e, t = {}) {
748
+ const o = t.environment ?? Zt, r = t.timeout ?? 15e3, a = o.createVideo(), i = o.createUrl(e);
749
+ return a.muted = !0, a.playsInline = !0, a.preload = "auto", new Promise((n, s) => {
750
+ let v = !1;
751
+ const c = setTimeout(() => g("The browser took too long to open the video."), r);
752
+ function d() {
753
+ v = !0, clearTimeout(c), a.removeAttribute("src"), a.load?.(), o.revokeUrl(i);
754
+ }
755
+ function g(p) {
756
+ v || (d(), s(new pt(p)));
757
+ }
758
+ function k() {
759
+ return Number.isFinite(a.duration) && a.duration > 0 ? Math.round(a.duration) : null;
760
+ }
761
+ a.addEventListener("error", () => g("The browser cannot play this video.")), a.addEventListener("loadedmetadata", () => {
762
+ if (!v) {
763
+ if (!t.frame) {
764
+ d(), n({
765
+ frame: null,
766
+ duration: k(),
767
+ width: a.videoWidth,
768
+ height: a.videoHeight
769
+ });
770
+ return;
771
+ }
772
+ if (a.videoWidth === 0 || a.videoHeight === 0) {
773
+ g("The video has no picture the browser can show.");
774
+ return;
775
+ }
776
+ a.currentTime = ea(a.duration);
777
+ }
778
+ }), a.addEventListener("seeked", () => {
779
+ if (v) return;
780
+ const p = o.createCanvas();
781
+ p.width = a.videoWidth, p.height = a.videoHeight;
782
+ const m = p.getContext("2d");
783
+ if (m === null) {
784
+ g("The browser gave no canvas to draw the frame on.");
785
+ return;
786
+ }
787
+ m.drawImage(a, 0, 0, p.width, p.height);
788
+ const { videoWidth: $, videoHeight: z } = a, O = k();
789
+ p.toBlob(
790
+ (L) => {
791
+ if (!v) {
792
+ if (L === null) {
793
+ g("The frame could not be turned into a picture.");
794
+ return;
795
+ }
796
+ d(), n({ frame: L, duration: O, width: $, height: z });
797
+ }
798
+ },
799
+ "image/jpeg",
800
+ 0.85
801
+ );
802
+ }), a.src = i;
803
+ });
804
+ }
805
+ function ta(e) {
806
+ const t = e.name.replace(/\.[^.]+$/, "");
807
+ return `${t === "" ? "video" : t}.jpg`;
808
+ }
809
+ const aa = /* @__PURE__ */ new Set([
810
+ "youtube.com",
811
+ "www.youtube.com",
812
+ "m.youtube.com",
813
+ "music.youtube.com",
814
+ "youtu.be",
815
+ "www.youtube-nocookie.com",
816
+ "youtube-nocookie.com"
817
+ ]), We = /^[A-Za-z0-9_-]{11}$/;
818
+ function la(e) {
819
+ let t;
820
+ try {
821
+ t = new URL(e.trim());
822
+ } catch {
823
+ return null;
824
+ }
825
+ if (!/^https?:$/.test(t.protocol) || !aa.has(t.hostname.toLowerCase()))
826
+ return null;
827
+ if (t.hostname.toLowerCase() === "youtu.be") {
828
+ const i = t.pathname.split("/")[1] ?? "";
829
+ return We.test(i) ? i : null;
830
+ }
831
+ const o = t.pathname === "/watch" ? t.searchParams.get("v") : null;
832
+ if (o !== null) return We.test(o) ? o : null;
833
+ const [, r, a] = t.pathname.split("/");
834
+ return ["shorts", "embed", "live"].includes(r ?? "") && We.test(a ?? "") ? a ?? null : null;
835
+ }
836
+ function oa(e) {
837
+ try {
838
+ const t = new URL(e.trim());
839
+ return /^https?:$/.test(t.protocol) && /\.(mp4|webm)$/i.test(t.pathname);
840
+ } catch {
841
+ return !1;
842
+ }
843
+ }
844
+ function na(e) {
845
+ return la(e) !== null || oa(e);
846
+ }
847
+ function ra(e, t, o) {
848
+ return t.includes(e.type) ? e.size > o ? "size" : null : "type";
849
+ }
850
+ function ia(e) {
851
+ return e.video?.provider !== "file" || !/\.png$/i.test(e.path) ? !1 : e.width === 1280 && e.height === 720 || e.width === 1 && e.height === 1;
852
+ }
853
+ function ue(e, t) {
854
+ const o = ["B", "KB", "MB", "GB", "TB"];
855
+ let r = Math.max(0, e), a = 0;
856
+ for (; r >= 1024 && a < o.length - 1; )
857
+ r /= 1024, a += 1;
858
+ return `${new Intl.NumberFormat(t, {
859
+ maximumFractionDigits: r >= 100 || a === 0 ? 0 : 1
860
+ }).format(r)} ${o[a]}`;
861
+ }
862
+ function gt(e) {
863
+ const t = Math.max(0, Math.round(e)), o = Math.floor(t / 3600), r = Math.floor(t % 3600 / 60), a = String(t % 60).padStart(2, "0");
864
+ return o > 0 ? `${o}:${String(r).padStart(2, "0")}:${a}` : `${r}:${a}`;
865
+ }
866
+ const Ue = "catalog.video", Re = "webx:catalog-video-targets";
867
+ function sa(e) {
868
+ const t = e.admin ?? Q(), o = ne(t), r = e.storage === void 0 ? ua() : e.storage, a = Vt({ admin: t, storage: r }), i = te("webx-catalog"), n = Se(), s = M([]), v = M(0);
869
+ let c = 1, d = !1, g = null;
870
+ const k = P(() => s.value.some((w) => w.stage !== "failed")), p = P(() => {
871
+ v.value;
872
+ const w = e.product.value, y = we(r), F = new Set(s.value.map((K) => ke(K.file)));
873
+ return w === null ? [] : At(Ue, r).filter((K) => y[K.fingerprint]?.product === w).filter((K) => !F.has(K.fingerprint)).map((K) => ({ ...K, image: y[K.fingerprint]?.image ?? null }));
874
+ });
875
+ function m(w, y) {
876
+ s.value = s.value.map((F) => F.key === w ? { ...F, ...y } : F);
877
+ }
878
+ function $(w) {
879
+ return s.value.find((y) => y.key === w);
880
+ }
881
+ function z(w, y, F) {
882
+ Me(r, {
883
+ ...we(r),
884
+ [ke(w)]: { product: y, image: F }
885
+ }), v.value += 1;
886
+ }
887
+ function O(w) {
888
+ const y = we(r);
889
+ delete y[ke(w)], Me(r, y), v.value += 1;
890
+ }
891
+ function L(w) {
892
+ e.images.value = e.images.value.map((y) => y.id === w.id ? w : y);
893
+ }
894
+ function G(w, y = null) {
895
+ const F = e.product.value;
896
+ F !== null && (s.value = [
897
+ ...s.value,
898
+ {
899
+ key: c++,
900
+ file: w,
901
+ product: F,
902
+ image: y,
903
+ created: !1,
904
+ poster: null,
905
+ duration: null,
906
+ stage: "waiting",
907
+ error: null,
908
+ unreadable: !1
909
+ }
910
+ ], Z());
911
+ }
912
+ async function Z() {
913
+ if (!d) {
914
+ d = !0;
915
+ try {
916
+ let w = s.value.find((y) => y.stage === "waiting");
917
+ for (; w !== void 0; )
918
+ await q(w.key), w = s.value.find((y) => y.stage === "waiting");
919
+ } finally {
920
+ d = !1;
921
+ }
922
+ }
923
+ }
924
+ async function q(w) {
925
+ let y = $(w);
926
+ if (y !== void 0)
927
+ try {
928
+ if (y.image === null) {
929
+ m(w, { stage: "poster" });
930
+ let J;
931
+ try {
932
+ J = await qe(y.file, { ...e.probe, frame: !0 });
933
+ } catch (ae) {
934
+ if (!(ae instanceof pt)) throw ae;
935
+ m(w, { stage: "failed", unreadable: !0, error: i("panel.video-unreadable") });
936
+ return;
937
+ }
938
+ if ($(w) === void 0) return;
939
+ const ve = URL.createObjectURL(J.frame);
940
+ m(w, { poster: ve, duration: J.duration });
941
+ try {
942
+ const ae = await o.addImage(
943
+ y.product,
944
+ new File([J.frame], ta(y.file), { type: "image/jpeg" })
945
+ );
946
+ if ($(w) === void 0) {
947
+ await o.removeImage(y.product, ae.id).catch(() => {
948
+ });
949
+ return;
950
+ }
951
+ e.product.value === y.product && (e.images.value = [...e.images.value, ae]), m(w, { image: ae.id, created: !0 });
952
+ } finally {
953
+ URL.revokeObjectURL(ve), m(w, { poster: null });
954
+ }
955
+ } else if (y.duration === null) {
956
+ const J = await qe(y.file, e.probe).catch(() => null);
957
+ m(w, { duration: J?.duration ?? null });
958
+ }
959
+ if (y = $(w), y === void 0 || y.image === null) return;
960
+ m(w, { stage: "uploading", error: null }), z(y.file, y.product, y.image), g = w;
961
+ const F = await a.start(y.file, Ue);
962
+ if (F === null || $(w) === void 0) return;
963
+ O(y.file), m(w, { stage: "attaching" });
964
+ const K = await o.attachVideo(y.product, y.image, {
965
+ upload: F,
966
+ duration: y.duration
967
+ });
968
+ if ("queued" in K) return;
969
+ e.product.value === y.product && L(K), s.value = s.value.filter((J) => J.key !== w), B.success(i("panel.video-attached"));
970
+ } catch (F) {
971
+ $(w) !== void 0 && m(w, { stage: "failed", error: n(F) });
972
+ }
973
+ }
974
+ function V(w) {
975
+ $(w.key)?.stage === "failed" && (m(w.key, { stage: "waiting", error: null, unreadable: !1 }), Z());
976
+ }
977
+ async function T(w) {
978
+ const y = $(w.key);
979
+ if (y !== void 0 && (s.value = s.value.filter((F) => F.key !== w.key), O(y.file), g === y.key && (g = null, await a.cancel()), y.created && y.image !== null))
980
+ try {
981
+ await o.removeImage(y.product, y.image), e.product.value === y.product && (e.images.value = e.images.value.filter((F) => F.id !== y.image));
982
+ } catch (F) {
983
+ B.danger(n(F));
984
+ }
985
+ }
986
+ function b(w) {
987
+ s.value = s.value.filter((y) => y.key !== w.key);
988
+ }
989
+ function I(w) {
990
+ Et(w.fingerprint, Ue, r);
991
+ const y = we(r);
992
+ delete y[w.fingerprint], Me(r, y), v.value += 1;
993
+ }
994
+ function re(w) {
995
+ k.value && w.preventDefault();
996
+ }
997
+ return typeof window < "u" && window.addEventListener("beforeunload", re), _t() !== void 0 && $t(() => {
998
+ typeof window < "u" && window.removeEventListener("beforeunload", re);
999
+ }), {
1000
+ jobs: Tt(s),
1001
+ upload: a,
1002
+ busy: k,
1003
+ unfinished: p,
1004
+ add: G,
1005
+ pause: () => a.pause(),
1006
+ resume: () => {
1007
+ a.resume();
1008
+ },
1009
+ retry: V,
1010
+ cancel: T,
1011
+ dismiss: b,
1012
+ forget: I
1013
+ };
1014
+ }
1015
+ function ua() {
1016
+ try {
1017
+ return typeof localStorage > "u" ? null : localStorage;
1018
+ } catch {
1019
+ return null;
1020
+ }
1021
+ }
1022
+ function we(e) {
1023
+ if (e === null) return {};
1024
+ try {
1025
+ const t = JSON.parse(e.getItem(Re) ?? "{}");
1026
+ return t !== null && typeof t == "object" ? t : {};
1027
+ } catch {
1028
+ return {};
1029
+ }
1030
+ }
1031
+ function Me(e, t) {
1032
+ if (e !== null)
1033
+ try {
1034
+ Object.keys(t).length === 0 ? e.removeItem(Re) : e.setItem(Re, JSON.stringify(t));
1035
+ } catch {
1036
+ }
1037
+ }
1038
+ function fe(e, t) {
1039
+ const o = e[t]?.[0];
1040
+ if (o !== void 0) return o;
1041
+ const r = Object.keys(e).find((a) => a.startsWith(`${t}.`));
1042
+ return r === void 0 ? void 0 : e[r]?.[0];
1043
+ }
1044
+ const da = /* @__PURE__ */ Y({
1045
+ __name: "VideoLinkDialog",
1046
+ props: {
1047
+ product: {},
1048
+ image: {}
1049
+ },
1050
+ setup(e) {
1051
+ const t = e, { open: o, resolve: r, dismiss: a } = Pe(), i = ne(Q());
1052
+ ce();
1053
+ const n = te("webx-catalog"), s = Se(), v = M(""), c = M(!1), d = M(null), g = ye("field"), k = P(() => na(v.value));
1054
+ de(async () => {
1055
+ await Te(), g.value?.querySelector("input")?.focus();
1056
+ });
1057
+ async function p() {
1058
+ if (!c.value) {
1059
+ if (!k.value) {
1060
+ d.value = n("panel.video-link-wrong");
1061
+ return;
1062
+ }
1063
+ c.value = !0, d.value = null;
1064
+ try {
1065
+ r(await i.attachVideo(t.product, t.image, { url: v.value.trim() }));
1066
+ } catch (m) {
1067
+ const $ = m.body?.errors ?? {};
1068
+ d.value = fe($, "url") ?? s(m);
1069
+ } finally {
1070
+ c.value = !1;
1071
+ }
1072
+ }
1073
+ }
1074
+ return (m, $) => (h(), U(l(Ve), {
1075
+ open: l(o),
1076
+ "onUpdate:open": $[2] || ($[2] = (z) => Ce(o) ? o.value = z : null),
1077
+ title: l(n)("panel.video-link-title"),
1078
+ width: 480
1079
+ }, {
1080
+ footer: f(() => [
1081
+ _(l(Ae), { size: "sm" }, {
1082
+ default: f(() => [
1083
+ _(l(D), {
1084
+ variant: "outline",
1085
+ onClick: $[1] || ($[1] = (z) => l(a)())
1086
+ }, {
1087
+ default: f(() => [
1088
+ A(S(l(n)("panel.cancel")), 1)
1089
+ ]),
1090
+ _: 1
1091
+ }),
1092
+ _(l(D), {
1093
+ type: "primary",
1094
+ loading: c.value,
1095
+ disabled: v.value.trim() === "",
1096
+ onClick: p
1097
+ }, {
1098
+ default: f(() => [
1099
+ A(S(l(n)("panel.video-attach")), 1)
1100
+ ]),
1101
+ _: 1
1102
+ }, 8, ["loading", "disabled"])
1103
+ ]),
1104
+ _: 1
1105
+ })
1106
+ ]),
1107
+ default: f(() => [
1108
+ _(l(oe), {
1109
+ label: l(n)("panel.video-link"),
1110
+ help: l(n)("panel.video-link-help"),
1111
+ error: d.value ?? void 0
1112
+ }, {
1113
+ default: f(() => [
1114
+ N("div", {
1115
+ ref_key: "field",
1116
+ ref: g
1117
+ }, [
1118
+ _(l(ge), {
1119
+ modelValue: v.value,
1120
+ "onUpdate:modelValue": $[0] || ($[0] = (z) => v.value = z),
1121
+ type: "url",
1122
+ placeholder: "https://www.youtube.com/watch?v=",
1123
+ "aria-label": l(n)("panel.video-link"),
1124
+ onKeydown: le(pe(p, ["prevent"]), ["enter"])
1125
+ }, null, 8, ["modelValue", "aria-label", "onKeydown"])
1126
+ ], 512)
1127
+ ]),
1128
+ _: 1
1129
+ }, 8, ["label", "help", "error"])
1130
+ ]),
1131
+ _: 1
1132
+ }, 8, ["open", "title"]));
1133
+ }
1134
+ }), ca = { class: "wx-catalog-video-progress__line" }, pa = { class: "wx-catalog-video-progress__figure" }, ga = { class: "wx-catalog-video-progress__buttons" }, fa = { class: "wx-catalog-video-progress__buttons" }, ha = { class: "wx-catalog-video-progress__line" }, va = { class: "wx-catalog-video-progress__buttons" }, ma = /* @__PURE__ */ Y({
1135
+ __name: "VideoProgress",
1136
+ props: {
1137
+ job: {},
1138
+ video: {}
1139
+ },
1140
+ setup(e) {
1141
+ const t = e, o = te("webx-catalog"), r = xe(), a = P(() => t.video.upload), i = P(() => a.value.state.value), n = P(() => Math.floor(a.value.progress.value * 100)), s = P(() => {
1142
+ const c = r.active.value, d = [
1143
+ o("panel.video-sent", {
1144
+ sent: ue(a.value.uploaded.value, c),
1145
+ total: ue(a.value.total.value, c)
1146
+ })
1147
+ ];
1148
+ if (i.value === "paused")
1149
+ d.push(o("panel.video-paused"));
1150
+ else if (i.value === "offline")
1151
+ d.push(o("panel.video-offline"));
1152
+ else {
1153
+ a.value.speed.value > 0 && d.push(`${ue(a.value.speed.value, c)}/s`);
1154
+ const g = a.value.remaining.value;
1155
+ g !== null && d.push(o("panel.video-left", { time: gt(g) }));
1156
+ }
1157
+ return d;
1158
+ }), v = P(() => {
1159
+ switch (t.job.stage) {
1160
+ case "waiting":
1161
+ return o("panel.video-waiting");
1162
+ case "poster":
1163
+ return o("panel.video-poster");
1164
+ case "attaching":
1165
+ return o("panel.video-attaching");
1166
+ default:
1167
+ return "";
1168
+ }
1169
+ });
1170
+ return (c, d) => (h(), W("div", {
1171
+ class: Ne(["wx-catalog-video-progress", { "is-failed": e.job.stage === "failed" }])
1172
+ }, [
1173
+ e.job.stage === "uploading" ? (h(), W(H, { key: 0 }, [
1174
+ _(l(De), {
1175
+ value: n.value,
1176
+ max: 100,
1177
+ size: "sm",
1178
+ "show-value": "",
1179
+ status: i.value === "failed" ? "danger" : "default",
1180
+ "aria-label": l(o)("panel.video-uploading", { name: e.job.file.name })
1181
+ }, null, 8, ["value", "status", "aria-label"]),
1182
+ N("div", ca, [
1183
+ _(l(X), {
1184
+ size: "sm",
1185
+ tone: "muted",
1186
+ class: "wx-catalog-video-progress__figures"
1187
+ }, {
1188
+ default: f(() => [
1189
+ (h(!0), W(H, null, me(s.value, (g, k) => (h(), W(H, { key: k }, [
1190
+ d[7] || (d[7] = A(S(" "), -1)),
1191
+ N("span", pa, S(k > 0 ? `· ${g}` : g), 1)
1192
+ ], 64))), 128))
1193
+ ]),
1194
+ _: 1
1195
+ }),
1196
+ N("div", ga, [
1197
+ i.value === "uploading" ? (h(), U(l(D), {
1198
+ key: 0,
1199
+ size: "sm",
1200
+ variant: "text",
1201
+ onClick: d[0] || (d[0] = (g) => e.video.pause())
1202
+ }, {
1203
+ default: f(() => [
1204
+ A(S(l(o)("panel.video-pause")), 1)
1205
+ ]),
1206
+ _: 1
1207
+ })) : i.value === "paused" || i.value === "offline" ? (h(), U(l(D), {
1208
+ key: 1,
1209
+ size: "sm",
1210
+ variant: "text",
1211
+ onClick: d[1] || (d[1] = (g) => e.video.resume())
1212
+ }, {
1213
+ default: f(() => [
1214
+ A(S(l(o)("panel.video-resume")), 1)
1215
+ ]),
1216
+ _: 1
1217
+ })) : j("", !0),
1218
+ _(l(D), {
1219
+ size: "sm",
1220
+ variant: "text",
1221
+ type: "danger",
1222
+ onClick: d[2] || (d[2] = (g) => e.video.cancel(e.job))
1223
+ }, {
1224
+ default: f(() => [
1225
+ A(S(l(o)("panel.cancel")), 1)
1226
+ ]),
1227
+ _: 1
1228
+ })
1229
+ ])
1230
+ ])
1231
+ ], 64)) : e.job.stage === "failed" ? (h(), W(H, { key: 1 }, [
1232
+ _(l(X), {
1233
+ size: "sm",
1234
+ tone: "danger",
1235
+ role: "alert"
1236
+ }, {
1237
+ default: f(() => [
1238
+ A(S(e.job.error), 1)
1239
+ ]),
1240
+ _: 1
1241
+ }),
1242
+ N("div", fa, [
1243
+ e.job.unreadable ? j("", !0) : (h(), U(l(D), {
1244
+ key: 0,
1245
+ size: "sm",
1246
+ variant: "text",
1247
+ onClick: d[3] || (d[3] = (g) => e.video.retry(e.job))
1248
+ }, {
1249
+ default: f(() => [
1250
+ A(S(l(o)("panel.video-retry")), 1)
1251
+ ]),
1252
+ _: 1
1253
+ })),
1254
+ e.job.unreadable ? (h(), U(l(D), {
1255
+ key: 1,
1256
+ size: "sm",
1257
+ variant: "text",
1258
+ onClick: d[4] || (d[4] = (g) => e.video.dismiss(e.job))
1259
+ }, {
1260
+ default: f(() => [
1261
+ A(S(l(o)("panel.video-dismiss")), 1)
1262
+ ]),
1263
+ _: 1
1264
+ })) : (h(), U(l(D), {
1265
+ key: 2,
1266
+ size: "sm",
1267
+ variant: "text",
1268
+ type: "danger",
1269
+ onClick: d[5] || (d[5] = (g) => e.video.cancel(e.job))
1270
+ }, {
1271
+ default: f(() => [
1272
+ A(S(l(o)("panel.cancel")), 1)
1273
+ ]),
1274
+ _: 1
1275
+ }))
1276
+ ])
1277
+ ], 64)) : (h(), W(H, { key: 2 }, [
1278
+ _(l(De), {
1279
+ indeterminate: "",
1280
+ size: "sm",
1281
+ "aria-label": v.value
1282
+ }, null, 8, ["aria-label"]),
1283
+ N("div", ha, [
1284
+ _(l(X), {
1285
+ size: "sm",
1286
+ tone: "muted"
1287
+ }, {
1288
+ default: f(() => [
1289
+ A(S(v.value), 1)
1290
+ ]),
1291
+ _: 1
1292
+ }),
1293
+ N("div", va, [
1294
+ _(l(D), {
1295
+ size: "sm",
1296
+ variant: "text",
1297
+ type: "danger",
1298
+ onClick: d[6] || (d[6] = (g) => e.video.cancel(e.job))
1299
+ }, {
1300
+ default: f(() => [
1301
+ A(S(l(o)("panel.cancel")), 1)
1302
+ ]),
1303
+ _: 1
1304
+ })
1305
+ ])
1306
+ ])
1307
+ ], 64))
1308
+ ], 2));
1309
+ }
1310
+ }), Ke = /* @__PURE__ */ he(ma, [["__scopeId", "data-v-09fd14bf"]]), ya = { class: "wx-catalog-gallery" }, xa = { class: "wx-catalog-gallery__item" }, ba = ["href", "title"], wa = ["src"], ka = ["aria-label"], _a = {
1311
+ key: 2,
1312
+ class: "wx-catalog-gallery__size"
1313
+ }, $a = { class: "wx-catalog-gallery__body" }, Ta = { class: "wx-catalog-gallery__words" }, Ca = {
1314
+ key: 3,
1315
+ class: "wx-catalog-gallery__pending"
1316
+ }, Sa = { class: "wx-catalog-gallery__thumb" }, Pa = ["src"], Va = { class: "wx-catalog-gallery__body" }, Aa = ["accept"], Ea = { class: "wx-catalog-gallery__address" }, Wa = 800, Je = "image/jpeg,image/png,image/webp,image/gif", Ie = "▶︎", Ua = /* @__PURE__ */ Y({
1317
+ name: "WxCatalogGallery",
1318
+ __name: "GalleryField",
1319
+ props: {
1320
+ video: { type: Boolean, default: !1 },
1321
+ videoTypes: { default: () => ["video/mp4", "video/webm"] },
1322
+ videoMaxBytes: { default: 2048 * 1048576 }
1323
+ },
1324
+ setup(e) {
1325
+ const t = e, o = Q(), r = ne(o), a = Ht(), i = xe();
1326
+ ce();
1327
+ const n = te("webx-catalog"), s = Se(), v = M([]), c = M(""), d = M(!1), g = P(() => a?.product.value?.id ?? null), k = P(() => a === null || a.locked.value), p = P({
1328
+ get: () => a?.images.value ?? [],
1329
+ set: (C) => {
1330
+ a && (a.images.value = C);
1331
+ }
1332
+ }), m = a === null ? null : a.video ?? sa({ product: g, images: p }), $ = P(() => t.video && m !== null), z = P(() => $.value ? [Je, ...t.videoTypes].join(",") : Je), O = P(() => m?.jobs.value ?? []), L = P(() => O.value.filter((C) => C.image === null)), G = P(() => $.value && !k.value ? m.unfinished.value : []), Z = It(
1333
+ da
1334
+ );
1335
+ let q, V = "";
1336
+ function T(C) {
1337
+ return JSON.stringify(C.map((x) => [x.id, x.alt, x.title]));
1338
+ }
1339
+ async function b(C) {
1340
+ const x = g.value;
1341
+ if (x === null) return;
1342
+ clearTimeout(q);
1343
+ const u = T(p.value);
1344
+ V = u;
1345
+ try {
1346
+ const E = await r.saveImages(x, p.value);
1347
+ T(p.value) === u && (p.value = E);
1348
+ } catch (E) {
1349
+ B.danger(`${C} ${s(E)}`);
1350
+ }
1351
+ }
1352
+ function I(C, x, u) {
1353
+ p.value = p.value.map(
1354
+ (E) => E.id === C.id ? { ...E, [x]: u ?? {} } : E
1355
+ ), clearTimeout(q), q = setTimeout(() => {
1356
+ b(n("panel.gallery-captions-failed"));
1357
+ }, Wa);
1358
+ }
1359
+ function re() {
1360
+ b(n("panel.gallery-reorder-failed"));
1361
+ }
1362
+ function w(C) {
1363
+ const x = ra(C, t.videoTypes, t.videoMaxBytes);
1364
+ return x === "type" && B.danger(n("panel.video-wrong-type")), x === "size" && B.danger(
1365
+ n("panel.video-too-large", { max: ue(t.videoMaxBytes, i.active.value) })
1366
+ ), x === null;
1367
+ }
1368
+ function y(C) {
1369
+ return C.type.startsWith("video/");
1370
+ }
1371
+ async function F(C) {
1372
+ const x = g.value;
1373
+ if (x !== null)
1374
+ for (const u of C) {
1375
+ if (!u.raw) continue;
1376
+ if (y(u.raw)) {
1377
+ v.value = v.value.filter((R) => R.id !== u.id), $.value && w(u.raw) && m.add(u.raw);
1378
+ continue;
1379
+ }
1380
+ const E = (R) => {
1381
+ v.value = v.value.map((ie) => ie.id === u.id ? { ...ie, ...R } : ie);
1382
+ };
1383
+ E({ status: "uploading", progress: 0 });
1384
+ try {
1385
+ const R = await r.addImage(x, u.raw, (ie) => E({ progress: ie }));
1386
+ p.value = [...p.value, R], v.value = v.value.filter((ie) => ie.id !== u.id);
1387
+ } catch (R) {
1388
+ E({ status: "error", error: s(R) });
1389
+ }
1390
+ }
1391
+ }
1392
+ function K(C, x) {
1393
+ x === "type" && B.danger($.value ? n("panel.gallery-wrong-type-video") : n("panel.gallery-wrong-type"));
1394
+ }
1395
+ function J() {
1396
+ B.info(n("panel.video-queued"));
1397
+ }
1398
+ async function ve() {
1399
+ const C = g.value, x = c.value.trim();
1400
+ if (!(C === null || x === "")) {
1401
+ d.value = !0;
1402
+ try {
1403
+ const u = await r.fetchImage(C, x);
1404
+ "queued" in u ? J() : p.value = [...p.value, u], c.value = "";
1405
+ } catch (u) {
1406
+ B.danger(`${n("panel.gallery-failed")} ${s(u)}`);
1407
+ } finally {
1408
+ d.value = !1;
1409
+ }
1410
+ }
1411
+ }
1412
+ async function ae(C) {
1413
+ const x = g.value;
1414
+ if (x === null || !await Be({
1415
+ title: n("panel.gallery-remove-title"),
1416
+ message: n("panel.gallery-remove-text"),
1417
+ confirmText: n("panel.delete"),
1418
+ cancelText: n("panel.cancel"),
1419
+ tone: "danger"
1420
+ })) return;
1421
+ const E = O.value.find((R) => R.image === C.id);
1422
+ if (E !== void 0 && await m.cancel(E), !!p.value.some((R) => R.id === C.id))
1423
+ try {
1424
+ await r.removeImage(x, C.id), p.value = p.value.filter((R) => R.id !== C.id), B.success(n("panel.gallery-removed"));
1425
+ } catch (R) {
1426
+ B.danger(s(R));
1427
+ }
1428
+ }
1429
+ const be = ye("picker");
1430
+ let Ee = null;
1431
+ function ze(C, x) {
1432
+ Ee = { image: C, resume: x }, be.value && (be.value.value = "", be.value.click());
1433
+ }
1434
+ function ht(C) {
1435
+ const x = C.target.files?.[0], u = Ee;
1436
+ if (Ee = null, !(!x || u === null || m === null)) {
1437
+ if (u.resume !== void 0) {
1438
+ if (ke(x) !== u.resume.fingerprint) {
1439
+ B.danger(
1440
+ n("panel.video-other-file", {
1441
+ name: u.resume.name,
1442
+ size: ue(u.resume.size, i.active.value)
1443
+ })
1444
+ );
1445
+ return;
1446
+ }
1447
+ const E = p.value.some((R) => R.id === u.resume.image) ? u.resume.image : null;
1448
+ w(x) && m.add(x, E);
1449
+ return;
1450
+ }
1451
+ w(x) && m.add(x, u.image);
1452
+ }
1453
+ }
1454
+ async function vt(C) {
1455
+ const x = g.value;
1456
+ if (x === null) return;
1457
+ const u = await Z({ product: x, image: C.id });
1458
+ u !== void 0 && ("queued" in u ? J() : (p.value = p.value.map((E) => E.id === u.id ? u : E), B.success(n("panel.video-attached"))));
1459
+ }
1460
+ async function mt(C) {
1461
+ const x = g.value;
1462
+ if (!(x === null || !await Be({
1463
+ title: n("panel.video-remove-title"),
1464
+ message: C.video?.provider === "file" ? n("panel.video-remove-file-text") : n("panel.video-remove-link-text"),
1465
+ confirmText: n("panel.video-remove"),
1466
+ cancelText: n("panel.cancel"),
1467
+ tone: "danger"
1468
+ })))
1469
+ try {
1470
+ const E = await r.detachVideo(x, C.id);
1471
+ p.value = p.value.map((R) => R.id === E.id ? E : R), B.success(n("panel.video-removed"));
1472
+ } catch (E) {
1473
+ B.danger(s(E));
1474
+ }
1475
+ }
1476
+ function yt(C) {
1477
+ const x = [], u = O.value.some((E) => E.image === C.id);
1478
+ return $.value && !u && (C.video ? x.push({
1479
+ key: "detach",
1480
+ label: n("panel.video-remove"),
1481
+ icon: "close",
1482
+ // Not red: the picture stays, and the question that follows says what goes.
1483
+ run: () => {
1484
+ mt(C);
1485
+ }
1486
+ }) : x.push(
1487
+ {
1488
+ key: "file",
1489
+ label: n("panel.video-attach-file"),
1490
+ icon: "upload",
1491
+ run: () => ze(C.id)
1492
+ },
1493
+ {
1494
+ key: "link",
1495
+ label: n("panel.video-attach-link"),
1496
+ icon: "link",
1497
+ run: () => {
1498
+ vt(C);
1499
+ }
1500
+ }
1501
+ )), x.push({
1502
+ key: "delete",
1503
+ label: n("panel.delete"),
1504
+ icon: "trash",
1505
+ danger: !0,
1506
+ run: () => {
1507
+ ae(C);
1508
+ }
1509
+ }), x;
1510
+ }
1511
+ function xt(C) {
1512
+ const x = C.video?.duration;
1513
+ return x ? `${Ie} ${gt(x)}` : Ie;
1514
+ }
1515
+ function Oe(C) {
1516
+ return O.value.find((x) => x.image === C.id);
1517
+ }
1518
+ function bt(C) {
1519
+ const x = i.active.value;
1520
+ return n("panel.video-unfinished", {
1521
+ name: C.name,
1522
+ sent: ue(C.offset, x),
1523
+ total: ue(C.size, x)
1524
+ });
1525
+ }
1526
+ return tt(() => {
1527
+ q !== void 0 && T(p.value) !== V && b(""), clearTimeout(q);
1528
+ }), (C, x) => (h(), W("div", ya, [
1529
+ l(a) ? (h(), W(H, { key: 1 }, [
1530
+ k.value && p.value.length === 0 ? (h(), U(l(_e), {
1531
+ key: 0,
1532
+ type: "info",
1533
+ variant: "soft",
1534
+ description: l(n)("panel.gallery-locked")
1535
+ }, null, 8, ["description"])) : j("", !0),
1536
+ (h(!0), W(H, null, me(G.value, (u) => (h(), U(l(_e), {
1537
+ key: u.fingerprint,
1538
+ type: "warning",
1539
+ variant: "soft",
1540
+ description: bt(u)
1541
+ }, {
1542
+ actions: f(() => [
1543
+ _(l(D), {
1544
+ size: "sm",
1545
+ variant: "outline",
1546
+ onClick: (E) => ze(null, u)
1547
+ }, {
1548
+ default: f(() => [
1549
+ A(S(l(n)("panel.video-choose-again")), 1)
1550
+ ]),
1551
+ _: 1
1552
+ }, 8, ["onClick"]),
1553
+ _(l(D), {
1554
+ size: "sm",
1555
+ variant: "text",
1556
+ onClick: (E) => l(m).forget(u)
1557
+ }, {
1558
+ default: f(() => [
1559
+ A(S(l(n)("panel.video-forget")), 1)
1560
+ ]),
1561
+ _: 1
1562
+ }, 8, ["onClick"])
1563
+ ]),
1564
+ _: 2
1565
+ }, 1032, ["description"]))), 128)),
1566
+ p.value.length > 0 ? (h(), U(l(ot), {
1567
+ key: 1,
1568
+ modelValue: p.value,
1569
+ "onUpdate:modelValue": x[0] || (x[0] = (u) => p.value = u),
1570
+ class: "wx-catalog-gallery__list",
1571
+ "item-key": "id",
1572
+ "item-label": (u) => u.path.split("/").pop() ?? String(u.id),
1573
+ disabled: k.value,
1574
+ title: l(n)("panel.gallery-order"),
1575
+ onMove: re
1576
+ }, {
1577
+ default: f(({ item: u, index: E }) => [
1578
+ N("div", xa, [
1579
+ N("a", {
1580
+ class: "wx-catalog-gallery__thumb",
1581
+ href: u.video?.url ?? u.url,
1582
+ target: "_blank",
1583
+ rel: "noopener",
1584
+ title: u.video ? l(n)("panel.video-open") : void 0
1585
+ }, [
1586
+ N("img", {
1587
+ src: u.thumb ?? u.url,
1588
+ alt: ""
1589
+ }, null, 8, wa),
1590
+ E === 0 ? (h(), U(l($e), {
1591
+ key: 0,
1592
+ class: "wx-catalog-gallery__main",
1593
+ type: "primary",
1594
+ size: "sm"
1595
+ }, {
1596
+ default: f(() => [
1597
+ A(S(l(n)("panel.gallery-main")), 1)
1598
+ ]),
1599
+ _: 1
1600
+ })) : j("", !0),
1601
+ u.video ? (h(), W("span", {
1602
+ key: 1,
1603
+ class: "wx-catalog-gallery__play",
1604
+ "aria-label": l(n)("panel.video-badge")
1605
+ }, S(xt(u)), 9, ka)) : j("", !0),
1606
+ u.width && u.height ? (h(), W("span", _a, S(u.width) + "×" + S(u.height), 1)) : j("", !0)
1607
+ ], 8, ba),
1608
+ N("div", $a, [
1609
+ N("div", Ta, [
1610
+ _(l(ge), {
1611
+ "model-value": u.alt,
1612
+ localized: "",
1613
+ size: "sm",
1614
+ placeholder: l(n)("panel.gallery-alt"),
1615
+ "aria-label": l(n)("panel.gallery-alt"),
1616
+ title: l(n)("panel.gallery-alt-help"),
1617
+ disabled: k.value,
1618
+ "onUpdate:modelValue": (R) => I(u, "alt", R)
1619
+ }, null, 8, ["model-value", "placeholder", "aria-label", "title", "disabled", "onUpdate:modelValue"]),
1620
+ _(l(ge), {
1621
+ "model-value": u.title,
1622
+ localized: "",
1623
+ size: "sm",
1624
+ placeholder: l(n)("panel.gallery-title"),
1625
+ "aria-label": l(n)("panel.gallery-title"),
1626
+ disabled: k.value,
1627
+ "onUpdate:modelValue": (R) => I(u, "title", R)
1628
+ }, null, 8, ["model-value", "placeholder", "aria-label", "disabled", "onUpdate:modelValue"])
1629
+ ]),
1630
+ l(m) && Oe(u) ? (h(), U(Ke, {
1631
+ key: 0,
1632
+ job: Oe(u),
1633
+ video: l(m)
1634
+ }, null, 8, ["job", "video"])) : $.value && l(ia)(u) ? (h(), U(l(X), {
1635
+ key: 1,
1636
+ size: "sm",
1637
+ tone: "muted"
1638
+ }, {
1639
+ default: f(() => [
1640
+ A(S(l(n)("panel.video-placeholder")), 1)
1641
+ ]),
1642
+ _: 1
1643
+ })) : j("", !0)
1644
+ ])
1645
+ ])
1646
+ ]),
1647
+ actions: f(({ item: u }) => [
1648
+ k.value ? j("", !0) : (h(), U(l(Wt), {
1649
+ key: 0,
1650
+ actions: yt(u),
1651
+ label: u.path.split("/").pop()
1652
+ }, null, 8, ["actions", "label"]))
1653
+ ]),
1654
+ _: 1
1655
+ }, 8, ["modelValue", "item-label", "disabled", "title"])) : !k.value && L.value.length === 0 ? (h(), U(l(X), {
1656
+ key: 2,
1657
+ tone: "muted"
1658
+ }, {
1659
+ default: f(() => [
1660
+ A(S(l(n)("panel.gallery-empty")), 1)
1661
+ ]),
1662
+ _: 1
1663
+ })) : j("", !0),
1664
+ l(m) && L.value.length > 0 ? (h(), W("ul", Ca, [
1665
+ (h(!0), W(H, null, me(L.value, (u) => (h(), W("li", {
1666
+ key: u.key,
1667
+ class: "wx-catalog-gallery__item"
1668
+ }, [
1669
+ N("span", Sa, [
1670
+ u.poster ? (h(), W("img", {
1671
+ key: 0,
1672
+ src: u.poster,
1673
+ alt: ""
1674
+ }, null, 8, Pa)) : j("", !0),
1675
+ N("span", { class: "wx-catalog-gallery__play" }, S(Ie))
1676
+ ]),
1677
+ N("div", Va, [
1678
+ _(l(X), {
1679
+ size: "sm",
1680
+ class: "wx-catalog-gallery__name"
1681
+ }, {
1682
+ default: f(() => [
1683
+ A(S(u.file.name), 1)
1684
+ ]),
1685
+ _: 2
1686
+ }, 1024),
1687
+ _(Ke, {
1688
+ job: u,
1689
+ video: l(m)
1690
+ }, null, 8, ["job", "video"])
1691
+ ])
1692
+ ]))), 128))
1693
+ ])) : j("", !0),
1694
+ k.value ? j("", !0) : (h(), W(H, { key: 4 }, [
1695
+ _(l(Rt), {
1696
+ modelValue: v.value,
1697
+ "onUpdate:modelValue": x[1] || (x[1] = (u) => v.value = u),
1698
+ accept: z.value,
1699
+ multiple: "",
1700
+ "button-text": $.value ? l(n)("panel.gallery-add-video") : l(n)("panel.gallery-add"),
1701
+ hint: $.value ? l(n)("panel.gallery-hint-video") : l(n)("panel.gallery-hint"),
1702
+ onAdd: F,
1703
+ onReject: K
1704
+ }, null, 8, ["modelValue", "accept", "button-text", "hint"]),
1705
+ $.value ? (h(), W("input", {
1706
+ key: 0,
1707
+ ref_key: "picker",
1708
+ ref: be,
1709
+ type: "file",
1710
+ class: "wx-catalog-gallery__picker",
1711
+ accept: e.videoTypes.join(","),
1712
+ tabindex: "-1",
1713
+ "aria-hidden": "true",
1714
+ onChange: ht
1715
+ }, null, 40, Aa)) : j("", !0),
1716
+ _(l(Ft), {
1717
+ title: l(n)("panel.gallery-url")
1718
+ }, {
1719
+ default: f(() => [
1720
+ N("div", Ea, [
1721
+ _(l(ge), {
1722
+ modelValue: c.value,
1723
+ "onUpdate:modelValue": x[2] || (x[2] = (u) => c.value = u),
1724
+ type: "url",
1725
+ size: "sm",
1726
+ placeholder: "https://",
1727
+ "aria-label": l(n)("panel.gallery-url"),
1728
+ onKeydown: le(pe(ve, ["prevent"]), ["enter"])
1729
+ }, null, 8, ["modelValue", "aria-label", "onKeydown"]),
1730
+ _(l(D), {
1731
+ size: "sm",
1732
+ variant: "outline",
1733
+ loading: d.value,
1734
+ disabled: c.value.trim() === "",
1735
+ onClick: ve
1736
+ }, {
1737
+ default: f(() => [
1738
+ A(S(l(n)("panel.gallery-url-add")), 1)
1739
+ ]),
1740
+ _: 1
1741
+ }, 8, ["loading", "disabled"])
1742
+ ]),
1743
+ _(l(X), {
1744
+ size: "sm",
1745
+ tone: "muted",
1746
+ class: "wx-catalog-gallery__address-hint"
1747
+ }, {
1748
+ default: f(() => [
1749
+ A(S($.value ? l(n)("panel.gallery-url-hint-video") : l(n)("panel.gallery-url-hint")), 1)
1750
+ ]),
1751
+ _: 1
1752
+ })
1753
+ ]),
1754
+ _: 1
1755
+ }, 8, ["title"])
1756
+ ], 64))
1757
+ ], 64)) : (h(), U(l(_e), {
1758
+ key: 0,
1759
+ type: "info",
1760
+ variant: "soft",
1761
+ description: l(n)("panel.gallery-empty")
1762
+ }, null, 8, ["description"]))
1763
+ ]));
1764
+ }
1765
+ }), Ma = /* @__PURE__ */ he(Ua, [["__scopeId", "data-v-fdb59e51"]]), se = ["neutral", "primary", "success", "warning", "danger", "info"];
1766
+ function Fe(e) {
1767
+ return typeof e == "string" && e !== "neutral" && se.includes(e) ? e : "default";
1768
+ }
1769
+ const Ia = ["aria-label", "aria-labelledby", "aria-disabled"], Ra = ["aria-checked", "tabindex", "disabled", "data-tone", "onClick"], Fa = {
1770
+ key: 0,
1771
+ class: "wx-catalog-tone__sample",
1772
+ "aria-hidden": "true"
1773
+ }, La = /* @__PURE__ */ Y({
1774
+ name: "WxCatalogToneField",
1775
+ __name: "ToneField",
1776
+ props: /* @__PURE__ */ Qe({
1777
+ options: { default: () => [] },
1778
+ disabled: { type: Boolean, default: !1 },
1779
+ ariaLabel: { default: void 0 }
1780
+ }, {
1781
+ modelValue: { default: null },
1782
+ modelModifiers: {}
1783
+ }),
1784
+ emits: ["update:modelValue"],
1785
+ setup(e) {
1786
+ const t = e, o = Le(e, "modelValue"), r = xe(), a = Ut(), i = ye("root"), n = M();
1787
+ de(() => {
1788
+ n.value = i.value?.closest(".wx-form-item")?.querySelector(".wx-form-item__label")?.id || void 0;
1789
+ });
1790
+ const s = P(
1791
+ () => se.includes(o.value ?? "") ? o.value : "neutral"
1792
+ ), v = P(() => new Map(t.options.map((k) => [k.value, k.label]))), c = P(() => {
1793
+ const k = a?.values.value.title;
1794
+ return Lt(k, r.active.value, "") || v.value.get(s.value) || "";
1795
+ });
1796
+ function d(k) {
1797
+ t.disabled || (o.value = k);
1798
+ }
1799
+ function g(k) {
1800
+ const p = se.indexOf(s.value);
1801
+ d(se[(p + k + se.length) % se.length]), Te(() => i.value?.querySelector('[aria-checked="true"]')?.focus());
1802
+ }
1803
+ return (k, p) => (h(), W("div", {
1804
+ ref_key: "root",
1805
+ ref: i,
1806
+ class: "wx-catalog-tone"
1807
+ }, [
1808
+ N("div", {
1809
+ class: "wx-catalog-tone__choices",
1810
+ role: "radiogroup",
1811
+ "aria-label": e.ariaLabel,
1812
+ "aria-labelledby": e.ariaLabel ? void 0 : n.value,
1813
+ "aria-disabled": e.disabled || void 0
1814
+ }, [
1815
+ (h(!0), W(H, null, me(l(se), (m) => (h(), W("button", {
1816
+ key: m,
1817
+ type: "button",
1818
+ role: "radio",
1819
+ class: Ne(["wx-catalog-tone__choice", { "is-chosen": m === s.value }]),
1820
+ "aria-checked": m === s.value,
1821
+ tabindex: m === s.value ? 0 : -1,
1822
+ disabled: e.disabled,
1823
+ "data-tone": m,
1824
+ onClick: ($) => d(m),
1825
+ onKeydown: [
1826
+ p[0] || (p[0] = le(pe(($) => g(1), ["prevent"]), ["right"])),
1827
+ p[1] || (p[1] = le(pe(($) => g(1), ["prevent"]), ["down"])),
1828
+ p[2] || (p[2] = le(pe(($) => g(-1), ["prevent"]), ["left"])),
1829
+ p[3] || (p[3] = le(pe(($) => g(-1), ["prevent"]), ["up"]))
1830
+ ]
1831
+ }, [
1832
+ _(l($e), {
1833
+ type: l(Fe)(m),
1834
+ variant: m === s.value ? "solid" : "soft",
1835
+ round: ""
1836
+ }, {
1837
+ default: f(() => [
1838
+ A(S(v.value.get(m) ?? m), 1)
1839
+ ]),
1840
+ _: 2
1841
+ }, 1032, ["type", "variant"])
1842
+ ], 42, Ra))), 128))
1843
+ ], 8, Ia),
1844
+ c.value ? (h(), W("span", Fa, [
1845
+ _(l($e), {
1846
+ type: l(Fe)(s.value),
1847
+ size: "sm"
1848
+ }, {
1849
+ default: f(() => [
1850
+ A(S(c.value), 1)
1851
+ ]),
1852
+ _: 1
1853
+ }, 8, ["type"])
1854
+ ])) : j("", !0)
1855
+ ], 512));
1856
+ }
1857
+ }), Na = /* @__PURE__ */ he(La, [["__scopeId", "data-v-2b8d13bb"]]);
1858
+ function rl(e = {}) {
1859
+ const t = e.path ?? "/catalog", o = { base: t }, r = {
1860
+ id: "catalog",
1861
+ path: `${t}/products`,
1862
+ routes: [
1863
+ { path: t, redirect: `${t}/products` },
1864
+ {
1865
+ path: `${t}/products`,
1866
+ name: "webx.catalog.products",
1867
+ component: () => import("./ProductsPage-BBmw9W4m.js"),
1868
+ props: o
1869
+ },
1870
+ {
1871
+ path: `${t}/products/:id(\\d+)`,
1872
+ name: "webx.catalog.products.edit",
1873
+ component: () => import("./ProductEditorPage-Bfp6ZV3d.js"),
1874
+ props: o
1875
+ },
1876
+ {
1877
+ path: `${t}/deleted`,
1878
+ name: "webx.catalog.deleted",
1879
+ component: () => import("./DeletedPage-TGTyQbzn.js"),
1880
+ props: o
1881
+ },
1882
+ // The exchange (§8.1 of the exchange spec): under the products, like «Deleted» — reached
1883
+ // from their head, and lit in the navigation as the products.
1884
+ {
1885
+ path: `${t}/exchange`,
1886
+ name: "webx.catalog.exchange",
1887
+ component: () => import("./ExchangePage-9RrRcSiS.js"),
1888
+ props: o
1889
+ },
1890
+ {
1891
+ path: `${t}/exchange/import`,
1892
+ name: "webx.catalog.exchange.import",
1893
+ component: () => import("./ExchangeImportPage-C6cSg7Cr.js"),
1894
+ props: o
1895
+ },
1896
+ {
1897
+ path: `${t}/exchange/profiles`,
1898
+ name: "webx.catalog.exchange.profiles",
1899
+ component: () => import("./ExchangeProfilesPage-T6G3HHD8.js"),
1900
+ props: o
1901
+ },
1902
+ {
1903
+ path: `${t}/exchange/profiles/:id(\\d+|new)`,
1904
+ name: "webx.catalog.exchange.profile",
1905
+ component: () => import("./ExchangeProfilePage-BUnh9_D7.js"),
1906
+ props: o
1907
+ }
1908
+ ],
1909
+ types: {
1910
+ "wx-catalog-category": { component: Gt, kind: "field" },
1911
+ // Wide: a row of the list carries a name, a switch and a grip, and half a line is too narrow
1912
+ // to read which filter is which.
1913
+ "wx-catalog-facets": { component: Qt, kind: "field", wide: !0 },
1914
+ "wx-catalog-gallery": { component: Ma, kind: "display" },
1915
+ // The tone of a label or a stock status: here, because both satellites paint in the same six.
1916
+ "wx-catalog-tone": { component: Na, kind: "field" }
1917
+ }
1918
+ }, a = {
1919
+ id: "catalog-categories",
1920
+ path: `${t}/categories`,
1921
+ routes: [
1922
+ {
1923
+ path: `${t}/categories`,
1924
+ name: "webx.catalog.categories",
1925
+ component: () => import("./CategoriesPage-B6GBTzvN.js"),
1926
+ props: o
1927
+ },
1928
+ {
1929
+ path: `${t}/categories/:id(\\d+)`,
1930
+ name: "webx.catalog.categories.edit",
1931
+ component: () => import("./CategoryEditorPage-y6EFmOof.js"),
1932
+ props: o
1933
+ }
1934
+ ]
1935
+ };
1936
+ return [r, a];
1937
+ }
1938
+ const ft = "f.";
1939
+ function il(e, t) {
1940
+ const o = {};
1941
+ for (const r of t) {
1942
+ const a = e[`${ft}${r.key}`], i = typeof a == "string" ? a.trim() : "";
1943
+ if (i !== "")
1944
+ if (r.kind === "toggle")
1945
+ i === "1" && (o[r.key] = !0);
1946
+ else if (r.kind === "range") {
1947
+ const [n, s] = i.split("-", 2).map((c) => c === "" ? null : Number(c)), v = {
1948
+ min: Number.isFinite(n) ? n : null,
1949
+ max: Number.isFinite(s) ? s : null
1950
+ };
1951
+ (v.min !== null || v.max !== null) && (o[r.key] = v);
1952
+ } else {
1953
+ const n = i.split(",").filter((s) => s !== "");
1954
+ n.length > 0 && (o[r.key] = n);
1955
+ }
1956
+ }
1957
+ return o;
1958
+ }
1959
+ function sl(e) {
1960
+ if (e == null) return;
1961
+ if (e === !0) return "1";
1962
+ if (Array.isArray(e)) return e.length > 0 ? e.join(",") : void 0;
1963
+ const t = e.min ?? null, o = e.max ?? null;
1964
+ return t === null && o === null ? void 0 : `${t ?? ""}-${o ?? ""}`;
1965
+ }
1966
+ const za = [
1967
+ "new",
1968
+ "empty",
1969
+ "empty-help",
1970
+ "order",
1971
+ "hidden",
1972
+ "count",
1973
+ "show-items",
1974
+ "delete-blocked",
1975
+ "delete-text",
1976
+ "deleted",
1977
+ "saved"
1978
+ ];
1979
+ function Oa(e) {
1980
+ const t = e.catalog ?? "/catalog";
1981
+ return {
1982
+ api: `catalog/${e.slug}`,
1983
+ path: `${t}/${e.slug}`,
1984
+ name: `webx.${e.id}`,
1985
+ module: e.id,
1986
+ screen: e.screen,
1987
+ manage: "catalog.manage",
1988
+ count: "products_count",
1989
+ items: (o) => ({
1990
+ path: `${t}/products`,
1991
+ query: { [`${ft}${e.facet}`]: String(o) }
1992
+ }),
1993
+ words: Object.fromEntries(
1994
+ za.map((o) => [o, `${e.namespace}::${e.group}.${o}`])
1995
+ )
1996
+ };
1997
+ }
1998
+ function ul(e) {
1999
+ const t = Oa(e), o = () => ja(e.namespace, e.messages);
2000
+ return {
2001
+ id: e.id,
2002
+ path: t.path,
2003
+ routes: Mt(t).map((r) => Da(r, o))
2004
+ };
2005
+ }
2006
+ const Ye = /* @__PURE__ */ new WeakMap();
2007
+ function ja(e, t) {
2008
+ try {
2009
+ const { i18n: o } = Q(), r = Ye.get(o) ?? /* @__PURE__ */ new Set();
2010
+ r.has(e) || (o.defaults(e, t), r.add(e), Ye.set(o, r));
2011
+ } catch {
2012
+ }
2013
+ }
2014
+ function Da(e, t) {
2015
+ const o = e.component;
2016
+ return o === void 0 ? e : {
2017
+ ...e,
2018
+ component: Y({
2019
+ name: "WxCatalogDictionaryView",
2020
+ setup() {
2021
+ return t(), () => Ct(o);
2022
+ }
2023
+ })
2024
+ };
2025
+ }
2026
+ const dl = "catalog.exchange", cl = {
2027
+ key: "sku",
2028
+ mode: "upsert",
2029
+ empty_clears: !1,
2030
+ absent: "keep",
2031
+ absent_scope: "categories",
2032
+ create_missing: !1,
2033
+ images: "append"
2034
+ };
2035
+ function Ba(e) {
2036
+ const t = `${e.apiPath}/${nt}/exchange`, o = (r) => r.data;
2037
+ return {
2038
+ columns: () => e.http.get(`${t}/columns`).then(o),
2039
+ inspect: (r, a = {}) => e.http.post(`${t}/inspect`, { ...r, ...a }).then(o),
2040
+ startImport: (r, a, i) => e.http.post(`${t}/import`, { ...r, ...a, dry_run: i }).then(o),
2041
+ startExport: (r, a) => e.http.post(`${t}/export`, { selection: r, ...a }).then(o),
2042
+ runs: (r = {}) => e.http.get(`${t}/runs`, {
2043
+ query: { page: r.page ?? 1, per_page: r.per_page ?? 20 }
2044
+ }),
2045
+ run: (r) => e.http.get(`${t}/runs/${r}`).then(o),
2046
+ errors: (r, a = 1) => e.http.get(`${t}/runs/${r}/errors`, {
2047
+ query: { page: a, per_page: 100 }
2048
+ }),
2049
+ errorsFile: (r) => `${t}/runs/${r}/errors?format=csv`,
2050
+ file: (r) => `${t}/runs/${r}/file`,
2051
+ profiles: (r) => e.http.get(`${t}/profiles`, {
2052
+ query: r ? { direction: r } : {}
2053
+ }).then(o),
2054
+ profile: (r) => e.http.get(`${t}/profiles/${r}`).then(o),
2055
+ createProfile: (r) => e.http.post(`${t}/profiles`, r).then(o),
2056
+ saveProfile: (r, a) => e.http.put(`${t}/profiles/${r}`, a).then(o),
2057
+ removeProfile: (r) => e.http.delete(`${t}/profiles/${r}`).then(() => {
2058
+ })
2059
+ };
2060
+ }
2061
+ function Ga(e) {
2062
+ return e.status === "queued" || e.status === "running";
2063
+ }
2064
+ function Ha(e, t) {
2065
+ return t ? `${e}@${t}` : e;
2066
+ }
2067
+ const Xa = 2e3;
2068
+ function pl(e, t) {
2069
+ const o = M([]);
2070
+ let r;
2071
+ async function a() {
2072
+ r = void 0;
2073
+ const n = await Promise.allSettled(o.value.map((s) => e.run(s)));
2074
+ for (const s of n)
2075
+ s.status === "fulfilled" && (t(s.value), Ga(s.value) || (o.value = o.value.filter((v) => v !== s.value.id)));
2076
+ i();
2077
+ }
2078
+ function i() {
2079
+ r === void 0 && o.value.length > 0 && (r = setTimeout(a, Xa));
2080
+ }
2081
+ return tt(() => {
2082
+ clearTimeout(r), o.value = [];
2083
+ }), {
2084
+ watching: o,
2085
+ watch(n) {
2086
+ o.value.includes(n) || (o.value = [...o.value, n]), i();
2087
+ }
2088
+ };
2089
+ }
2090
+ const gl = /* @__PURE__ */ Y({
2091
+ __name: "ProductCreateDialog",
2092
+ setup(e) {
2093
+ const { open: t, resolve: o, dismiss: r } = Pe(), a = Q(), i = ne(a), n = xe();
2094
+ ce();
2095
+ const s = te("webx-catalog"), v = M(""), c = M(!1), d = M({}), g = ye("field");
2096
+ de(async () => {
2097
+ await Te(), g.value?.querySelector("input")?.focus();
2098
+ });
2099
+ async function k() {
2100
+ if (!(v.value.trim() === "" || c.value)) {
2101
+ c.value = !0, d.value = {};
2102
+ try {
2103
+ o(
2104
+ await i.createProduct({
2105
+ name: { [n.active.value]: v.value.trim() },
2106
+ is_published: !1
2107
+ })
2108
+ );
2109
+ } catch (p) {
2110
+ d.value = p.body?.errors ?? {};
2111
+ } finally {
2112
+ c.value = !1;
2113
+ }
2114
+ }
2115
+ }
2116
+ return (p, m) => (h(), U(l(Ve), {
2117
+ open: l(t),
2118
+ "onUpdate:open": m[2] || (m[2] = ($) => Ce(t) ? t.value = $ : null),
2119
+ title: l(s)("panel.new-product"),
2120
+ width: 440
2121
+ }, {
2122
+ footer: f(() => [
2123
+ _(l(Ae), { size: "sm" }, {
2124
+ default: f(() => [
2125
+ _(l(D), {
2126
+ variant: "outline",
2127
+ onClick: m[1] || (m[1] = ($) => l(r)())
2128
+ }, {
2129
+ default: f(() => [
2130
+ A(S(l(s)("panel.cancel")), 1)
2131
+ ]),
2132
+ _: 1
2133
+ }),
2134
+ _(l(D), {
2135
+ type: "primary",
2136
+ loading: c.value,
2137
+ disabled: v.value.trim() === "",
2138
+ onClick: k
2139
+ }, {
2140
+ default: f(() => [
2141
+ A(S(l(s)("panel.create")), 1)
2142
+ ]),
2143
+ _: 1
2144
+ }, 8, ["loading", "disabled"])
2145
+ ]),
2146
+ _: 1
2147
+ })
2148
+ ]),
2149
+ default: f(() => [
2150
+ _(l(oe), {
2151
+ label: l(s)("product.name"),
2152
+ error: l(fe)(d.value, "name") ?? l(fe)(d.value, "slug"),
2153
+ required: ""
2154
+ }, {
2155
+ default: f(() => [
2156
+ N("div", {
2157
+ ref_key: "field",
2158
+ ref: g
2159
+ }, [
2160
+ _(l(ge), {
2161
+ modelValue: v.value,
2162
+ "onUpdate:modelValue": m[0] || (m[0] = ($) => v.value = $),
2163
+ "aria-label": l(s)("product.name"),
2164
+ onKeyup: le(k, ["enter"])
2165
+ }, null, 8, ["modelValue", "aria-label"])
2166
+ ], 512)
2167
+ ]),
2168
+ _: 1
2169
+ }, 8, ["label", "error"])
2170
+ ]),
2171
+ _: 1
2172
+ }, 8, ["open", "title"]));
2173
+ }
2174
+ }), fl = /* @__PURE__ */ Y({
2175
+ __name: "CategoryCreateDialog",
2176
+ props: {
2177
+ parent: { default: null }
2178
+ },
2179
+ setup(e) {
2180
+ const t = e, { open: o, resolve: r, dismiss: a } = Pe(), i = Q(), n = ne(i), s = st(i), v = xe();
2181
+ ce();
2182
+ const c = te("webx-catalog"), d = M(""), g = M(t.parent), k = M(!1), p = M({}), m = ye("field"), $ = P(() => s.nodes.value ?? []);
2183
+ de(async () => {
2184
+ s.load().catch(() => {
2185
+ }), await Te(), m.value?.querySelector("input")?.focus();
2186
+ });
2187
+ async function z() {
2188
+ if (!(d.value.trim() === "" || k.value)) {
2189
+ k.value = !0, p.value = {};
2190
+ try {
2191
+ const O = typeof g.value == "number" ? g.value : null;
2192
+ r(
2193
+ await n.createCategory(
2194
+ { name: { [v.active.value]: d.value.trim() }, is_published: !1 },
2195
+ O
2196
+ )
2197
+ );
2198
+ } catch (O) {
2199
+ p.value = O.body?.errors ?? {};
2200
+ } finally {
2201
+ k.value = !1;
2202
+ }
2203
+ }
2204
+ }
2205
+ return (O, L) => (h(), U(l(Ve), {
2206
+ open: l(o),
2207
+ "onUpdate:open": L[3] || (L[3] = (G) => Ce(o) ? o.value = G : null),
2208
+ title: l(c)("panel.new-category"),
2209
+ width: 480
2210
+ }, {
2211
+ footer: f(() => [
2212
+ _(l(Ae), { size: "sm" }, {
2213
+ default: f(() => [
2214
+ _(l(D), {
2215
+ variant: "outline",
2216
+ onClick: L[2] || (L[2] = (G) => l(a)())
2217
+ }, {
2218
+ default: f(() => [
2219
+ A(S(l(c)("panel.cancel")), 1)
2220
+ ]),
2221
+ _: 1
2222
+ }),
2223
+ _(l(D), {
2224
+ type: "primary",
2225
+ loading: k.value,
2226
+ disabled: d.value.trim() === "",
2227
+ onClick: z
2228
+ }, {
2229
+ default: f(() => [
2230
+ A(S(l(c)("panel.create")), 1)
2231
+ ]),
2232
+ _: 1
2233
+ }, 8, ["loading", "disabled"])
2234
+ ]),
2235
+ _: 1
2236
+ })
2237
+ ]),
2238
+ default: f(() => [
2239
+ _(l(oe), {
2240
+ label: l(c)("category.name"),
2241
+ error: l(fe)(p.value, "name") ?? l(fe)(p.value, "slug"),
2242
+ required: ""
2243
+ }, {
2244
+ default: f(() => [
2245
+ N("div", {
2246
+ ref_key: "field",
2247
+ ref: m
2248
+ }, [
2249
+ _(l(ge), {
2250
+ modelValue: d.value,
2251
+ "onUpdate:modelValue": L[0] || (L[0] = (G) => d.value = G),
2252
+ "aria-label": l(c)("category.name"),
2253
+ onKeyup: le(z, ["enter"])
2254
+ }, null, 8, ["modelValue", "aria-label"])
2255
+ ], 512)
2256
+ ]),
2257
+ _: 1
2258
+ }, 8, ["label", "error"]),
2259
+ _(l(oe), {
2260
+ label: l(c)("panel.field-parent"),
2261
+ error: l(fe)(p.value, "parent_id")
2262
+ }, {
2263
+ default: f(() => [
2264
+ _(l(at), {
2265
+ modelValue: g.value,
2266
+ "onUpdate:modelValue": L[1] || (L[1] = (G) => g.value = G),
2267
+ nodes: $.value,
2268
+ "node-key": "id",
2269
+ "label-key": "name",
2270
+ "children-key": "children",
2271
+ "show-path": "",
2272
+ separator: " / ",
2273
+ filterable: "",
2274
+ clearable: "",
2275
+ "default-expand-all": "",
2276
+ teleport: "",
2277
+ placeholder: l(c)("panel.parent-root")
2278
+ }, null, 8, ["modelValue", "nodes", "placeholder"])
2279
+ ]),
2280
+ _: 1
2281
+ }, 8, ["label", "error"])
2282
+ ]),
2283
+ _: 1
2284
+ }, 8, ["open", "title"]));
2285
+ }
2286
+ }), qa = {
2287
+ key: 1,
2288
+ class: "wx-catalog-export__body"
2289
+ }, Ka = { class: "wx-catalog-export__columns" }, Ja = /* @__PURE__ */ Y({
2290
+ __name: "ExchangeExportDialog",
2291
+ props: {
2292
+ selection: { default: null },
2293
+ count: { default: null }
2294
+ },
2295
+ setup(e) {
2296
+ const t = e, { open: o, resolve: r, dismiss: a } = Pe(), i = Q(), n = Ba(i);
2297
+ ce();
2298
+ const s = te("webx-catalog"), v = Se(), c = M(null), d = M([]), g = M(null), k = M([]), p = M([]), m = M("xlsx"), $ = M(!1);
2299
+ de(async () => {
2300
+ try {
2301
+ const [T, b] = await Promise.all([n.columns(), n.profiles("export")]);
2302
+ c.value = T, d.value = b, k.value = T.map((I) => I.key);
2303
+ } catch (T) {
2304
+ B.danger(v(T)), c.value = [];
2305
+ }
2306
+ });
2307
+ const z = P(
2308
+ () => d.value.map((T) => ({ value: T.id, label: T.name }))
2309
+ ), O = P(
2310
+ () => (c.value ?? []).map((T) => ({ value: T.key, label: T.label }))
2311
+ ), L = P(() => [...new Set((c.value ?? []).flatMap((b) => b.locales))].map((b) => ({ value: b, label: b.toUpperCase() }))), G = P(() => [
2312
+ { value: "xlsx", label: "XLSX" },
2313
+ { value: "csv", label: "CSV" }
2314
+ ]), Z = P(
2315
+ () => (c.value ?? []).filter((T) => k.value.includes(T.key)).flatMap((T) => [
2316
+ T.key,
2317
+ ...T.localized ? T.locales.filter((b) => p.value.includes(b)).map((b) => Ha(T.key, b)) : []
2318
+ ])
2319
+ ), q = P(() => g.value !== null || Z.value.length > 0);
2320
+ async function V() {
2321
+ if (!q.value) {
2322
+ B.warning(s("panel.exchange-export-none"));
2323
+ return;
2324
+ }
2325
+ $.value = !0;
2326
+ try {
2327
+ const T = await n.startExport(
2328
+ t.selection ?? { query: {} },
2329
+ g.value !== null ? { profile_id: g.value } : { columns: Z.value, format: m.value }
2330
+ );
2331
+ r(T);
2332
+ } catch (T) {
2333
+ B.danger(v(T));
2334
+ } finally {
2335
+ $.value = !1;
2336
+ }
2337
+ }
2338
+ return (T, b) => (h(), U(l(Ve), {
2339
+ open: l(o),
2340
+ "onUpdate:open": b[5] || (b[5] = (I) => Ce(o) ? o.value = I : null),
2341
+ title: l(s)("panel.exchange-export-title"),
2342
+ width: 520
2343
+ }, {
2344
+ footer: f(() => [
2345
+ _(l(Ae), { size: "sm" }, {
2346
+ default: f(() => [
2347
+ _(l(D), {
2348
+ variant: "outline",
2349
+ onClick: b[4] || (b[4] = (I) => l(a)())
2350
+ }, {
2351
+ default: f(() => [
2352
+ A(S(l(s)("panel.cancel")), 1)
2353
+ ]),
2354
+ _: 1
2355
+ }),
2356
+ _(l(D), {
2357
+ type: "primary",
2358
+ icon: "download",
2359
+ loading: $.value,
2360
+ disabled: c.value === null || !q.value,
2361
+ onClick: V
2362
+ }, {
2363
+ default: f(() => [
2364
+ A(S(l(s)("panel.exchange-export-start")), 1)
2365
+ ]),
2366
+ _: 1
2367
+ }, 8, ["loading", "disabled"])
2368
+ ]),
2369
+ _: 1
2370
+ })
2371
+ ]),
2372
+ default: f(() => [
2373
+ _(l(X), {
2374
+ tone: "muted",
2375
+ size: "sm"
2376
+ }, {
2377
+ default: f(() => [
2378
+ A(S(e.count !== null ? l(s)("panel.exchange-export-selected", { count: e.count }) : l(s)("panel.exchange-export-all")), 1)
2379
+ ]),
2380
+ _: 1
2381
+ }),
2382
+ c.value === null ? (h(), U(l(lt), {
2383
+ key: 0,
2384
+ rows: 4,
2385
+ class: "wx-catalog-export__body"
2386
+ })) : (h(), W("div", qa, [
2387
+ d.value.length > 0 ? (h(), U(l(oe), {
2388
+ key: 0,
2389
+ label: l(s)("panel.exchange-profile")
2390
+ }, {
2391
+ default: f(() => [
2392
+ _(l(Nt), {
2393
+ modelValue: g.value,
2394
+ "onUpdate:modelValue": b[0] || (b[0] = (I) => g.value = I),
2395
+ options: z.value,
2396
+ clearable: "",
2397
+ placeholder: l(s)("panel.exchange-export-pick"),
2398
+ "aria-label": l(s)("panel.exchange-profile")
2399
+ }, null, 8, ["modelValue", "options", "placeholder", "aria-label"])
2400
+ ]),
2401
+ _: 1
2402
+ }, 8, ["label"])) : j("", !0),
2403
+ g.value === null ? (h(), W(H, { key: 1 }, [
2404
+ _(l(oe), {
2405
+ label: l(s)("panel.exchange-export-columns"),
2406
+ help: l(s)("panel.exchange-export-columns-help")
2407
+ }, {
2408
+ default: f(() => [
2409
+ N("div", Ka, [
2410
+ _(l(Ge), {
2411
+ modelValue: k.value,
2412
+ "onUpdate:modelValue": b[1] || (b[1] = (I) => k.value = I),
2413
+ options: O.value
2414
+ }, null, 8, ["modelValue", "options"])
2415
+ ])
2416
+ ]),
2417
+ _: 1
2418
+ }, 8, ["label", "help"]),
2419
+ L.value.length > 0 ? (h(), U(l(oe), {
2420
+ key: 0,
2421
+ label: l(s)("panel.exchange-export-languages"),
2422
+ help: l(s)("panel.exchange-export-languages-help")
2423
+ }, {
2424
+ default: f(() => [
2425
+ _(l(Ge), {
2426
+ modelValue: p.value,
2427
+ "onUpdate:modelValue": b[2] || (b[2] = (I) => p.value = I),
2428
+ inline: "",
2429
+ options: L.value
2430
+ }, null, 8, ["modelValue", "options"])
2431
+ ]),
2432
+ _: 1
2433
+ }, 8, ["label", "help"])) : j("", !0),
2434
+ _(l(oe), {
2435
+ label: l(s)("panel.exchange-format")
2436
+ }, {
2437
+ default: f(() => [
2438
+ _(l(zt), {
2439
+ modelValue: m.value,
2440
+ "onUpdate:modelValue": b[3] || (b[3] = (I) => m.value = I),
2441
+ options: G.value,
2442
+ "aria-label": l(s)("panel.exchange-format")
2443
+ }, null, 8, ["modelValue", "options", "aria-label"])
2444
+ ]),
2445
+ _: 1
2446
+ }, 8, ["label"])
2447
+ ], 64)) : j("", !0)
2448
+ ]))
2449
+ ]),
2450
+ _: 1
2451
+ }, 8, ["open", "title"]));
2452
+ }
2453
+ }), hl = /* @__PURE__ */ he(Ja, [["__scopeId", "data-v-df38616e"]]), Ya = {
2454
+ key: 0,
2455
+ class: "wx-catalog-column-value is-empty"
2456
+ }, Qa = {
2457
+ key: 1,
2458
+ class: "wx-catalog-column-value"
2459
+ }, Za = /* @__PURE__ */ Y({
2460
+ name: "WxCatalogColumnValue",
2461
+ __name: "ColumnValue",
2462
+ props: {
2463
+ value: { type: [String, Number, Boolean, null, Object, Array] }
2464
+ },
2465
+ setup(e) {
2466
+ const t = e;
2467
+ function o(a, i) {
2468
+ if (a == null || a === "") return null;
2469
+ if (typeof a == "object" && !Array.isArray(a) && "name" in a) {
2470
+ const n = a;
2471
+ return {
2472
+ key: String(n.id ?? i),
2473
+ name: String(n.name ?? ""),
2474
+ tone: typeof n.color == "string" ? n.color : null,
2475
+ muted: n.visible === !1
2476
+ };
2477
+ }
2478
+ return typeof a == "boolean" ? { key: String(i), name: a ? "✓" : "—", tone: null, muted: !a } : { key: String(i), name: String(a), tone: null, muted: !1 };
2479
+ }
2480
+ const r = P(
2481
+ () => (Array.isArray(t.value) ? t.value : [t.value]).map((a, i) => o(a, i)).filter((a) => a !== null)
2482
+ );
2483
+ return (a, i) => r.value.length === 0 ? (h(), W("span", Ya, "—")) : (h(), W("span", Qa, [
2484
+ (h(!0), W(H, null, me(r.value, (n) => (h(), W(H, {
2485
+ key: n.key
2486
+ }, [
2487
+ n.tone !== null ? (h(), U(l($e), {
2488
+ key: 0,
2489
+ type: l(Fe)(n.tone),
2490
+ size: "sm"
2491
+ }, {
2492
+ default: f(() => [
2493
+ A(S(n.name), 1)
2494
+ ]),
2495
+ _: 2
2496
+ }, 1032, ["type"])) : (h(), U(l(X), {
2497
+ key: 1,
2498
+ size: "sm",
2499
+ truncate: "",
2500
+ tone: n.muted ? "muted" : void 0
2501
+ }, {
2502
+ default: f(() => [
2503
+ A(S(n.name), 1)
2504
+ ]),
2505
+ _: 2
2506
+ }, 1032, ["tone"]))
2507
+ ], 64))), 128))
2508
+ ]));
2509
+ }
2510
+ }), vl = /* @__PURE__ */ he(Za, [["__scopeId", "data-v-2389d2f9"]]), ml = ee(() => import("./ProductsPage-BBmw9W4m.js")), yl = ee(() => import("./ProductEditorPage-Bfp6ZV3d.js")), xl = ee(() => import("./CategoriesPage-B6GBTzvN.js")), bl = ee(
2511
+ () => import("./CategoryEditorPage-y6EFmOof.js")
2512
+ ), wl = ee(() => import("./DeletedPage-TGTyQbzn.js")), kl = ee(() => import("./ExchangePage-9RrRcSiS.js")), _l = ee(
2513
+ () => import("./ExchangeImportPage-C6cSg7Cr.js")
2514
+ ), $l = ee(
2515
+ () => import("./ExchangeProfilesPage-T6G3HHD8.js")
2516
+ ), Tl = ee(
2517
+ () => import("./ExchangeProfilePage-BUnh9_D7.js")
2518
+ );
2519
+ export {
2520
+ Qt as A,
2521
+ yl as B,
2522
+ vl as C,
2523
+ ml as D,
2524
+ hl as E,
2525
+ ft as F,
2526
+ Ma as G,
2527
+ Na as H,
2528
+ cl as I,
2529
+ rl as J,
2530
+ Ot as K,
2531
+ ct as L,
2532
+ Ha as M,
2533
+ Oa as N,
2534
+ ul as O,
2535
+ dt as P,
2536
+ jt as Q,
2537
+ Fe as R,
2538
+ Xt as S,
2539
+ se as T,
2540
+ Ht as U,
2541
+ Ue as V,
2542
+ xl as W,
2543
+ he as _,
2544
+ ce as a,
2545
+ Bt as b,
2546
+ ne as c,
2547
+ gl as d,
2548
+ sa as e,
2549
+ ut as f,
2550
+ fl as g,
2551
+ ll as h,
2552
+ nl as i,
2553
+ Ba as j,
2554
+ Ga as k,
2555
+ pl as l,
2556
+ dl as m,
2557
+ nt as n,
2558
+ Xa as o,
2559
+ ol as p,
2560
+ bl as q,
2561
+ il as r,
2562
+ Gt as s,
2563
+ wl as t,
2564
+ st as u,
2565
+ _l as v,
2566
+ sl as w,
2567
+ kl as x,
2568
+ Tl as y,
2569
+ $l as z
2570
+ };
2571
+ //# sourceMappingURL=index-BTEbHnJ5.js.map