@webx-ui/module-catalog 0.1.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/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/BulkBar.d.ts +20 -0
- package/dist/BulkParamsDialog.d.ts +12 -0
- package/dist/CategoriesPage.d.ts +23 -0
- package/dist/CategoryCreateDialog.d.ts +14 -0
- package/dist/CategoryEditorPage.d.ts +7 -0
- package/dist/CategoryField.d.ts +14 -0
- package/dist/DeletedPage.d.ts +19 -0
- package/dist/FacetsField.d.ts +10 -0
- package/dist/GalleryField.d.ts +2 -0
- package/dist/ProductCreateDialog.d.ts +4 -0
- package/dist/ProductEditorPage.d.ts +7 -0
- package/dist/ProductsPage.d.ts +20 -0
- package/dist/api.d.ts +59 -0
- package/dist/editor.d.ts +41 -0
- package/dist/errors.d.ts +6 -0
- package/dist/filters.d.ts +18 -0
- package/dist/i18n.d.ts +2 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +2908 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +11 -0
- package/dist/module.d.ts +22 -0
- package/dist/paths.d.ts +6 -0
- package/dist/store.d.ts +29 -0
- package/dist/style.css +1 -0
- package/dist/types.d.ts +270 -0
- package/package.json +66 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/api.ts","../src/errors.ts","../src/messages.ts","../src/i18n.ts","../src/store.ts","../src/CategoryCreateDialog.vue","../src/paths.ts","../src/CategoriesPage.vue","../src/editor.ts","../src/CategoryEditorPage.vue","../src/CategoryField.vue","../src/DeletedPage.vue","../src/FacetsField.vue","../src/GalleryField.vue","../src/ProductEditorPage.vue","../src/BulkParamsDialog.vue","../src/BulkBar.vue","../src/ProductCreateDialog.vue","../src/filters.ts","../src/ProductsPage.vue","../src/module.ts"],"sourcesContent":["import { readCookie, type AdminContext } from '@webx-ui/module-admin'\nimport type { Paginated } from '@webx-ui/core'\nimport type { ScreenModel } from '@webx-ui/schema'\nimport type {\n BulkActionInfo,\n BulkRun,\n BulkSelection,\n CategoryDetail,\n CategoryNode,\n CategoryRow,\n DeletedCategory,\n DeletedKind,\n DeletedProduct,\n FacetInfo,\n FacetRegistryAnswer,\n SortInfo,\n ProductDetail,\n ProductImage,\n ProductQuery,\n ProductRow,\n ProductsPage,\n} from './types'\n\nexport interface CatalogApi {\n products(query?: ProductQuery): Promise<ProductsPage>\n product(id: number): Promise<ProductDetail>\n /** The values of `catalog.product-form`; a refused field comes back as a 422 under its name. */\n createProduct(values: ScreenModel): Promise<ProductDetail>\n saveProduct(id: number, values: ScreenModel): Promise<ProductDetail>\n removeProduct(id: number): Promise<void>\n restoreProduct(id: number): Promise<ProductRow>\n\n /** A file off the disk, with how far it has got; or an address the server fetches itself. */\n addImage(\n id: number,\n source: File | string,\n onProgress?: (percent: number) => void,\n ): Promise<ProductImage>\n /** The whole gallery in its order, with every picture's words (§11.2). */\n saveImages(\n id: number,\n images: Pick<ProductImage, 'id' | 'alt' | 'title'>[],\n ): Promise<ProductImage[]>\n removeImage(id: number, image: number): Promise<void>\n\n categories(): Promise<CategoryNode[]>\n category(id: number): Promise<CategoryDetail>\n createCategory(values: ScreenModel, parent: number | null): Promise<CategoryDetail>\n saveCategory(id: number, values: ScreenModel): Promise<CategoryDetail>\n /** Under `parent` (null — the top), before `before` (null — last). Answers with the whole tree. */\n moveCategory(id: number, parent: number | null, before: number | null): Promise<CategoryNode[]>\n removeCategory(id: number): Promise<void>\n restoreCategory(id: number): Promise<CategoryRow>\n\n /** The registry of facets, with the sorts the list is offered. */\n facets(): Promise<FacetRegistryAnswer>\n\n /** The bulk actions this administrator may start, with what each asks for (§11.4). */\n bulkActions(): Promise<BulkActionInfo[]>\n /** Done at once when small (`id` null in the answer), queued otherwise. */\n startBulk(\n action: string,\n params: Record<string, unknown>,\n selection: BulkSelection,\n ): Promise<BulkRun>\n bulkRun(id: number): Promise<BulkRun>\n\n deleted(\n kind: 'products',\n query?: { q?: string; page?: number; per_page?: number },\n ): Promise<Paginated<DeletedProduct>>\n deleted(\n kind: 'categories',\n query?: { q?: string; page?: number; per_page?: number },\n ): Promise<Paginated<DeletedCategory>>\n deleted(\n kind: DeletedKind,\n query?: { q?: string; page?: number; per_page?: number },\n ): Promise<Paginated<DeletedProduct | DeletedCategory>>\n}\n\n/** The path of the catalogue under the panel's API. */\nexport const CATALOG_API = 'catalog'\n\n/**\n * The list's query as Laravel reads nested parameters: `facets[brand][]=3`,\n * `facets[price][min]=100`. Every facet's choice is a list, a toggle's too — on is\n * `facets[in-stock][]=1`, the value the storefront's own links send; a bare `facets[in-stock]=1`\n * is refused. Empty choices are left out, so a filter that was opened and closed again asks for\n * nothing.\n */\nexport function productSearch(query: ProductQuery): URLSearchParams {\n const search = new URLSearchParams()\n\n if (query.q) search.set('q', query.q)\n if (query.state) search.set('state', query.state)\n if (query.sort && query.sort !== 'default') search.set('sort', query.sort)\n if (query.page && query.page > 1) search.set('page', String(query.page))\n if (query.per_page) search.set('per_page', String(query.per_page))\n\n for (const [key, choice] of Object.entries(query.facets ?? {})) {\n if (choice === true) {\n search.set(`facets[${key}][]`, '1')\n } else if (Array.isArray(choice)) {\n for (const value of choice) search.append(`facets[${key}][]`, String(value))\n } else {\n if (choice.min != null) search.set(`facets[${key}][min]`, String(choice.min))\n if (choice.max != null) search.set(`facets[${key}][max]`, String(choice.max))\n }\n }\n\n return search\n}\n\n/**\n * The upload is the one request that is not JSON, and the one worth a progress bar: a phone\n * sending a twelve-megapixel photo over a shop's wifi takes long enough for \"is it doing\n * anything?\". XHR for that, as `module-media` does it.\n */\nfunction upload<T>(admin: AdminContext, url: string, file: File, onProgress?: (p: number) => void) {\n const body = new FormData()\n body.append('file', file)\n\n return new Promise<T>((resolve, reject) => {\n const request = new XMLHttpRequest()\n\n request.open('POST', url)\n request.responseType = 'json'\n request.withCredentials = true\n request.setRequestHeader('Accept', 'application/json')\n request.setRequestHeader('X-Requested-With', 'XMLHttpRequest')\n // The panel's own client sends the language on every request; this one is not that client,\n // and without it a refusal comes back in English under a Russian panel.\n request.setRequestHeader('X-Webx-Locale', admin.i18n.state.locale)\n\n const token = readCookie('XSRF-TOKEN')\n if (token) request.setRequestHeader('X-XSRF-TOKEN', token)\n\n request.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) onProgress?.(Math.round((event.loaded / event.total) * 100))\n })\n\n request.addEventListener('load', () => {\n const answer = request.response as { data?: T; message?: string } | null\n\n if (request.status >= 200 && request.status < 300 && answer?.data) {\n resolve(answer.data)\n\n return\n }\n\n reject(\n Object.assign(new Error(answer?.message ?? 'Upload failed'), {\n status: request.status,\n body: answer,\n }),\n )\n })\n\n request.addEventListener('error', () => reject(new Error('Upload failed')))\n request.send(body)\n })\n}\n\nexport function createCatalogApi(admin: AdminContext): CatalogApi {\n const base = `${admin.apiPath}/${CATALOG_API}`\n const data = <T>(body: { data: T }): T => body.data\n const withQuery = (path: string, search: URLSearchParams) =>\n search.size > 0 ? `${path}?${search}` : path\n\n return {\n products: (query = {}) =>\n admin.http.get<ProductsPage>(withQuery(`${base}/products`, productSearch(query))),\n product: (id) => admin.http.get<{ data: ProductDetail }>(`${base}/products/${id}`).then(data),\n createProduct: (values) =>\n admin.http.post<{ data: ProductDetail }>(`${base}/products`, { values }).then(data),\n saveProduct: (id, values) =>\n admin.http.put<{ data: ProductDetail }>(`${base}/products/${id}`, { values }).then(data),\n removeProduct: (id) => admin.http.delete<void>(`${base}/products/${id}`).then(() => undefined),\n restoreProduct: (id) =>\n admin.http.post<{ data: ProductRow }>(`${base}/products/${id}/restore`, {}).then(data),\n\n addImage: (id, source, onProgress) =>\n typeof source === 'string'\n ? admin.http\n .post<{ data: ProductImage }>(`${base}/products/${id}/images`, { url: source })\n .then(data)\n : upload<ProductImage>(admin, `${base}/products/${id}/images`, source, onProgress),\n saveImages: (id, images) =>\n admin.http\n .put<{ data: ProductImage[] }>(`${base}/products/${id}/images`, {\n images: images.map(({ id: image, alt, title }) => ({ id: image, alt, title })),\n })\n .then(data),\n removeImage: (id, image) =>\n admin.http.delete<void>(`${base}/products/${id}/images/${image}`).then(() => undefined),\n\n categories: () => admin.http.get<{ data: CategoryNode[] }>(`${base}/categories`).then(data),\n category: (id) =>\n admin.http.get<{ data: CategoryDetail }>(`${base}/categories/${id}`).then(data),\n createCategory: (values, parent) =>\n admin.http\n .post<{ data: CategoryDetail }>(`${base}/categories`, { values, parent_id: parent })\n .then(data),\n saveCategory: (id, values) =>\n admin.http.put<{ data: CategoryDetail }>(`${base}/categories/${id}`, { values }).then(data),\n moveCategory: (id, parent, before) =>\n admin.http\n .post<{ data: CategoryNode[] }>(`${base}/categories/${id}/move`, {\n parent_id: parent,\n before_id: before,\n })\n .then(data),\n removeCategory: (id) =>\n admin.http.delete<void>(`${base}/categories/${id}`).then(() => undefined),\n restoreCategory: (id) =>\n admin.http.post<{ data: CategoryRow }>(`${base}/categories/${id}/restore`, {}).then(data),\n\n facets: () =>\n admin.http\n .get<{ data: FacetInfo[]; meta?: { sorts?: SortInfo[] } }>(`${base}/facets`)\n .then((body) => ({ facets: body.data, sorts: body.meta?.sorts ?? [] })),\n\n bulkActions: () => admin.http.get<{ data: BulkActionInfo[] }>(`${base}/bulk`).then(data),\n startBulk: (action, params, selection) =>\n admin.http.post<{ data: BulkRun }>(`${base}/bulk`, { action, params, selection }).then(data),\n bulkRun: (id) => admin.http.get<{ data: BulkRun }>(`${base}/bulk/${id}`).then(data),\n\n deleted: ((kind: DeletedKind, query: { q?: string; page?: number; per_page?: number } = {}) => {\n const search = new URLSearchParams({ type: kind })\n\n if (query.q) search.set('q', query.q)\n if (query.page && query.page > 1) search.set('page', String(query.page))\n if (query.per_page) search.set('per_page', String(query.per_page))\n\n return admin.http.get(`${base}/deleted?${search}`)\n }) as CatalogApi['deleted'],\n }\n}\n","/**\n * The first refusal of a field, whether the server named the field (`name`) or one language of it\n * (`name.en`). Matched on the name and a dot, not on the first dot of the key: names with a dot in\n * them exist (`stock.status`), and `name.en` must not be read as the field `name.en`.\n */\nexport function firstError(errors: Record<string, string[]>, field: string): string | undefined {\n const own = errors[field]?.[0]\n\n if (own !== undefined) return own\n\n const key = Object.keys(errors).find((name) => name.startsWith(`${field}.`))\n\n return key === undefined ? undefined : errors[key]?.[0]\n}\n","import type { Messages } from '@webx-ui/module-admin'\n\n/**\n * The English this package speaks on its own, before the server's dictionary arrives, or without\n * one. The server ships the same lines under `webx-catalog::` and overrides these;\n * `messages.test.ts` keeps the two sets of keys equal.\n *\n * `module`, `states`, `product`, `category` and `units` are the server's groups, which the panel\n * reads too — a column called \"Article number\" in the list and \"Article number\" on the form\n * are one word. `panel` is what only the panel says.\n */\nexport const catalogMessages: Record<string, Messages> = {\n module: {\n title: 'Catalog',\n group: 'Catalog',\n products: 'Products',\n categories: 'Categories',\n deleted: 'Deleted',\n product: 'Product',\n category: 'Category',\n },\n states: {\n published: 'Published',\n unpublished: 'Unpublished',\n deleted: 'Deleted',\n },\n product: {\n name: 'Name',\n slug: 'Address',\n sku: 'Article number',\n barcode: 'Barcode',\n summary: 'Summary',\n description: 'Description',\n category_id: 'Main category',\n category: 'Main category',\n categories: 'Additional categories',\n price: 'Price',\n old_price: 'Old price',\n unit: 'Unit',\n priority: 'Priority',\n is_published: 'Published',\n images: 'Pictures',\n 'no-category': 'No category',\n },\n category: {\n name: 'Name',\n slug: 'Address',\n description: 'Text',\n cover: 'Picture',\n cover_id: 'Picture',\n is_published: 'Published',\n parent: 'Parent category',\n facets: 'Filters',\n },\n units: {\n pcs: 'pcs',\n kg: 'kg',\n g: 'g',\n m: 'm',\n m2: 'm²',\n m3: 'm³',\n l: 'l',\n pack: 'pack',\n set: 'set',\n },\n panel: {\n create: 'Create',\n cancel: 'Cancel',\n save: 'Save',\n saved: 'Saved.',\n 'save-failed': 'Not saved: what is wrong is said under the fields in red.',\n untitled: 'Untitled',\n open: 'Open',\n 'open-on-site': 'Open on the site',\n publish: 'Publish',\n unpublish: 'Take off the site',\n delete: 'Delete',\n restore: 'Restore',\n 'leave-title': 'Leave without saving?',\n 'leave-text': 'What you changed is not on the server.',\n leave: 'Leave',\n 'address-moving':\n 'The address is changing. The old one keeps working and leads to the new one.',\n\n 'new-product': 'New product',\n 'search-products': 'Search by name or article number',\n 'empty-products': 'No products yet.',\n 'empty-products-help': 'A product lives in one main category and any number of others.',\n 'empty-search': 'Nothing matches that.',\n 'view-all': 'All',\n 'view-published': 'Published',\n 'view-unpublished': 'Unpublished',\n 'view-no-category': 'No category',\n 'column-product': 'Product',\n 'column-state': 'State',\n 'column-updated': 'Changed',\n invisible: 'Published, but no category of it is on the site, so nobody sees it.',\n sort: 'Order',\n 'sort-default': 'By priority, then newest',\n 'range-from': 'From',\n 'range-to': 'To',\n any: 'Any',\n selected: 'Selected: :count',\n 'select-clear': 'Clear the selection',\n 'bulk-actions': 'Actions',\n 'select-all-found': 'Select everything found: :count',\n 'selected-all': 'Selected everything found: :count',\n 'bulk-apply': 'Apply',\n 'bulk-confirm-title': 'Apply «:action»?',\n 'bulk-confirm-text': 'Products it applies to: :count',\n 'bulk-running': 'Running in the background. Done :done of :total',\n 'bulk-done': 'Done. Products: :count',\n 'bulk-refused': 'Refused: :count',\n 'bulk-stopped': 'The run stopped. Done so far: :count',\n 'bulk-errors': 'What was refused',\n 'bulk-close': 'Close',\n 'bulk-nothing': 'None of the selected products fit this action.',\n 'product-trail': 'Where this product sits',\n 'delete-product-title': 'Delete “:name”?',\n 'delete-product-text':\n 'It goes to «Deleted» and comes off the site. Its address leads to its category from then on.',\n 'product-deleted': 'The product is in «Deleted».',\n 'product-restored': 'The product is back.',\n 'product-restored-bare':\n 'The product is back without a category and unpublished: its category is deleted.',\n 'product-published': 'The product is on the site.',\n 'product-unpublished': 'The product is off the site.',\n 'sku-open': 'Open that product',\n 'sku-open-deleted': 'Find it in «Deleted»',\n\n 'gallery-add': 'Add pictures',\n 'gallery-hint': 'JPEG, PNG, WebP or GIF. The first picture is the main one.',\n 'gallery-url': 'Or by address',\n 'gallery-url-add': 'Fetch',\n 'gallery-empty': 'No pictures yet.',\n 'gallery-main': 'Main',\n 'gallery-alt': 'Alternative text',\n 'gallery-alt-help': 'What the picture shows, for search engines and screen readers.',\n 'gallery-title': 'Title',\n 'gallery-order': 'Drag to change the order. The first picture is the main one.',\n 'gallery-failed': 'The picture was not added.',\n 'gallery-remove-title': 'Delete this picture?',\n 'gallery-remove-text': 'The file is deleted from the disk at once.',\n 'gallery-removed': 'The picture is deleted.',\n 'gallery-reorder-failed': 'The new order was not saved.',\n 'gallery-captions-failed': 'The captions were not saved.',\n 'gallery-locked': 'Pictures are added to a product you may edit.',\n\n 'new-category': 'New category',\n 'add-child': 'Add a subcategory',\n 'search-categories': 'Search by name or address',\n 'empty-categories': 'No categories yet.',\n 'empty-categories-help':\n 'Categories are the shelves of the catalogue; each has an address of its own at the root of the site.',\n 'column-products': 'Products',\n 'category-hidden': 'Hidden: a category above it is unpublished.',\n 'category-order': 'Drag to move a category. Its address stays the same.',\n 'category-moved': 'The category is moved.',\n 'category-trail': 'Where this category sits',\n 'field-parent': 'Inside',\n 'parent-root': 'At the top level',\n 'show-products': 'Show its products',\n 'delete-category-title': 'Delete “:name”?',\n 'delete-category-text': 'It goes to «Deleted», and its address answers that it is gone.',\n 'category-deleted': 'The category is in «Deleted».',\n 'category-restored': 'The category is back.',\n 'category-published': 'The category is on the site.',\n 'category-unpublished': 'The category and everything under it is off the site.',\n 'pick-category': 'Choose a category',\n 'pick-categories': 'Choose categories',\n 'category-gone': 'deleted',\n\n 'facets-own': 'Own setting',\n 'facets-own-help': 'Which filters this category shows, and in which order.',\n 'facets-inherited': 'As in “:name”',\n 'facets-default': 'All filters, in their default order',\n 'facets-inherited-help':\n 'Switch it on to choose for this category. Categories under it take the setting unless they have their own.',\n 'facets-empty': 'No filters are installed.',\n 'facets-failed': 'The list of filters did not load.',\n 'facets-shown': 'Shown',\n 'facets-unknown': 'Its module is not installed',\n\n 'deleted-search': 'Search by name',\n 'deleted-empty': 'Nothing is deleted.',\n 'deleted-help': 'A deleted product keeps its pictures and comes back under its old address.',\n 'column-deleted': 'Deleted',\n 'column-parent': 'Was inside',\n 'restore-bare': 'Comes back without a category',\n },\n}\n","import { useAdmin } from '@webx-ui/module-admin'\nimport { catalogMessages } from './messages'\n\nconst seeded = new WeakSet<object>()\n\n/** Puts this package's English under the panel's dictionary, once per panel. */\nexport function useCatalogMessages(): void {\n try {\n const { i18n } = useAdmin()\n\n if (!seeded.has(i18n)) {\n i18n.defaults('webx-catalog', catalogMessages)\n seeded.add(i18n)\n }\n } catch {\n // Outside a panel there is no dictionary to seed, and `useTranslate` falls back on its own.\n }\n}\n","import { computed, ref, type ComputedRef, type Ref } from 'vue'\nimport type { AdminContext } from '@webx-ui/module-admin'\nimport { createCatalogApi } from './api'\nimport type { CategoryNode, FacetInfo, FacetKind, FacetRegistryAnswer, SortInfo } from './types'\n\n/**\n * What several screens of the catalogue read and nobody should ask for twice: the tree of\n * categories and the registry of facets.\n *\n * The tree is read by the list's filter, by both category pickers of the product form and by the\n * tree screen; one panel, one copy, dropped whenever a category is created, saved, moved, deleted\n * or restored — the next reader asks again. Kept per panel rather than per module instance, so a\n * test that builds a panel of its own starts from nothing.\n */\ninterface Shelf<T> {\n value: Ref<T | null>\n pending: Promise<T> | null\n}\n\ninterface CatalogStore {\n tree: Shelf<CategoryNode[]>\n facets: Shelf<FacetRegistryAnswer>\n}\n\nconst stores = new WeakMap<AdminContext, CatalogStore>()\n\nfunction storeOf(admin: AdminContext): CatalogStore {\n let store = stores.get(admin)\n\n if (!store) {\n store = {\n tree: { value: ref(null), pending: null },\n facets: { value: ref(null), pending: null },\n }\n stores.set(admin, store)\n }\n\n return store\n}\n\nfunction fetchInto<T>(shelf: Shelf<T>, fetch: () => Promise<T>, force: boolean): Promise<T> {\n if (!force && shelf.value.value !== null) return Promise.resolve(shelf.value.value)\n if (!force && shelf.pending) return shelf.pending\n\n const pending = fetch()\n .then((value) => {\n if (shelf.pending === pending) shelf.value.value = value\n\n return value\n })\n .finally(() => {\n if (shelf.pending === pending) shelf.pending = null\n })\n\n shelf.pending = pending\n\n return pending\n}\n\nexport interface CategoryTree {\n /** `null` until the first answer. */\n nodes: Ref<CategoryNode[] | null>\n load(force?: boolean): Promise<CategoryNode[]>\n /** Put in what the server answered with — a move answers with the whole tree. */\n take(nodes: CategoryNode[]): void\n /** Forget it; the next reader asks again. */\n drop(): void\n}\n\nexport function useCategoryTree(admin: AdminContext): CategoryTree {\n const shelf = storeOf(admin).tree\n const api = createCatalogApi(admin)\n\n return {\n nodes: shelf.value,\n load: (force = false) => fetchInto(shelf, () => api.categories(), force),\n take: (nodes) => {\n shelf.pending = null\n shelf.value.value = nodes\n },\n drop: () => {\n shelf.pending = null\n shelf.value.value = null\n },\n }\n}\n\nexport interface FacetRegistry {\n facets: ComputedRef<FacetInfo[] | null>\n /** The orders the list offers, in the registry's order; empty until the answer. */\n sorts: ComputedRef<SortInfo[]>\n load(): Promise<FacetRegistryAnswer>\n}\n\n/**\n * The facets every category can show (§7.1) and the sorts of the list (§7.2) — one answer, since\n * the list needs both before it can draw its filter. The kind is lowercased on the way in: a panel\n * comparing with 'range' should not care how the server cased its enum.\n */\nexport function useFacetRegistry(admin: AdminContext): FacetRegistry {\n const shelf = storeOf(admin).facets\n const api = createCatalogApi(admin)\n\n return {\n facets: computed(() => shelf.value.value?.facets ?? null),\n sorts: computed(() => shelf.value.value?.sorts ?? []),\n load: () =>\n fetchInto(\n shelf,\n () =>\n api.facets().then((answer) => ({\n sorts: answer.sorts,\n facets: answer.facets.map((facet) => ({\n ...facet,\n kind: String(facet.kind).toLowerCase() as FacetKind,\n })),\n })),\n false,\n ),\n }\n}\n\n/** Every node of the tree, depth first, as the server ordered them. */\nexport function flatten(nodes: CategoryNode[]): CategoryNode[] {\n return nodes.flatMap((node) => [node, ...flatten(node.children ?? [])])\n}\n\n/** A node and the chain of its parents, the node first. Empty when it is not in the tree. */\nexport function ancestry(nodes: CategoryNode[], id: number): CategoryNode[] {\n const byId = new Map(flatten(nodes).map((node) => [node.id, node]))\n const chain: CategoryNode[] = []\n let current = byId.get(id)\n\n while (current) {\n chain.push(current)\n current = current.parent_id === null ? undefined : byId.get(current.parent_id)\n }\n\n return chain\n}\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onMounted, ref, useTemplateRef } from 'vue'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport {\n useLocales,\n useModal,\n WxButton,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSpace,\n WxTreeSelect,\n type TreeSelectValue,\n} from '@webx-ui/core'\nimport { createCatalogApi } from './api'\nimport { firstError } from './errors'\nimport { useCatalogMessages } from './i18n'\nimport { useCategoryTree } from './store'\nimport type { CategoryDetail } from './types'\n\n/**\n * A new category: its name and where it hangs. Created unpublished — a shelf nobody filled is\n * not one to show visitors — at the end of its parent's children; the tree is where it is dragged\n * into place. The address is made of the name, and a taken one is refused under the name.\n */\nconst props = withDefaults(defineProps<{ parent?: number | null }>(), { parent: null })\n\nconst { open, resolve, dismiss } = useModal<CategoryDetail>()\n\nconst context = useAdmin()\nconst api = createCatalogApi(context)\nconst tree = useCategoryTree(context)\nconst locales = useLocales()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\n\nconst name = ref('')\nconst parent = ref<TreeSelectValue>(props.parent)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\nconst field = useTemplateRef<HTMLElement>('field')\n\nconst nodes = computed(() => tree.nodes.value ?? [])\n\nonMounted(async () => {\n void tree.load().catch(() => undefined)\n await nextTick()\n field.value?.querySelector('input')?.focus()\n})\n\nasync function submit(): Promise<void> {\n if (name.value.trim() === '' || saving.value) return\n\n saving.value = true\n errors.value = {}\n\n try {\n const under = typeof parent.value === 'number' ? parent.value : null\n\n resolve(\n await api.createCategory(\n { name: { [locales.active.value]: name.value.trim() }, is_published: false },\n under,\n ),\n )\n } catch (error) {\n errors.value = (error as { body?: { errors?: Record<string, string[]> } }).body?.errors ?? {}\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog v-model:open=\"open\" :title=\"t('panel.new-category')\" :width=\"480\">\n <wx-form-item\n :label=\"t('category.name')\"\n :error=\"firstError(errors, 'name') ?? firstError(errors, 'slug')\"\n required\n >\n <div ref=\"field\">\n <wx-input v-model=\"name\" :aria-label=\"t('category.name')\" @keyup.enter=\"submit\" />\n </div>\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.field-parent')\" :error=\"firstError(errors, 'parent_id')\">\n <wx-tree-select\n v-model=\"parent\"\n :nodes=\"nodes\"\n node-key=\"id\"\n label-key=\"name\"\n children-key=\"children\"\n show-path\n separator=\" / \"\n filterable\n clearable\n default-expand-all\n teleport\n :placeholder=\"t('panel.parent-root')\"\n />\n </wx-form-item>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" :disabled=\"name.trim() === ''\" @click=\"submit\">\n {{ t('panel.create') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n","/**\n * The last segment of an address on the site, without slashes: `/laptops/` → `laptops`,\n * `https://shop.test/en/lamp-12` → `lamp-12`. The panel compares it with the slug being typed;\n * the language prefix and the host in front of it are not part of what the slug field edits.\n */\nexport function lastSegment(url: string | null | undefined): string | null {\n if (!url) return null\n\n let path: string\n\n try {\n path = new URL(url, 'http://panel.invalid').pathname\n } catch {\n return null\n }\n\n const segments = path.split('/').filter((segment) => segment !== '')\n\n return segments.length > 0 ? decodeURIComponent(segments[segments.length - 1]!) : null\n}\n","<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 :back=\"`${props.base}/products`\"\n :back-label=\"t('module.products')\"\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","import { inject, provide, type InjectionKey, type Ref } from 'vue'\nimport type { CategoryRow, ProductImage, ProductRow } from './types'\n\n/**\n * What the product editor knows and the nodes of `catalog.product-form` do not.\n *\n * The gallery needs it most: its pictures are not a value of the form but records of their own,\n * added, ordered and captioned by requests of their own (§11.2), so the node has to know which\n * product it is attached to and whether this administrator may write.\n */\nexport interface ProductEditorContext {\n /** The product as the server last answered it, or `null` while the first request is out. */\n product: Ref<ProductRow | null>\n /** The gallery in its order. The editor reads it with the product; the node keeps it. */\n images: Ref<ProductImage[]>\n /** Closed for writing: no permission, or a save in flight. */\n locked: Ref<boolean>\n}\n\nexport const productEditorKey: InjectionKey<ProductEditorContext> = Symbol('wx-catalog-product')\n\nexport function provideProductEditor(editor: ProductEditorContext): void {\n provide(productEditorKey, editor)\n}\n\n/** The editor above this node, or `null` outside one — a demo or a test draws a placeholder. */\nexport function useProductEditor(): ProductEditorContext | null {\n return inject(productEditorKey, null)\n}\n\n/**\n * What the category editor knows and `wx-catalog-facets` needs: which category it is, so that the\n * field can say whose setting it inherits — the parent's, the grandparent's, or nobody's (§6.2).\n */\nexport interface CategoryEditorContext {\n category: Ref<CategoryRow | null>\n /** Closed for writing — what the screen's form says to its own controls, for the ones it cannot. */\n locked: Ref<boolean>\n /**\n * The server's answer to \"whose facet setting does it show\" (`facets_from`): the ancestor, `null`\n * for its own or the default, `undefined` when the server did not say.\n */\n facetsFrom: Ref<{ id: number; name: string } | null | undefined>\n}\n\nexport const categoryEditorKey: InjectionKey<CategoryEditorContext> = Symbol('wx-catalog-category')\n\nexport function provideCatalogCategoryEditor(editor: CategoryEditorContext): void {\n provide(categoryEditorKey, editor)\n}\n\nexport function useCatalogCategoryEditor(): CategoryEditorContext | null {\n return inject(categoryEditorKey, null)\n}\n","<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","<script setup lang=\"ts\">\nimport { computed, onMounted } from 'vue'\nimport { useAdmin, useRecordAddress, useTranslate } from '@webx-ui/module-admin'\nimport { WxTreeSelect, type TreeSelectValue } from '@webx-ui/core'\nimport { useCatalogMessages } from './i18n'\nimport { useCategoryTree } from './store'\nimport type { CategoryNode } from './types'\n\n/**\n * `wx-catalog-category`: a category of the catalogue, or several with `props.multiple`.\n *\n * A tree and not a flat list, because the tree is how anybody finds a shelf — \"Laptops\" means\n * nothing until it is seen under \"Computers\" — and a single choice shows its whole path once\n * picked, for the same reason.\n *\n * The additional categories cannot include the main one (decision 2): the server would drop it\n * anyway, and a picker that lets somebody tick what will silently not be saved is a picker that\n * lies. The main one is read off the form the editor hosts.\n *\n * Nothing but `multiple` is declared: a wrapper that declared what `WxTreeSelect` takes would hand\n * it a `false` where the screen asked for nothing (CLAUDE.md §4).\n */\ndefineOptions({ name: 'WxCatalogCategoryField', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<{ multiple?: boolean }>(), { multiple: false })\n\nconst value = defineModel<number | number[] | null>({ default: null })\n\nconst admin = useAdmin()\nconst tree = useCategoryTree(admin)\nconst address = useRecordAddress()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\n\ntype Choice = CategoryNode & { locked?: boolean }\n\n/** The main category, for the list of the others to leave out. */\nconst main = computed(() => {\n const chosen = address?.values.value.category_id\n\n return typeof chosen === 'number' ? chosen : null\n})\n\nconst nodes = computed<Choice[]>(() => {\n const mark = (list: CategoryNode[]): Choice[] =>\n list.map((node) => ({\n ...node,\n locked: props.multiple && node.id === main.value,\n children: mark(node.children ?? []),\n }))\n\n return mark(tree.nodes.value ?? [])\n})\n\nconst model = computed<TreeSelectValue>({\n get: () => {\n if (props.multiple) return Array.isArray(value.value) ? value.value : []\n\n return typeof value.value === 'number' ? value.value : null\n },\n set: (next) => {\n if (props.multiple) {\n const ids = (Array.isArray(next) ? next : []).map(Number)\n value.value = ids.filter((id) => id !== main.value)\n\n return\n }\n\n value.value = next === null || next === undefined || Array.isArray(next) ? null : Number(next)\n },\n})\n\nonMounted(() => {\n // A tree that did not arrive leaves the chosen ids where they are, drawn by number; the form\n // still saves what it opened with.\n void tree.load().catch(() => undefined)\n})\n</script>\n\n<template>\n <wx-tree-select\n v-bind=\"$attrs\"\n v-model=\"model\"\n class=\"wx-catalog-category\"\n :nodes=\"nodes\"\n :multiple=\"props.multiple\"\n :check-strictly=\"props.multiple\"\n node-key=\"id\"\n label-key=\"name\"\n children-key=\"children\"\n disabled-key=\"locked\"\n :show-path=\"!props.multiple\"\n separator=\" / \"\n filterable\n clearable\n default-expand-all\n teleport\n :placeholder=\"props.multiple ? t('panel.pick-categories') : t('panel.pick-category')\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n rowMenuWidth,\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n} from '@webx-ui/module-admin'\nimport {\n toast,\n WxBadge,\n WxTable,\n WxText,\n type Paginated,\n type TabItem,\n type TableColumn,\n type TableState,\n type TabValue,\n} from '@webx-ui/core'\nimport { createCatalogApi } from './api'\nimport { useCatalogMessages } from './i18n'\nimport { useCategoryTree } from './store'\nimport type { CategoryRef, DeletedCategory, DeletedKind, DeletedProduct } from './types'\n\n/**\n * «Deleted» (§5, §6.3): what was deleted, and the one thing that can be done to it — bring it\n * back. There is no \"delete for ever\": orders will point at products, and their links have to\n * keep answering. No filters either; a search finds what somebody is looking for, and the list\n * is newest first, which is where a regret usually is.\n *\n * Products and categories are two tabs of one screen rather than two screens, because the\n * question a reader comes with is \"where did it go\", not which kind of thing it was.\n *\n * A row says what a restore will do to it before it is done: a product whose category is\n * deleted too comes back without one and unpublished, and that is worth knowing first.\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()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\nconst message = useErrorText()\n\ntype Row = DeletedProduct | DeletedCategory\n\nconst page = ref<Paginated<Row> | null>(null)\nconst loading = ref(true)\nconst search = ref(typeof route.query.q === 'string' ? route.query.q : '')\n\nconst canRestore = computed(() => context.can('catalog.delete'))\n\nconst kind = computed<TabValue>({\n get: () => (route.query.type === 'categories' ? 'categories' : 'products'),\n set: (value) => {\n // The table is keyed by the tab and mounts afresh, which asks for its first page itself.\n search.value = ''\n page.value = null\n void router.replace({\n query: { type: value === 'categories' ? 'categories' : undefined },\n })\n },\n})\n\nconst views = computed<TabItem[]>(() => [\n { value: 'products', label: t('module.products') },\n { value: 'categories', label: t('module.categories') },\n])\n\nconst columns = computed<TableColumn<Row>[]>(() =>\n kind.value === 'categories'\n ? [\n { key: 'name', label: t('category.name'), minWidth: 200 },\n { key: 'parent', label: t('panel.column-parent'), width: 200, hideBelow: 640 },\n { key: 'deleted_at', label: t('panel.column-deleted'), width: 150 },\n { key: 'actions', label: '', width: rowMenuWidth, align: 'right' },\n ]\n : [\n { key: 'name', label: t('panel.column-product'), minWidth: 200 },\n { key: 'category', label: t('product.category'), width: 220, hideBelow: 640 },\n { key: 'deleted_at', label: t('panel.column-deleted'), width: 150 },\n { key: 'actions', label: '', width: rowMenuWidth, align: 'right' },\n ],\n)\n\nlet asked = 0\n\nasync function load(state?: TableState): Promise<void> {\n const mine = ++asked\n\n loading.value = true\n\n try {\n const answer = await api.deleted(kind.value as DeletedKind, {\n q: state?.search ?? search.value,\n page: state?.page,\n per_page: state?.perPage,\n })\n\n if (mine === asked) page.value = answer\n } catch (error) {\n toast.danger(message(error))\n } finally {\n if (mine === asked) loading.value = false\n }\n}\n\nfunction onState(state: TableState): void {\n void router.replace({\n query: { ...route.query, q: state.search === '' ? undefined : state.search },\n })\n void load(state)\n}\n\nasync function restore(row: Row): Promise<void> {\n try {\n if (kind.value === 'categories') {\n await api.restoreCategory(row.id)\n tree.drop()\n toast.success(t('panel.category-restored'))\n } else {\n const product = await api.restoreProduct(row.id)\n const bare = product.category === null && (row as DeletedProduct).category !== null\n\n toast.success(bare ? t('panel.product-restored-bare') : t('panel.product-restored'))\n }\n\n await load()\n } catch (error) {\n // A category whose address was taken while it was away is refused, and the server says by whom.\n toast.danger(message(error))\n }\n}\n\n/** A product's category or a category's parent, as the row names it. */\nfunction refOf(row: Record<string, unknown>, key: 'category' | 'parent'): CategoryRef | null {\n const found = row[key]\n\n return found && typeof found === 'object' ? (found as CategoryRef) : null\n}\n\nfunction actionsFor(row: Row): RowAction[] {\n const actions: RowAction[] = []\n\n if (canRestore.value) {\n actions.push({\n key: 'restore',\n icon: 'refresh',\n label: t('panel.restore'),\n run: () => void restore(row),\n })\n }\n\n return actions\n}\n</script>\n\n<template>\n <div class=\"wx-catalog-deleted\">\n <wx-list-screen\n v-model:view=\"kind\"\n :title=\"t('module.deleted')\"\n :subtitle=\"t('panel.deleted-help')\"\n :back=\"`${props.base}/products`\"\n :back-label=\"t('module.products')\"\n :views=\"views\"\n >\n <wx-table\n :key=\"String(kind)\"\n v-model:search=\"search\"\n :data=\"page\"\n :columns=\"columns\"\n row-key=\"id\"\n searchable\n :clickable=\"false\"\n :hover=\"false\"\n flush\n layout=\"fixed\"\n :loading=\"loading\"\n :search-placeholder=\"t('panel.deleted-search')\"\n :empty-text=\"search ? t('panel.empty-search') : t('panel.deleted-empty')\"\n :aria-label=\"t('module.deleted')\"\n @state-change=\"onState\"\n >\n <template #cell-name=\"{ row }\">\n <div class=\"wx-catalog-deleted__name\">\n <span class=\"wx-catalog-deleted__title\">{{ row.name }}</span>\n <span v-if=\"'sku' in row && row.sku\" class=\"wx-catalog-deleted__code\">{{\n row.sku\n }}</span>\n <span v-else-if=\"'slug' in row && row.slug\" class=\"wx-catalog-deleted__code\">\n /{{ row.slug }}/\n </span>\n </div>\n </template>\n\n <template #cell-category=\"{ row }\">\n <wx-text v-if=\"!refOf(row, 'category')\" size=\"sm\" tone=\"muted\">\n {{ t('product.no-category') }}\n </wx-text>\n <span v-else class=\"wx-catalog-deleted__ref\">\n <wx-text\n size=\"sm\"\n truncate\n :tone=\"refOf(row, 'category')?.deleted ? 'muted' : undefined\"\n >\n {{ refOf(row, 'category')?.name }}\n </wx-text>\n <wx-badge v-if=\"refOf(row, 'category')?.deleted\" type=\"warning\" size=\"sm\" round>\n {{ t('panel.restore-bare') }}\n </wx-badge>\n </span>\n </template>\n\n <template #cell-parent=\"{ row }\">\n <wx-text v-if=\"!refOf(row, 'parent')\" size=\"sm\" tone=\"muted\">\n {{ t('panel.parent-root') }}\n </wx-text>\n <wx-text\n v-else\n size=\"sm\"\n truncate\n :tone=\"refOf(row, 'parent')?.deleted ? 'muted' : undefined\"\n >\n {{ refOf(row, 'parent')?.name }}\n <template v-if=\"refOf(row, 'parent')?.deleted\">\n ({{ t('panel.category-gone') }})</template\n >\n </wx-text>\n </template>\n\n <template #cell-deleted_at=\"{ row }\">\n <wx-date :value=\"row.deleted_at\" compact />\n </template>\n\n <template #cell-actions=\"{ row }\">\n <wx-row-menu v-if=\"canRestore\" :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-deleted {\n min-width: 0;\n}\n\n.wx-catalog-deleted__name {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.wx-catalog-deleted__title {\n font-weight: var(--wx-font-weight-medium);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wx-catalog-deleted__code {\n font-family: var(--wx-font-family-mono);\n font-size: var(--wx-font-size-sm);\n color: var(--wx-text-muted);\n}\n\n.wx-catalog-deleted__ref {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wx-space-4) var(--wx-space-8);\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref, watch } from 'vue'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport { WxAlert, WxSkeleton, WxSortableList, WxSwitch, WxText } from '@webx-ui/core'\nimport { createCatalogApi } from './api'\nimport { useCatalogCategoryEditor } from './editor'\nimport { useCatalogMessages } from './i18n'\nimport { useFacetRegistry } from './store'\nimport type { FacetInfo, FacetSetting } from './types'\n\n/**\n * `wx-catalog-facets`: which filters a category shows and in which order (§6.2).\n *\n * The value is `null` — the category takes the setting of its nearest ancestor that has one, or\n * every facet in the registry's order — or its own list. Off, the field says where the setting\n * comes from, because \"inherited\" alone leaves the reader to walk up the tree to find out what\n * that means. On, it is the list itself: dragged into order, each facet shown or not.\n *\n * Switching it on starts from what was inherited, not from a blank list: the reader wanted to\n * change one thing about the setting they were looking at.\n *\n * A facet registered after the setting was written is not in it, and is shown here switched off\n * — a new module does not get to change somebody else's filters on its own (§6.2). A key whose\n * module has gone is kept as it is: putting the module back brings the setting back with it.\n */\ndefineOptions({ name: 'WxCatalogFacetsField' })\n\nconst value = defineModel<FacetSetting[] | null>({ default: null })\n\nconst admin = useAdmin()\nconst api = createCatalogApi(admin)\nconst registry = useFacetRegistry(admin)\nconst editor = useCatalogCategoryEditor()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\n\nconst loading = ref(true)\nconst failed = ref(false)\n/** The nearest ancestor with a setting of its own, or `null` — the registry's order. */\nconst source = ref<{ name: string; rows: FacetSetting[] } | null>(null)\n\nconst facets = computed<FacetInfo[]>(() => registry.facets.value ?? [])\nconst labels = computed(() => new Map(facets.value.map((facet) => [facet.key, facet.label])))\n\nconst own = computed(() => Array.isArray(value.value))\nconst locked = computed(() => editor?.locked.value ?? false)\n\ninterface Row extends FacetSetting {\n label: string\n known: boolean\n}\n\n/** The setting with every facet the registry has that it does not, switched off, at the end. */\nfunction complete(rows: FacetSetting[]): FacetSetting[] {\n const named = new Set(rows.map((row) => row.key))\n\n return [\n ...rows.map((row) => ({ key: row.key, visible: row.visible })),\n ...facets.value\n .filter((facet) => !named.has(facet.key))\n .map((facet) => ({ key: facet.key, visible: false })),\n ]\n}\n\nconst inherited = computed<FacetSetting[]>(() =>\n source.value === null\n ? facets.value.map((facet) => ({ key: facet.key, visible: true }))\n : complete(source.value.rows),\n)\n\nconst rows = computed<Row[]>({\n get: () =>\n complete(value.value ?? []).map((row) => ({\n ...row,\n label: labels.value.get(row.key) ?? row.key,\n known: labels.value.has(row.key),\n })),\n set: (next) => {\n value.value = next.map((row) => ({ key: row.key, visible: row.visible }))\n },\n})\n\n/** What a visitor of the category sees while it inherits: the names, in order. */\nconst inheritedNames = computed(() =>\n inherited.value\n .filter((row) => row.visible && labels.value.has(row.key))\n .map((row) => labels.value.get(row.key))\n .join(', '),\n)\n\nfunction toggleOwn(on: boolean | string | number | null): void {\n value.value = on ? inherited.value.map((row) => ({ ...row })) : null\n}\n\nfunction show(key: string, visible: boolean | string | number | null): void {\n rows.value = rows.value.map((row) =>\n row.key === key ? { ...row, visible: Boolean(visible) } : row,\n )\n}\n\n/**\n * Whose setting this is. The server names the ancestor (`facets_from`), and one request reads\n * its rows — the setting is shown, not only named. A server that does not say is walked up the\n * tree from the parent until somebody has a setting of their own, one request per level.\n */\nasync function findSource(parent: number | null): Promise<void> {\n const from = editor?.facetsFrom.value\n\n source.value = null\n\n if (from === null) return\n\n if (from !== undefined) {\n const detail = await api.category(from.id)\n\n if (Array.isArray(detail.values.facets)) {\n source.value = { name: from.name, rows: detail.values.facets as FacetSetting[] }\n }\n\n return\n }\n\n let next = parent\n\n while (next !== null) {\n const detail = await api.category(next)\n const setting = detail.values.facets\n\n if (Array.isArray(setting)) {\n source.value = { name: detail.category.name, rows: setting as FacetSetting[] }\n\n return\n }\n\n next = detail.category.parent_id\n }\n}\n\nasync function load(): Promise<void> {\n loading.value = true\n failed.value = false\n\n try {\n await Promise.all([registry.load(), findSource(editor?.category.value?.parent_id ?? null)])\n } catch {\n failed.value = true\n } finally {\n loading.value = false\n }\n}\n\n/* A move or a save changes whose setting it is; the editor hands both over with the answer. */\nwatch(\n () => [editor?.category.value?.parent_id, JSON.stringify(editor?.facetsFrom.value)],\n (now, before) => {\n if (now[0] !== before[0] || now[1] !== before[1]) void load()\n },\n)\n\nonMounted(load)\n</script>\n\n<template>\n <div class=\"wx-catalog-facets\">\n <wx-skeleton v-if=\"loading\" :rows=\"3\" />\n\n <wx-alert\n v-else-if=\"failed\"\n type=\"warning\"\n variant=\"soft\"\n :description=\"t('panel.facets-failed')\"\n />\n\n <template v-else>\n <div class=\"wx-catalog-facets__own\">\n <wx-switch\n :model-value=\"own\"\n :disabled=\"locked\"\n :label=\"t('panel.facets-own')\"\n @update:model-value=\"toggleOwn\"\n />\n <wx-text size=\"sm\" tone=\"muted\">\n {{ own ? t('panel.facets-own-help') : t('panel.facets-inherited-help') }}\n </wx-text>\n </div>\n\n <div v-if=\"!own\" class=\"wx-catalog-facets__inherited\">\n <wx-text weight=\"medium\">\n {{\n source ? t('panel.facets-inherited', { name: source.name }) : t('panel.facets-default')\n }}\n </wx-text>\n <wx-text v-if=\"inheritedNames\" size=\"sm\" tone=\"muted\">{{ inheritedNames }}</wx-text>\n <wx-text v-else-if=\"facets.length === 0\" size=\"sm\" tone=\"muted\">\n {{ t('panel.facets-empty') }}\n </wx-text>\n </div>\n\n <wx-sortable-list\n v-else\n v-model=\"rows\"\n size=\"sm\"\n item-key=\"key\"\n item-label=\"label\"\n :disabled=\"locked\"\n :empty-text=\"t('panel.facets-empty')\"\n >\n <template #default=\"{ item }\">\n <span class=\"wx-catalog-facets__name\" :class=\"{ 'is-off': !(item as Row).visible }\">\n {{ (item as Row).label }}\n </span>\n <wx-text v-if=\"!(item as Row).known\" size=\"sm\" tone=\"muted\">\n {{ t('panel.facets-unknown') }}\n </wx-text>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-switch\n size=\"sm\"\n :model-value=\"(item as Row).visible\"\n :disabled=\"locked || !(item as Row).known\"\n :aria-label=\"`${t('panel.facets-shown')}: ${(item as Row).label}`\"\n @update:model-value=\"(on) => show((item as Row).key, on)\"\n />\n </template>\n </wx-sortable-list>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-catalog-facets {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n}\n\n.wx-catalog-facets__own,\n.wx-catalog-facets__inherited {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-4);\n}\n\n.wx-catalog-facets :deep(.wx-sortable-list__content) {\n display: flex;\n align-items: center;\n gap: var(--wx-space-8);\n min-width: 0;\n}\n\n.wx-catalog-facets__name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Hidden facets stay in the list — their place is part of the setting — but read as switched off. */\n.wx-catalog-facets__name.is-off {\n color: var(--wx-text-muted);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n confirm,\n toast,\n WxAction,\n WxAlert,\n WxBadge,\n WxButton,\n WxFormItem,\n WxInput,\n WxSortableList,\n WxText,\n WxUpload,\n type LocalizedValue,\n type UploadFile,\n} from '@webx-ui/core'\nimport { createCatalogApi } from './api'\nimport { useProductEditor } from './editor'\nimport { useCatalogMessages } from './i18n'\nimport type { ProductImage } from './types'\n\n/**\n * `wx-catalog-gallery`: the pictures of the product being edited (§10.4, §11.1).\n *\n * Not a value of the form. A picture is a record of its own with files on the disk, so adding one\n * is a request the moment it is chosen, deleting one deletes its files at once, and the order and\n * the captions are one request for the whole gallery — the editor's \"Save\" has nothing to do with\n * any of it. That is also why this node has no `name`: there is nothing for the form to carry.\n *\n * The captions save themselves a moment after the last keystroke, like a draft does elsewhere in\n * the panel; a reorder saves on the drop. Both send the whole gallery in its order, which is what\n * the server takes (`PUT …/images`).\n */\ndefineOptions({ name: 'WxCatalogGallery' })\n\n/** How long after the last keystroke the captions go to the server. */\nconst PAUSE = 800\n\nconst admin = useAdmin()\nconst api = createCatalogApi(admin)\nconst editor = useProductEditor()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\nconst message = useErrorText()\n\nconst uploads = ref<UploadFile[]>([])\nconst address = ref('')\nconst fetching = ref(false)\n\nconst productId = computed(() => editor?.product.value?.id ?? null)\nconst locked = computed(() => editor === null || editor.locked.value)\n\n/** Writable, because that is how `WxSortableList` hands a reorder back. */\nconst images = computed<ProductImage[]>({\n get: () => editor?.images.value ?? [],\n set: (next) => {\n if (editor) editor.images.value = next\n },\n})\n\n/* What was sent last, so an answer that arrives after further typing does not undo it. */\nlet timer: ReturnType<typeof setTimeout> | undefined\nlet sent = ''\n\nfunction captions(list: ProductImage[]): string {\n return JSON.stringify(list.map((image) => [image.id, image.alt, image.title]))\n}\n\nasync function saveGallery(failure: string): Promise<void> {\n const id = productId.value\n\n if (id === null) return\n\n clearTimeout(timer)\n const carrying = captions(images.value)\n sent = carrying\n\n try {\n const answer = await api.saveImages(id, images.value)\n\n // Typed on while the request was out: keep what is on screen; the next pause sends it.\n if (captions(images.value) === carrying) images.value = answer\n } catch (error) {\n toast.danger(`${failure} ${message(error)}`)\n }\n}\n\nfunction caption(image: ProductImage, field: 'alt' | 'title', text: unknown): void {\n images.value = images.value.map((one) =>\n one.id === image.id ? { ...one, [field]: (text ?? {}) as LocalizedValue } : one,\n )\n\n clearTimeout(timer)\n timer = setTimeout(() => void saveGallery(t('panel.gallery-captions-failed')), PAUSE)\n}\n\nfunction moved(): void {\n void saveGallery(t('panel.gallery-reorder-failed'))\n}\n\n/**\n * One file after another rather than all at once: the server numbers them in the order they\n * arrive, and a gallery whose order is whichever upload finished first is not the order anybody\n * chose them in.\n */\nasync function add(files: UploadFile[]): Promise<void> {\n const id = productId.value\n\n if (id === null) return\n\n for (const file of files) {\n if (!file.raw) continue\n\n const mark = (patch: Partial<UploadFile>) => {\n uploads.value = uploads.value.map((one) => (one.id === file.id ? { ...one, ...patch } : one))\n }\n\n mark({ status: 'uploading', progress: 0 })\n\n try {\n const image = await api.addImage(id, file.raw, (progress) => mark({ progress }))\n\n images.value = [...images.value, image]\n uploads.value = uploads.value.filter((one) => one.id !== file.id)\n } catch (error) {\n mark({ status: 'error', error: message(error) })\n }\n }\n}\n\nasync function fetchAddress(): Promise<void> {\n const id = productId.value\n const url = address.value.trim()\n\n if (id === null || url === '') return\n\n fetching.value = true\n\n try {\n images.value = [...images.value, await api.addImage(id, url)]\n address.value = ''\n } catch (error) {\n toast.danger(`${t('panel.gallery-failed')} ${message(error)}`)\n } finally {\n fetching.value = false\n }\n}\n\nasync function remove(image: ProductImage): Promise<void> {\n const id = productId.value\n\n if (id === null) return\n\n const agreed = await confirm({\n title: t('panel.gallery-remove-title'),\n message: t('panel.gallery-remove-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.removeImage(id, image.id)\n images.value = images.value.filter((one) => one.id !== image.id)\n toast.success(t('panel.gallery-removed'))\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\n/* Leaving with a pause still running: send it rather than drop the last words typed. */\nonBeforeUnmount(() => {\n if (timer !== undefined && captions(images.value) !== sent) void saveGallery('')\n clearTimeout(timer)\n})\n</script>\n\n<template>\n <div class=\"wx-catalog-gallery\">\n <wx-alert v-if=\"!editor\" type=\"info\" variant=\"soft\" :description=\"t('panel.gallery-empty')\" />\n\n <template v-else>\n <wx-alert\n v-if=\"locked && images.length === 0\"\n type=\"info\"\n variant=\"soft\"\n :description=\"t('panel.gallery-locked')\"\n />\n\n <wx-sortable-list\n v-if=\"images.length > 0\"\n v-model=\"images\"\n class=\"wx-catalog-gallery__list\"\n item-key=\"id\"\n :item-label=\"(image: ProductImage) => image.path.split('/').pop() ?? String(image.id)\"\n :disabled=\"locked\"\n :title=\"t('panel.gallery-order')\"\n @move=\"moved\"\n >\n <template #default=\"{ item, index }\">\n <div class=\"wx-catalog-gallery__item\">\n <a\n class=\"wx-catalog-gallery__thumb\"\n :href=\"(item as ProductImage).url\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n <img :src=\"(item as ProductImage).thumb ?? (item as ProductImage).url\" alt=\"\" />\n <wx-badge\n v-if=\"index === 0\"\n class=\"wx-catalog-gallery__main\"\n type=\"primary\"\n size=\"sm\"\n >\n {{ t('panel.gallery-main') }}\n </wx-badge>\n </a>\n\n <div class=\"wx-catalog-gallery__words\">\n <wx-form-item :label=\"t('panel.gallery-alt')\" :help=\"t('panel.gallery-alt-help')\">\n <wx-input\n :model-value=\"(item as ProductImage).alt\"\n localized\n size=\"sm\"\n :disabled=\"locked\"\n @update:model-value=\"(text) => caption(item as ProductImage, 'alt', text)\"\n />\n </wx-form-item>\n\n <wx-form-item :label=\"t('panel.gallery-title')\">\n <wx-input\n :model-value=\"(item as ProductImage).title\"\n localized\n size=\"sm\"\n :disabled=\"locked\"\n @update:model-value=\"(text) => caption(item as ProductImage, 'title', text)\"\n />\n </wx-form-item>\n\n <wx-text\n v-if=\"(item as ProductImage).width && (item as ProductImage).height\"\n size=\"sm\"\n tone=\"muted\"\n >\n {{ (item as ProductImage).width }} × {{ (item as ProductImage).height }}\n </wx-text>\n </div>\n </div>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-action\n v-if=\"!locked\"\n type=\"remove\"\n size=\"sm\"\n :title=\"t('panel.delete')\"\n @click=\"remove(item as ProductImage)\"\n />\n </template>\n </wx-sortable-list>\n\n <wx-text v-else-if=\"!locked\" tone=\"muted\">{{ t('panel.gallery-empty') }}</wx-text>\n\n <template v-if=\"!locked\">\n <wx-upload\n v-model=\"uploads\"\n accept=\"image/jpeg,image/png,image/webp,image/gif\"\n multiple\n :button-text=\"t('panel.gallery-add')\"\n :hint=\"t('panel.gallery-hint')\"\n @add=\"add\"\n />\n\n <!-- Not a <form>: the gallery stands inside the screen's own, and Enter here must fetch\n the picture rather than submit the product. -->\n <wx-form-item :label=\"t('panel.gallery-url')\">\n <div class=\"wx-catalog-gallery__address\">\n <wx-input\n v-model=\"address\"\n type=\"url\"\n size=\"sm\"\n placeholder=\"https://\"\n @keydown.enter.prevent=\"fetchAddress\"\n />\n <wx-button\n size=\"sm\"\n variant=\"outline\"\n :loading=\"fetching\"\n :disabled=\"address.trim() === ''\"\n @click=\"fetchAddress\"\n >\n {{ t('panel.gallery-url-add') }}\n </wx-button>\n </div>\n </wx-form-item>\n </template>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-catalog-gallery {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-16);\n container-type: inline-size;\n}\n\n.wx-catalog-gallery :deep(.wx-sortable-list__content) {\n min-width: 0;\n}\n\n.wx-catalog-gallery__item {\n display: grid;\n grid-template-columns: 96px minmax(0, 1fr);\n gap: var(--wx-space-16);\n align-items: start;\n padding-block: var(--wx-space-8);\n}\n\n.wx-catalog-gallery__thumb {\n position: relative;\n display: block;\n width: 96px;\n aspect-ratio: 1;\n overflow: clip;\n border-radius: var(--wx-radius-sm);\n background: var(--wx-bg-subtle);\n border: 1px solid var(--wx-border-default);\n}\n\n.wx-catalog-gallery__thumb img {\n width: 100%;\n height: 100%;\n min-width: 0;\n object-fit: contain;\n display: block;\n}\n\n.wx-catalog-gallery__main {\n position: absolute;\n inset-inline-start: var(--wx-space-4);\n inset-block-start: var(--wx-space-4);\n}\n\n/* Two fields side by side while there is room for two readable lines of text, stacked below. */\n.wx-catalog-gallery__words {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--wx-space-8);\n}\n\n@container (min-width: 640px) {\n .wx-catalog-gallery__words {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .wx-catalog-gallery__words > .wx-text {\n grid-column: 1 / -1;\n }\n}\n\n/* A phone: the picture above its words rather than a narrow column beside them. */\n@container (max-width: 420px) {\n .wx-catalog-gallery__item {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.wx-catalog-gallery__address {\n display: flex;\n gap: var(--wx-space-8);\n align-items: center;\n max-width: 560px;\n}\n\n.wx-catalog-gallery__address > :first-child {\n flex: 1;\n min-width: 0;\n}\n</style>\n","<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 WxAlert,\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 { provideProductEditor } from './editor'\nimport { useCatalogMessages } from './i18n'\nimport { lastSegment } from './paths'\nimport type { ProductDetail, ProductImage, ProductRow, SkuHolder } from './types'\n\n/**\n * One product: a head, `catalog.product-form` under it, and one button (§11.1).\n *\n * One explicit save, as a category has: a product has no draft (decision 14), so what is saved is\n * on the site at once — a price that changes between two keystrokes is not something to do behind\n * the editor's back. The gallery is the exception and saves itself: its pictures are records of\n * their own, not values of this form (`GalleryField.vue`).\n *\n * The article number is unique across deleted products too (decision 5), so a refusal names the\n * product holding it — and this page turns that into a way to it, which a line under the field\n * cannot be.\n */\ndefineOptions({ name: 'WxCatalogProductEditor' })\n\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/catalog' })\n\nconst context = useAdmin()\nconst api = createCatalogApi(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}/products`)\n\nconst product = ref<ProductRow | null>(null)\nconst values = ref<ScreenModel>({})\nconst images = ref<ProductImage[]>([])\nconst snapshot = ref('')\n\nconst loading = ref(true)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\nconst holder = ref<SkuHolder | null>(null)\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\nconst section = computed(\n () =>\n context.state.manifest?.modules.find((module) => module.id === 'catalog')?.title ??\n t('module.title'),\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, product.value?.name ?? '') || t('panel.untitled')\n )\n})\n\n/**\n * What the site does with it, under the name. Published but seen by nobody is the one state worth\n * a sentence: every other is what the badge beside the name already says.\n */\nconst subtitle = computed(() => {\n const row = product.value\n\n if (!row) return undefined\n\n if (row.is_published && !row.visible) return t('panel.invisible')\n\n return row.sku ?? undefined\n})\n\nprovideProductEditor({ product, images, locked })\nprovideHistorySubject({ id: computed(() => product.value?.id ?? null) })\n\n/*\n * The address field is the panel's shared one (`wx-slug`). A product answers at `/{slug}-{id}`\n * (§4), so what is compared with the slug being typed is the registry's address without its\n * number — otherwise every product would look like one whose address is about to move.\n */\nprovideRecordAddress({\n values,\n prefix: ref(''),\n path: computed(() => {\n const segment = lastSegment(product.value?.url)\n\n return segment?.replace(new RegExp(`-${product.value?.id}$`), '') ?? null\n }),\n moving: () => t('panel.address-moving'),\n})\n\nfunction take(detail: ProductDetail): void {\n product.value = detail.product\n values.value = detail.values\n images.value = detail.images\n snapshot.value = JSON.stringify(detail.values)\n}\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n take(await api.product(id.value))\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 (!product.value || saving.value || !canManage.value) return\n\n saving.value = true\n errors.value = {}\n holder.value = null\n\n try {\n // The gallery is not sent: it saves itself, and the answer carries it as the server has it.\n take(await api.saveProduct(product.value.id, values.value))\n toast.success(t('panel.saved'))\n } catch (error) {\n const body = (\n error as {\n body?: { errors?: Record<string, string[]>; meta?: { taken_by?: SkuHolder } }\n }\n ).body\n\n if (body?.errors && Object.keys(body.errors).length > 0) {\n errors.value = body.errors\n holder.value = body.meta?.taken_by ?? null\n toast.danger(t('panel.save-failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n\n/**\n * Where the product holding the article number is opened: its editor, or «Deleted» searched by\n * that number — a deleted product has no editor, and the only way back to it is a restore.\n */\nconst holderLink = computed(() => {\n const found = holder.value\n\n if (!found) return null\n\n if (found.deleted) {\n const sku = typeof values.value.sku === 'string' ? values.value.sku : ''\n\n return { path: `${props.base}/deleted`, query: sku ? { q: sku } : {} }\n }\n\n return { path: `${props.base}/products/${found.id}` }\n})\n\nasync function remove(): Promise<void> {\n const row = product.value\n\n if (!row) return\n\n const agreed = await confirm({\n title: t('panel.delete-product-title', { name: row.name }),\n message: t('panel.delete-product-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.removeProduct(row.id)\n toast.success(t('panel.product-deleted'))\n // Nothing left to protect: the product is in «Deleted», and asking about its unsaved edits on\n // the way out would be asking about a page that is gone.\n snapshot.value = current.value\n void router.push(list.value)\n } catch (error) {\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\n/* Ctrl+S saves, as it does everywhere else that has a save button. */\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\n/*\n * What leads away from the product. \"Open on the site\" is there for an unpublished one too: it\n * answers with the trimmed page (§5), and that page is what a visitor with an old link sees.\n */\nconst actions = computed<ScreenAction[]>(() => {\n const row = product.value\n const leads: ScreenAction[] = []\n\n if (!row) return leads\n\n if (row.url) {\n leads.push({ key: 'site', label: t('panel.open-on-site'), icon: 'link', href: row.url })\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-product\" @keydown=\"onKeydown\">\n <template v-if=\"loading || !product\">\n <!-- Shaped like the screen it stands in for: the head, and a card for what is coming. -->\n <wx-skeleton class=\"wx-catalog-product__ghost\" title :rows=\"1\" />\n <wx-card><wx-skeleton :rows=\"8\" /></wx-card>\n </template>\n\n <template v-else>\n <wx-screen-head\n divider\n :back=\"list\"\n :back-label=\"t('module.products')\"\n :title=\"title\"\n :subtitle=\"subtitle\"\n :actions=\"actions\"\n >\n <template #trail>\n <wx-breadcrumb size=\"sm\" :label=\"t('panel.product-trail')\">\n <wx-breadcrumb-item :as=\"'router-link'\" :to=\"list\">{{ section }}</wx-breadcrumb-item>\n <wx-breadcrumb-item v-if=\"product.category\" current>\n {{ product.category.name }}\n </wx-breadcrumb-item>\n <wx-breadcrumb-item v-else current>{{ t('product.no-category') }}</wx-breadcrumb-item>\n </wx-breadcrumb>\n </template>\n\n <template #title-after>\n <wx-badge\n :type=\"product.is_published ? (product.visible ? 'success' : 'warning') : 'default'\"\n dot\n >\n {{ t(`states.${product.state}`) }}\n </wx-badge>\n <wx-badge v-if=\"!product.category\" type=\"warning\" round>\n {{ t('product.no-category') }}\n </wx-badge>\n </template>\n </wx-screen-head>\n\n <!-- The article number is somebody else's: say whose, and take the reader there. Kept above\n the tabs, because the field it is about may be on a tab nobody is looking at. -->\n <wx-alert\n v-if=\"holder && holderLink\"\n type=\"warning\"\n :description=\"errors.sku?.[0] ?? ''\"\n closable\n @close=\"holder = null\"\n >\n <template #actions>\n <wx-button size=\"sm\" variant=\"outline\" @click=\"router.push(holderLink)\">\n {{ holder.deleted ? t('panel.sku-open-deleted') : t('panel.sku-open') }}\n </wx-button>\n </template>\n </wx-alert>\n\n <wx-screen v-model=\"values\" name=\"catalog.product-form\" :errors=\"errors\" :disabled=\"locked\" />\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-product {\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-product__ghost {\n max-width: 420px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, reactive } from 'vue'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport {\n useModal,\n WxButton,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSelect,\n WxSpace,\n WxText,\n WxTreeSelect,\n type SelectOption,\n type TreeSelectValue,\n} from '@webx-ui/core'\nimport { useCatalogMessages } from './i18n'\nimport { useCategoryTree } from './store'\nimport type { BulkActionInfo, BulkParam } from './types'\n\n/**\n * What a bulk action asks for before it runs — a category, a label — and the last word before it\n * does: how many products it is about to touch. The fields are drawn from what the server said\n * about the action, so a satellite's action gets its dialog without this file knowing it.\n */\nconst props = defineProps<{ action: BulkActionInfo; count: number }>()\n\nconst { open, resolve, dismiss } = useModal<Record<string, unknown>>()\n\nconst context = useAdmin()\nconst tree = useCategoryTree(context)\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\n\nconst values = reactive<Record<string, unknown>>({})\n\nconst ready = computed(() =>\n props.action.params.every(\n (param) =>\n !param.rules?.includes('required') ||\n (values[param.name] !== undefined &&\n values[param.name] !== null &&\n values[param.name] !== ''),\n ),\n)\n\nonMounted(() => {\n if (props.action.params.some((param) => param.type === 'category')) {\n void tree.load().catch(() => undefined)\n }\n})\n\nfunction optionsOf(param: BulkParam): SelectOption[] {\n return Array.isArray(param.values)\n ? param.values.map((one) =>\n typeof one === 'object'\n ? { value: one.value, label: one.label }\n : { value: one, label: String(one) },\n )\n : []\n}\n\nfunction onCategory(param: BulkParam, value: TreeSelectValue): void {\n values[param.name] = Array.isArray(value) ? (value[0] ?? null) : value\n}\n\nfunction apply(): void {\n if (ready.value) resolve({ ...values })\n}\n</script>\n\n<template>\n <wx-dialog\n v-model:open=\"open\"\n :title=\"t('panel.bulk-confirm-title', { action: action.label })\"\n :width=\"440\"\n >\n <wx-text tone=\"muted\" size=\"sm\">{{ t('panel.bulk-confirm-text', { count }) }}</wx-text>\n\n <wx-form-item\n v-for=\"param in action.params\"\n :key=\"param.name\"\n :label=\"param.label\"\n :required=\"param.rules?.includes('required')\"\n class=\"wx-catalog-bulk-params__field\"\n >\n <wx-tree-select\n v-if=\"param.type === 'category'\"\n :model-value=\"(values[param.name] as number | null | undefined) ?? null\"\n :nodes=\"tree.nodes.value ?? []\"\n node-key=\"id\"\n label-key=\"name\"\n children-key=\"children\"\n check-strictly\n filterable\n :filter-placeholder=\"t('panel.search-categories')\"\n :aria-label=\"param.label\"\n @update:model-value=\"(value: TreeSelectValue) => onCategory(param, value)\"\n />\n <wx-select\n v-else-if=\"Array.isArray(param.values)\"\n :model-value=\"(values[param.name] as string | number | undefined) ?? null\"\n :options=\"optionsOf(param)\"\n :aria-label=\"param.label\"\n @update:model-value=\"(value: unknown) => (values[param.name] = value)\"\n />\n <wx-input v-else v-model=\"values[param.name] as string\" :aria-label=\"param.label\" />\n </wx-form-item>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button\n :type=\"action.permission === 'catalog.delete' && !action.trashed ? 'danger' : 'primary'\"\n :disabled=\"!ready\"\n @click=\"apply\"\n >\n {{ t('panel.bulk-apply') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n\n<style scoped>\n.wx-catalog-bulk-params__field {\n margin-top: var(--wx-space-16);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\nimport { useAdmin, useErrorText, useTranslate } from '@webx-ui/module-admin'\nimport {\n createModal,\n toast,\n WxButton,\n WxDropdown,\n WxDropdownItem,\n WxIcon,\n WxProgress,\n WxText,\n} from '@webx-ui/core'\nimport BulkParamsDialog from './BulkParamsDialog.vue'\nimport { createCatalogApi } from './api'\nimport { useCatalogMessages } from './i18n'\nimport type { BulkActionInfo, BulkRun, BulkSelection } from './types'\n\n/**\n * The actions over what is picked in the list (§11.4), and the run they start.\n *\n * Which actions there are is the server's answer — the core's and every satellite's, only the\n * ones this administrator may start. A small selection is done inside the request and answered at\n * once; a large one is a run in the background, polled here with its progress, and its refusals\n * are listed by product when it ends. The list reloads either way, and `finished` carries the ids\n * that refused — what the list leaves picked, so they can be put right and tried again.\n */\nconst props = defineProps<{ count: number; selection: BulkSelection }>()\nconst emit = defineEmits<{ finished: [refused: number[]] }>()\n\n/** Often enough to look alive, rarely enough that a run of forty thousand is not a request storm. */\nconst POLL = 1500\n\nconst context = useAdmin()\nconst api = createCatalogApi(context)\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\nconst message = useErrorText()\n\nconst params = createModal<Record<string, unknown>, { action: BulkActionInfo; count: number }>(\n BulkParamsDialog,\n)\n\nconst actions = ref<BulkActionInfo[]>([])\nconst run = ref<BulkRun | null>(null)\nconst starting = ref(false)\nlet timer: ReturnType<typeof setTimeout> | undefined\n\nconst running = computed(\n () => run.value !== null && (run.value.status === 'queued' || run.value.status === 'running'),\n)\nconst refused = computed(() =>\n run.value !== null && !running.value && run.value.failed > 0 ? run.value : null,\n)\n\nonMounted(async () => {\n try {\n actions.value = await api.bulkActions()\n } catch {\n actions.value = []\n }\n})\n\nonBeforeUnmount(() => clearTimeout(timer))\n\n/** An action that asks for something, or deletes, is said once more with the number in it. */\nfunction asks(action: BulkActionInfo): boolean {\n return action.params.length > 0 || (action.permission === 'catalog.delete' && !action.trashed)\n}\n\nasync function start(action: BulkActionInfo): Promise<void> {\n let given: Record<string, unknown> = {}\n\n if (asks(action)) {\n const answer = await params({ action, count: props.count })\n\n if (!answer) return\n given = answer\n }\n\n starting.value = true\n\n try {\n follow(await api.startBulk(action.key, given, props.selection))\n } catch (error) {\n toast.danger(message(error))\n } finally {\n starting.value = false\n }\n}\n\nfunction follow(answer: BulkRun): void {\n run.value = answer\n\n if (answer.status === 'queued' || answer.status === 'running') {\n timer = setTimeout(() => void poll(answer.id!), POLL)\n\n return\n }\n\n finish(answer)\n}\n\nasync function poll(id: number): Promise<void> {\n try {\n follow(await api.bulkRun(id))\n } catch {\n // A missed answer is not the end of the run: ask again.\n timer = setTimeout(() => void poll(id), POLL * 2)\n }\n}\n\nfunction finish(answer: BulkRun): void {\n if (answer.total === 0) toast.warning(t('panel.bulk-nothing'))\n else if (answer.status === 'failed') toast.danger(t('panel.bulk-stopped', { count: answer.done }))\n else if (answer.failed === 0) toast.success(t('panel.bulk-done', { count: answer.done }))\n\n if (answer.failed === 0 && answer.status !== 'failed') run.value = null\n\n emit(\n 'finished',\n answer.errors.map((error) => error.id),\n )\n}\n</script>\n\n<template>\n <div class=\"wx-catalog-bulk\">\n <wx-dropdown v-if=\"actions.length > 0 && !running\" align=\"start\">\n <template #trigger>\n <wx-button size=\"sm\" variant=\"outline\" :loading=\"starting\">\n {{ t('panel.bulk-actions') }}\n <wx-icon name=\"chevron-down\" size=\"sm\" />\n </wx-button>\n </template>\n\n <wx-dropdown-item\n v-for=\"action in actions\"\n :key=\"action.key\"\n :tone=\"action.permission === 'catalog.delete' && !action.trashed ? 'danger' : 'default'\"\n @click=\"start(action)\"\n >\n {{ action.label }}\n </wx-dropdown-item>\n </wx-dropdown>\n\n <div v-if=\"running && run\" class=\"wx-catalog-bulk__progress\" role=\"status\">\n <wx-progress\n :value=\"run.done + run.failed\"\n :max=\"Math.max(1, run.total)\"\n size=\"sm\"\n :aria-label=\"run.label\"\n />\n <wx-text size=\"sm\" tone=\"muted\">\n {{ run.label }} ·\n {{ t('panel.bulk-running', { done: run.done + run.failed, total: run.total }) }}\n </wx-text>\n </div>\n\n <div v-if=\"refused\" class=\"wx-catalog-bulk__refused\">\n <wx-text size=\"sm\" weight=\"medium\">\n {{ refused.label }} · {{ t('panel.bulk-done', { count: refused.done }) }} ·\n {{ t('panel.bulk-refused', { count: refused.failed }) }}\n </wx-text>\n <details class=\"wx-catalog-bulk__errors\">\n <summary>{{ t('panel.bulk-errors') }}</summary>\n <ul>\n <li v-for=\"error in refused.errors\" :key=\"error.id\">\n <strong>{{ error.name }}</strong> — {{ error.message }}\n </li>\n </ul>\n </details>\n <wx-button size=\"sm\" variant=\"text\" @click=\"run = null\">{{\n t('panel.bulk-close')\n }}</wx-button>\n </div>\n </div>\n</template>\n\n<style scoped>\n/* No box of its own: the button, the progress and the refusals stand in the selection strip\n around it, which already wraps — a box here would push the button onto a line of its own. */\n.wx-catalog-bulk {\n display: contents;\n}\n\n.wx-catalog-bulk__progress {\n display: grid;\n gap: var(--wx-space-4);\n flex: 1 1 240px;\n min-width: 0;\n}\n\n.wx-catalog-bulk__refused {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--wx-space-8);\n flex-basis: 100%;\n min-width: 0;\n}\n\n.wx-catalog-bulk__errors {\n flex-basis: 100%;\n font-size: var(--wx-font-size-sm);\n}\n\n.wx-catalog-bulk__errors summary {\n cursor: pointer;\n color: var(--wx-text-muted);\n}\n\n.wx-catalog-bulk__errors ul {\n margin: var(--wx-space-8) 0 0;\n padding-inline-start: var(--wx-space-18);\n max-height: 200px;\n overflow: auto;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { nextTick, onMounted, ref, useTemplateRef } from 'vue'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport {\n useLocales,\n useModal,\n WxButton,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSpace,\n} from '@webx-ui/core'\nimport { createCatalogApi } from './api'\nimport { useCatalogMessages } from './i18n'\nimport { firstError } from './errors'\nimport type { ProductDetail } from './types'\n\n/**\n * A new product: what it is called, and nothing else. It is created unpublished and without a\n * category — the form is where there is room for those, and a product cannot be published before\n * it has a main category anyway (decision 3). The address is made of the name.\n */\nconst { open, resolve, dismiss } = useModal<ProductDetail>()\n\nconst context = useAdmin()\nconst api = createCatalogApi(context)\nconst locales = useLocales()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\n\nconst name = ref('')\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\nconst field = useTemplateRef<HTMLElement>('field')\n\nonMounted(async () => {\n await nextTick()\n field.value?.querySelector('input')?.focus()\n})\n\nasync function submit(): Promise<void> {\n if (name.value.trim() === '' || saving.value) return\n\n saving.value = true\n errors.value = {}\n\n try {\n resolve(\n await api.createProduct({\n name: { [locales.active.value]: name.value.trim() },\n is_published: false,\n }),\n )\n } catch (error) {\n errors.value = (error as { body?: { errors?: Record<string, string[]> } }).body?.errors ?? {}\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog v-model:open=\"open\" :title=\"t('panel.new-product')\" :width=\"440\">\n <wx-form-item\n :label=\"t('product.name')\"\n :error=\"firstError(errors, 'name') ?? firstError(errors, 'slug')\"\n required\n >\n <div ref=\"field\">\n <wx-input v-model=\"name\" :aria-label=\"t('product.name')\" @keyup.enter=\"submit\" />\n </div>\n </wx-form-item>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('panel.cancel') }}</wx-button>\n <wx-button type=\"primary\" :loading=\"saving\" :disabled=\"name.trim() === ''\" @click=\"submit\">\n {{ t('panel.create') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n","import type { LocationQuery } from 'vue-router'\nimport type { FacetChoice, FacetInfo } from './types'\n\n/**\n * The list's facet filters live in the address, one parameter per facet — `f.<key>` — so that\n * coming back from a product lands on the same filter, and a filtered list can be linked to\n * (the tree's \"Show its products\" does exactly that):\n *\n * f.category=12,14 values of a terms or tree facet\n * f.price=100-500 a range; either end may be empty\n * f.in-stock=1 a toggle\n *\n * The server's own format is another (`facets[key][]=…`, see `productSearch()`); this one is for\n * a person reading the address bar.\n */\nexport const FACET_PREFIX = 'f.'\n\nexport function readFacets(query: LocationQuery, facets: FacetInfo[]): Record<string, FacetChoice> {\n const chosen: Record<string, FacetChoice> = {}\n\n for (const facet of facets) {\n const raw = query[`${FACET_PREFIX}${facet.key}`]\n const text = typeof raw === 'string' ? raw.trim() : ''\n\n if (text === '') continue\n\n if (facet.kind === 'toggle') {\n if (text === '1') chosen[facet.key] = true\n } else if (facet.kind === 'range') {\n const [min, max] = text.split('-', 2).map((end) => (end === '' ? null : Number(end)))\n const range = {\n min: Number.isFinite(min) ? min : null,\n max: Number.isFinite(max) ? max : null,\n }\n\n if (range.min !== null || range.max !== null) chosen[facet.key] = range\n } else {\n const values = text.split(',').filter((value) => value !== '')\n\n if (values.length > 0) chosen[facet.key] = values\n }\n }\n\n return chosen\n}\n\n/** One facet's choice as its parameter; `undefined` takes the parameter away. */\nexport function writeFacet(choice: FacetChoice | null | undefined): string | undefined {\n if (choice === null || choice === undefined) return undefined\n if (choice === true) return '1'\n\n if (Array.isArray(choice)) return choice.length > 0 ? choice.join(',') : undefined\n\n const min = choice.min ?? null\n const max = choice.max ?? null\n\n return min === null && max === null ? undefined : `${min ?? ''}-${max ?? ''}`\n}\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'\nimport {\n rowMenuWidth,\n useAdmin,\n useErrorText,\n useTranslate,\n WxDate,\n WxFilterChips,\n WxListScreen,\n WxRowMenu,\n type AppliedFilter,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport {\n confirm,\n createModal,\n toast,\n useElementWidth,\n WxBadge,\n WxButton,\n WxEntityCard,\n WxFormItem,\n WxIcon,\n WxInputNumber,\n WxSelect,\n WxSwitch,\n WxTable,\n WxText,\n WxTooltip,\n WxTreeSelect,\n type RowKey,\n type SelectOption,\n type TabItem,\n type TableColumn,\n type TableState,\n type TabValue,\n type TreeSelectValue,\n} from '@webx-ui/core'\nimport BulkBar from './BulkBar.vue'\nimport ProductCreateDialog from './ProductCreateDialog.vue'\nimport { createCatalogApi } from './api'\nimport { FACET_PREFIX, readFacets, writeFacet } from './filters'\nimport { useCatalogMessages } from './i18n'\nimport { flatten, useCategoryTree, useFacetRegistry } from './store'\nimport type {\n BulkSelection,\n FacetChoice,\n FacetInfo,\n ProductDetail,\n ProductQuery,\n ProductRow,\n ProductSort,\n SortInfo,\n ProductsPage,\n} from './types'\n\n/**\n * The products of the catalogue (§11.1): a page of rows, the views of decision 3 over it, the\n * facets as filters behind the funnel, and a checkbox per row.\n *\n * The checkboxes are for the bulk actions (§11.4): a selection outlives the page it was made on,\n * which is what \"select these twelve across three pages\" needs, and \"everything found\" picks the\n * filter itself rather than its ids. The actions and their progress are `BulkBar`'s.\n *\n * What the list shows beyond the core's columns is the satellites' (`ProductColumns`, §7.4): the\n * server says which, and each row carries its values under their keys.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/catalog' })\n\n/** Where the row stops being a row. Below it the table draws cards and this screen draws one. */\nconst CARDS = 640\n\nconst context = useAdmin()\nconst api = createCatalogApi(context)\nconst tree = useCategoryTree(context)\nconst registry = useFacetRegistry(context)\nconst route = useRoute()\nconst router = useRouter()\nuseCatalogMessages()\n\nconst t = useTranslate('webx-catalog')\n/* The words a list needs as soon as it has filters belong to the panel, not to the catalogue. */\nconst admin = useTranslate('webx-admin')\nconst message = useErrorText()\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst width = useElementWidth(root)\n\nconst page = ref<ProductsPage | null>(null)\nconst loading = ref(true)\nconst selected = ref<RowKey[]>([])\n/** The whole of what the filter finds is picked, not only the ticked rows. */\nconst everything = ref(false)\n/* The table's own search and page, started from the address: coming back lands where it left. */\nconst search = ref(typeof route.query.q === 'string' ? route.query.q : '')\nconst pageNumber = ref(Number(route.query.page ?? 1) || 1)\n/* The page size the table last asked for: a reload after a filter has to page the same way. */\nlet perPage: number | undefined\n\nconst create = createModal<ProductDetail, Record<string, never>>(ProductCreateDialog)\n\nconst canManage = computed(() => context.can('catalog.manage'))\nconst canDelete = computed(() => context.can('catalog.delete'))\n\nconst title = computed(() => t('module.products'))\n\n/** Everything the list is looking at lives in the address — coming back lands in the same place. */\nconst view = computed<TabValue>({\n get: () => (typeof route.query.view === 'string' ? route.query.view : ''),\n set: (value) => {\n void router.replace({\n query: { ...route.query, view: value === '' ? undefined : String(value), page: undefined },\n })\n },\n})\n\n/**\n * The orders are the registry's (§7.2): a satellite adds its own, and a site without prices has\n * none by price — a sort the server does not know is a 422, so nothing is offered or asked for\n * that it did not list. Until it answers, the default order is the one there is.\n */\nconst sorts = computed<SortInfo[]>(() =>\n registry.sorts.value.length > 0\n ? registry.sorts.value\n : [{ key: 'default', label: t('panel.sort-default') }],\n)\n\nconst sort = computed<ProductSort>(() => {\n const asked = route.query.sort\n\n return typeof asked === 'string' && registry.sorts.value.some((one) => one.key === asked)\n ? asked\n : 'default'\n})\n\nconst facets = computed<FacetInfo[]>(() => registry.facets.value ?? [])\nconst chosen = computed(() => readFacets(route.query, facets.value))\n\n/** The counter of decision 3 rides on its own tab, where somebody looking for those products looks. */\nconst views = computed<TabItem[]>(() => {\n const missing = page.value?.counts.no_category ?? 0\n\n return [\n { value: '', label: t('panel.view-all') },\n { value: 'published', label: t('panel.view-published') },\n { value: 'unpublished', label: t('panel.view-unpublished') },\n {\n value: 'no-category',\n label: t('panel.view-no-category'),\n badge: missing > 0 ? missing : undefined,\n },\n ]\n})\n\n/** Absent from every row when the site switched prices off — then the column is not drawn. */\nconst priced = computed(() => (page.value?.data ?? []).some((row) => 'price' in row))\nconst extra = computed(() => page.value?.columns ?? [])\n\nconst asCards = computed(() => width.value > 0 && width.value < CARDS)\n\nconst categoryNames = computed(\n () => new Map(flatten(tree.nodes.value ?? []).map((node) => [String(node.id), node.name])),\n)\n\n/**\n * Every column but the name carries a width and the table is laid out `fixed`, so the ones that\n * drop below a breakpoint give their room to the name. They go in the order they can be spared:\n * when it changed, then the satellites', then the category — what is left is the picture, the\n * name and the state, which is what identifies a product and what somebody is looking for.\n */\nconst columns = computed<TableColumn<ProductRow>[]>(() => {\n if (asCards.value) {\n // The card is the row: a tap opens the product, and a line of its own for the `···` would make\n // every card half as tall again for a menu whose first item is that same tap.\n return [{ key: 'card', label: '' }]\n }\n\n return [\n { key: 'image', label: '', width: 64 },\n { key: 'name', label: t('panel.column-product'), minWidth: 200 },\n { key: 'category', label: t('product.category'), width: 180, hideBelow: 860 },\n ...(priced.value\n ? [{ key: 'price', label: t('product.price'), width: 150, align: 'right' as const }]\n : []),\n ...extra.value.map((column) => ({\n key: `x.${column.key}`,\n label: column.label,\n width: 120,\n hideBelow: 1040,\n })),\n { key: 'state', label: t('panel.column-state'), width: 150, hideBelow: 720 },\n { key: 'updated_at', label: t('panel.column-updated'), width: 130, hideBelow: 1180 },\n { key: 'actions', label: '', width: rowMenuWidth, align: 'right' },\n ]\n})\n\nfunction query(state?: TableState): ProductQuery {\n return {\n q: state?.search ?? search.value,\n state: view.value as ProductQuery['state'],\n sort: sort.value,\n page: state?.page ?? pageNumber.value,\n per_page: state?.perPage ?? perPage,\n facets: chosen.value,\n }\n}\n\nlet asked = 0\n\nasync function load(state?: TableState): Promise<void> {\n const mine = ++asked\n\n loading.value = true\n\n try {\n const answer = await api.products(query(state))\n\n // A slower answer to an older question must not land over a newer one.\n if (mine === asked) page.value = answer\n } catch (error) {\n toast.danger(message(error))\n } finally {\n if (mine === asked) loading.value = false\n }\n}\n\nfunction onState(state: TableState): void {\n perPage = state.perPage\n\n const wanted: LocationQueryRaw = {\n ...route.query,\n q: state.search === '' ? undefined : state.search,\n page: state.page === 1 ? undefined : String(state.page),\n }\n\n void router.replace({ query: wanted })\n void load(state)\n}\n\nfunction narrow(key: string, choice: FacetChoice | null): void {\n void router.replace({\n query: { ...route.query, [`${FACET_PREFIX}${key}`]: writeFacet(choice), page: undefined },\n })\n}\n\nfunction order(value: unknown): void {\n void router.replace({\n query: {\n ...route.query,\n sort: typeof value === 'string' && value !== 'default' ? value : undefined,\n page: undefined,\n },\n })\n}\n\nfunction clearFilters(): void {\n const rest = Object.fromEntries(\n Object.entries(route.query).filter(([name]) => !name.startsWith(FACET_PREFIX)),\n )\n\n void router.replace({ query: { ...rest, page: undefined } })\n}\n\n/**\n * What a terms facet can be narrowed to: the values the list counted for it, with how many\n * products each would leave. The engine counts a facet without its own choice, so picking one\n * value does not take the others away; a chosen value that counts nothing any more stays offered,\n * or it could not be taken off.\n */\nfunction optionsOf(key: string): SelectOption[] {\n const counted = page.value?.facets?.[key]?.values ?? []\n const options: SelectOption[] = counted.map((one) => ({\n value: one.value,\n label: `${one.label} (${one.count})`,\n }))\n\n for (const value of valuesOf(key)) {\n if (!counted.some((one) => one.value === value)) options.push({ value, label: value })\n }\n\n return options\n}\n\n/** Values of a terms facet, or of the tree, for a chip: \"Category: Laptops, Tablets\". */\nfunction valueLabel(facet: FacetInfo, value: string | number): string {\n if (facet.kind === 'tree') return categoryNames.value.get(String(value)) ?? `#${value}`\n\n return (\n page.value?.facets?.[facet.key]?.values?.find((one) => one.value === String(value))?.label ??\n String(value)\n )\n}\n\n/** The bounds a range facet has in the list as it stands, said in its fields before anything is typed. */\nfunction boundOf(key: string, end: 'min' | 'max'): string {\n const bound = page.value?.facets?.[key]?.[end]\n\n return typeof bound === 'number' ? money.value.format(bound) : ''\n}\n\nconst applied = computed<AppliedFilter[]>(() =>\n facets.value.flatMap((facet) => {\n const choice = chosen.value[facet.key]\n\n if (choice === undefined) return []\n\n let said: string\n\n if (choice === true) said = facet.label\n else if (Array.isArray(choice)) {\n said = `${facet.label}: ${choice.map((value) => valueLabel(facet, value)).join(', ')}`\n } else {\n said = `${facet.label}: ${choice.min ?? '…'} – ${choice.max ?? '…'}`\n }\n\n return [{ key: facet.key, label: said, clear: () => narrow(facet.key, null) }]\n }),\n)\n\nconst emptyText = computed(() => {\n if (search.value !== '') return t('panel.empty-search')\n if (applied.value.length > 0 || view.value !== '') return t('panel.empty-search')\n\n return t('panel.empty-products')\n})\n\nfunction rangeOf(key: string): { min?: number | null; max?: number | null } {\n const choice = chosen.value[key]\n\n return choice && !Array.isArray(choice) && choice !== true ? choice : {}\n}\n\nfunction valuesOf(key: string): string[] {\n const choice = chosen.value[key]\n\n return Array.isArray(choice) ? choice.map(String) : []\n}\n\nfunction treeChoice(key: string): TreeSelectValue {\n return valuesOf(key).map(Number)\n}\n\n/** How many the list finds as it is filtered — what \"select everything found\" would pick. */\nconst found = computed(() => page.value?.total ?? 0)\n\n/**\n * \"Everything found\" is the list's query, not its ids (§11.4): the server turns it into ids when\n * the run starts, so forty thousand products never travel through the browser.\n */\nconst bulkSelection = computed<BulkSelection>(() => {\n if (!everything.value) return { ids: selected.value.map(Number) }\n\n const facetsQuery: Record<\n string,\n Array<string | number> | { min?: number | null; max?: number | null }\n > = {}\n\n for (const [key, choice] of Object.entries(chosen.value)) {\n // A toggle is sent the way the list sends it: a list with `1` in it.\n facetsQuery[key] = choice === true ? ['1'] : choice\n }\n\n return { query: { q: search.value, state: String(view.value), facets: facetsQuery } }\n})\n\nfunction clearSelection(): void {\n selected.value = []\n everything.value = false\n}\n\n/**\n * What refused stays picked, and nothing else: the strip keeps its list of refusals beside the\n * very products it names, ready for another go once they are put right.\n */\nfunction onBulkFinished(refused: number[]): void {\n everything.value = false\n selected.value = refused\n void load()\n}\n\n/* One source per value, not one getter returning an array: a page turn must not fire a second\n request racing the one `onState` already sent. */\nwatch([view, sort, () => JSON.stringify(chosen.value), search], () => {\n // \"Everything found\" was everything this filter found; another filter finds something else.\n everything.value = false\n})\n\nwatch([view, sort, () => JSON.stringify(chosen.value)], () => {\n // A new filter is a new list: the page it was on belongs to the list it was on. If that moves\n // the table's page, the table asks for itself; otherwise nobody would.\n if (pageNumber.value !== 1) pageNumber.value = 1\n else void load()\n})\n\nonMounted(() => {\n void registry.load().catch(() => undefined)\n void tree.load().catch(() => undefined)\n})\n\nfunction open(product: ProductRow): void {\n void router.push({ path: `${props.base}/products/${product.id}` })\n}\n\nasync function add(): Promise<void> {\n const detail = await create({})\n\n if (!detail) return\n\n open(detail.product)\n}\n\nasync function publish(product: ProductRow, on: boolean): Promise<void> {\n try {\n await api.saveProduct(product.id, { is_published: on })\n toast.success(on ? t('panel.product-published') : t('panel.product-unpublished'))\n await load()\n } catch (error) {\n // Publishing without a main category is refused (decision 3), and the server says so.\n toast.danger(message(error))\n }\n}\n\nasync function remove(product: ProductRow): Promise<void> {\n const agreed = await confirm({\n title: t('panel.delete-product-title', { name: product.name }),\n message: t('panel.delete-product-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.removeProduct(product.id)\n selected.value = selected.value.filter((key) => key !== product.id)\n toast.success(t('panel.product-deleted'))\n await load()\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction actionsFor(product: ProductRow): RowAction[] {\n const actions: RowAction[] = [\n { key: 'open', icon: 'edit', label: t('panel.open'), run: () => open(product) },\n ]\n\n if (product.url) {\n actions.push({ key: 'site', icon: 'link', label: t('panel.open-on-site'), href: product.url })\n }\n\n if (canManage.value) {\n actions.push(\n product.is_published\n ? {\n key: 'unpublish',\n icon: 'eye-off',\n label: t('panel.unpublish'),\n run: () => void publish(product, false),\n }\n : {\n key: 'publish',\n icon: 'eye',\n label: t('panel.publish'),\n run: () => void publish(product, 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(product),\n })\n }\n\n return actions\n}\n\nfunction stateType(product: ProductRow): 'success' | 'warning' | 'default' {\n if (!product.is_published) return 'default'\n\n return product.visible ? 'success' : 'warning'\n}\n\nconst money = computed(\n () =>\n new Intl.NumberFormat(context.i18n.state.locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }),\n)\n\nfunction price(value: number | null | undefined): string {\n return value === null || value === undefined ? '—' : money.value.format(value)\n}\n\nfunction unit(product: ProductRow): string {\n return product.unit ? ` / ${t(`units.${product.unit}`)}` : ''\n}\n\nfunction cell(product: ProductRow, key: string): string {\n const value = product.columns?.[key]\n\n if (value === null || value === undefined || value === '') return '—'\n if (typeof value === 'boolean') return value ? '✓' : '—'\n\n return String(value)\n}\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-product'),\n icon: 'plus',\n primary: true,\n run: () => void add(),\n })\n }\n\n leads.push({\n key: 'categories',\n label: t('module.categories'),\n icon: 'folder',\n run: () => void router.push(`${props.base}/categories`),\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(`${props.base}/deleted`),\n })\n }\n\n return leads\n})\n</script>\n\n<template>\n <div ref=\"root\" class=\"wx-catalog-products\">\n <wx-list-screen v-model:view=\"view\" :title=\"title\" :views=\"views\" :actions=\"actions\">\n <!-- What is picked, said above the rows it was picked from, with what can be done to it. -->\n <div v-if=\"selected.length > 0 || everything\" class=\"wx-catalog-products__selection\">\n <wx-text size=\"sm\" weight=\"medium\">\n {{\n everything\n ? t('panel.selected-all', { count: found })\n : t('panel.selected', { count: selected.length })\n }}\n </wx-text>\n <wx-button\n v-if=\"!everything && found > selected.length\"\n size=\"sm\"\n variant=\"text\"\n @click=\"everything = true\"\n >\n {{ t('panel.select-all-found', { count: found }) }}\n </wx-button>\n <wx-button size=\"sm\" variant=\"text\" @click=\"clearSelection\">\n {{ t('panel.select-clear') }}\n </wx-button>\n <bulk-bar\n v-if=\"canManage || canDelete\"\n :count=\"everything ? found : selected.length\"\n :selection=\"bulkSelection\"\n @finished=\"onBulkFinished\"\n />\n </div>\n\n <wx-table\n v-model:selected=\"selected\"\n v-model:search=\"search\"\n v-model:page=\"pageNumber\"\n :data=\"page\"\n :columns=\"columns\"\n row-key=\"id\"\n searchable\n selectable\n clickable\n hover\n flush\n :loading=\"loading\"\n layout=\"fixed\"\n :cards-below=\"CARDS\"\n :filters-count=\"applied.length\"\n :filters-label=\"admin('filters.title')\"\n :search-placeholder=\"t('panel.search-products')\"\n :empty-text=\"emptyText\"\n :aria-label=\"title\"\n @row-click=\"open\"\n @state-change=\"onState\"\n >\n <template #filters>\n <wx-form-item :label=\"t('panel.sort')\">\n <wx-select\n :model-value=\"sort\"\n :options=\"sorts.map((one) => ({ value: one.key, label: one.label }))\"\n size=\"sm\"\n @update:model-value=\"order\"\n />\n </wx-form-item>\n\n <wx-form-item v-for=\"facet in facets\" :key=\"facet.key\" :label=\"facet.label\">\n <wx-tree-select\n v-if=\"facet.kind === 'tree'\"\n :model-value=\"treeChoice(facet.key)\"\n :nodes=\"tree.nodes.value ?? []\"\n node-key=\"id\"\n label-key=\"name\"\n children-key=\"children\"\n multiple\n check-strictly\n filterable\n clearable\n size=\"sm\"\n :placeholder=\"t('panel.any')\"\n @update:model-value=\"\n (value: TreeSelectValue) =>\n narrow(facet.key, Array.isArray(value) ? value.map(String) : [])\n \"\n />\n\n <div v-else-if=\"facet.kind === 'range'\" class=\"wx-catalog-products__range\">\n <wx-input-number\n :model-value=\"rangeOf(facet.key).min ?? null\"\n :min=\"0\"\n :controls=\"false\"\n size=\"sm\"\n :placeholder=\"boundOf(facet.key, 'min') || t('panel.range-from')\"\n :aria-label=\"`${facet.label}: ${t('panel.range-from')}`\"\n @update:model-value=\"\n (value: number | null | undefined) =>\n narrow(facet.key, { ...rangeOf(facet.key), min: value ?? null })\n \"\n />\n <wx-input-number\n :model-value=\"rangeOf(facet.key).max ?? null\"\n :min=\"0\"\n :controls=\"false\"\n size=\"sm\"\n :placeholder=\"boundOf(facet.key, 'max') || t('panel.range-to')\"\n :aria-label=\"`${facet.label}: ${t('panel.range-to')}`\"\n @update:model-value=\"\n (value: number | null | undefined) =>\n narrow(facet.key, { ...rangeOf(facet.key), max: value ?? null })\n \"\n />\n </div>\n\n <wx-switch\n v-else-if=\"facet.kind === 'toggle'\"\n :model-value=\"chosen[facet.key] === true\"\n size=\"sm\"\n @update:model-value=\"(on) => narrow(facet.key, on ? true : null)\"\n />\n\n <wx-select\n v-else\n :model-value=\"valuesOf(facet.key)\"\n :options=\"optionsOf(facet.key)\"\n multiple\n filterable\n clearable\n size=\"sm\"\n :placeholder=\"t('panel.any')\"\n @update:model-value=\"\n (value: unknown) => narrow(facet.key, Array.isArray(value) ? value.map(String) : [])\n \"\n />\n </wx-form-item>\n\n <wx-button v-if=\"applied.length > 0\" variant=\"text\" size=\"sm\" block @click=\"clearFilters\">\n <template #icon><wx-icon name=\"close\" /></template>\n {{ admin('filters.reset') }}\n </wx-button>\n </template>\n\n <template #applied>\n <wx-filter-chips :filters=\"applied\" />\n </template>\n\n <template #cell-image=\"{ row }\">\n <span class=\"wx-catalog-products__image\" :class=\"{ 'is-empty': !row.image }\">\n <img v-if=\"row.image\" :src=\"row.image.thumb ?? row.image.url\" alt=\"\" loading=\"lazy\" />\n <wx-icon v-else name=\"image\" size=\"sm\" />\n </span>\n </template>\n\n <template #cell-name=\"{ row }\">\n <div class=\"wx-catalog-products__name\">\n <span class=\"wx-catalog-products__title\">{{ row.name }}</span>\n <span class=\"wx-catalog-products__sku\">{{ row.sku ?? '' }}</span>\n </div>\n </template>\n\n <template #cell-category=\"{ row }\">\n <wx-badge v-if=\"!row.category\" type=\"warning\" size=\"sm\" round>\n {{ t('product.no-category') }}\n </wx-badge>\n <wx-text v-else size=\"sm\" truncate :tone=\"row.category.deleted ? 'muted' : undefined\">\n {{ row.category.name }}\n </wx-text>\n </template>\n\n <template #cell-price=\"{ row }\">\n <span class=\"wx-catalog-products__price\">\n <span\n >{{ price(row.price) }}<small v-if=\"row.price != null\">{{ unit(row) }}</small></span\n >\n <s v-if=\"row.old_price != null\">{{ price(row.old_price) }}</s>\n </span>\n </template>\n\n <template v-for=\"column in extra\" :key=\"column.key\" #[`cell-x.${column.key}`]=\"{ row }\">\n <wx-text size=\"sm\" truncate>{{ cell(row, column.key) }}</wx-text>\n </template>\n\n <template #cell-state=\"{ row }\">\n <wx-tooltip v-if=\"row.is_published && !row.visible\" :content=\"t('panel.invisible')\">\n <wx-badge :type=\"stateType(row)\" dot size=\"sm\">{{ t(`states.${row.state}`) }}</wx-badge>\n </wx-tooltip>\n <wx-badge v-else :type=\"stateType(row)\" dot size=\"sm\">\n {{ t(`states.${row.state}`) }}\n </wx-badge>\n </template>\n\n <template #cell-updated_at=\"{ row }\">\n <wx-date :value=\"row.updated_at\" compact />\n </template>\n\n <template #cell-card=\"{ row }\">\n <wx-entity-card\n variant=\"plain\"\n :title=\"row.name\"\n :image=\"row.image?.thumb ?? row.image?.url ?? undefined\"\n image-size=\"56px\"\n :title-lines=\"2\"\n :subtitle=\"row.sku ?? undefined\"\n >\n <template #meta>\n <wx-badge :type=\"stateType(row)\" dot size=\"sm\">{{\n t(`states.${row.state}`)\n }}</wx-badge>\n <wx-badge v-if=\"!row.category\" type=\"warning\" size=\"sm\" round>\n {{ t('product.no-category') }}\n </wx-badge>\n <wx-text v-if=\"priced && row.price != null\" size=\"sm\">\n {{ price(row.price) }}{{ unit(row) }}\n </wx-text>\n </template>\n </wx-entity-card>\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-products {\n min-width: 0;\n}\n\n.wx-catalog-products__selection {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--wx-space-12);\n padding: var(--wx-space-8) var(--wx-space-16);\n border-bottom: 1px solid var(--wx-border-default);\n background: var(--wx-bg-subtle);\n}\n\n.wx-catalog-products__image {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: var(--wx-radius-sm);\n overflow: clip;\n background: var(--wx-bg-subtle);\n color: var(--wx-text-muted);\n vertical-align: middle;\n}\n\n.wx-catalog-products__image img {\n width: 100%;\n height: 100%;\n min-width: 0;\n object-fit: cover;\n}\n\n.wx-catalog-products__name {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.wx-catalog-products__title {\n font-weight: var(--wx-font-weight-medium);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wx-catalog-products__sku {\n font-family: var(--wx-font-family-mono);\n font-size: var(--wx-font-size-sm);\n color: var(--wx-text-muted);\n min-height: 1em;\n}\n\n.wx-catalog-products__price {\n display: inline-flex;\n flex-direction: column;\n align-items: flex-end;\n font-variant-numeric: tabular-nums;\n}\n\n/* A price and its unit are one reading: '99 990 / pcs' broken over two lines reads as two facts. */\n.wx-catalog-products__price > * {\n white-space: nowrap;\n}\n\n.wx-catalog-products__price small,\n.wx-catalog-products__price s {\n font-size: var(--wx-font-size-sm);\n color: var(--wx-text-muted);\n}\n\n.wx-catalog-products__range {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--wx-space-8);\n}\n</style>\n","import type { AdminModule } from '@webx-ui/module-admin'\nimport CategoriesPage from './CategoriesPage.vue'\nimport CategoryEditorPage from './CategoryEditorPage.vue'\nimport CategoryField from './CategoryField.vue'\nimport DeletedPage from './DeletedPage.vue'\nimport FacetsField from './FacetsField.vue'\nimport GalleryField from './GalleryField.vue'\nimport ProductEditorPage from './ProductEditorPage.vue'\nimport ProductsPage from './ProductsPage.vue'\n\nexport interface CatalogOptions {\n /**\n * Where the catalogue lives inside the panel. The server's refusal of a taken article number\n * links to `{path}/products/{id}` under the panel's own path, so a panel that moves it has to\n * move the server's idea of it too — leave it unless there is a reason.\n */\n path?: string\n}\n\n/**\n * The catalogue as a section of the panel (§11): products, their categories as a tree, and\n * «Deleted».\n *\n * One section and not three, because the server registers one module — `catalog` — and the\n * navigation draws one entry per module. The products are where it opens; the tree and «Deleted»\n * are reached from their head. The satellites (brands, stock, labels) stand beside it in the\n * `catalog` group as sections of their own.\n *\n * The three node types are what only this module can draw on its two screens: a category picker\n * that knows the tree, the «Filters» tab of a category (§6.2), and the gallery.\n */\nexport function catalog(options: CatalogOptions = {}): AdminModule {\n const path = options.path ?? '/catalog'\n const props = { base: path }\n\n return {\n id: 'catalog',\n path,\n routes: [\n { path, redirect: `${path}/products` },\n { path: `${path}/products`, name: 'webx.catalog.products', component: ProductsPage, props },\n {\n path: `${path}/products/:id(\\\\d+)`,\n name: 'webx.catalog.products.edit',\n component: ProductEditorPage,\n props,\n },\n {\n path: `${path}/categories`,\n name: 'webx.catalog.categories',\n component: CategoriesPage,\n props,\n },\n {\n path: `${path}/categories/:id(\\\\d+)`,\n name: 'webx.catalog.categories.edit',\n component: CategoryEditorPage,\n props,\n },\n { path: `${path}/deleted`, name: 'webx.catalog.deleted', component: DeletedPage, props },\n ],\n types: {\n 'wx-catalog-category': { component: CategoryField, kind: 'field' },\n // Wide: a row of the list carries a name, a switch and a grip, and half a line is too narrow\n // to read which filter is which.\n 'wx-catalog-facets': { component: FacetsField, kind: 'field', wide: true },\n 'wx-catalog-gallery': { component: GalleryField, kind: 'display' },\n },\n }\n}\n"],"names":["CATALOG_API","productSearch","query","search","key","choice","value","upload","admin","url","file","onProgress","body","resolve","reject","request","token","readCookie","event","answer","createCatalogApi","base","data","withQuery","path","id","values","source","images","image","alt","title","parent","before","action","params","selection","kind","firstError","errors","field","own","name","catalogMessages","seeded","useCatalogMessages","i18n","useAdmin","stores","storeOf","store","ref","fetchInto","shelf","fetch","force","pending","useCategoryTree","api","nodes","useFacetRegistry","computed","facet","flatten","node","ancestry","byId","chain","current","props","__props","open","dismiss","useModal","context","tree","locales","useLocales","t","useTranslate","saving","useTemplateRef","onMounted","nextTick","submit","under","error","_createBlock","_unref","WxDialog","$event","_createVNode","WxSpace","WxButton","WxFormItem","_createElementVNode","WxInput","WxTreeSelect","lastSegment","segments","segment","router","useRouter","message","useErrorText","rows","loading","loaded","create","createModal","CategoryCreateDialog","canManage","canDelete","asTree","matches","term","columns","rowMenuWidth","treeOptions","drag","drop","show","plain","load","toast","onState","state","add","detail","dropped","publish","on","remove","confirm","productsOf","actionsFor","actions","leads","_openBlock","_createElementBlock","_hoisted_1","WxListScreen","WxTable","_withCtx","row","_normalizeClass","_toDisplayString","WxText","_component_router_link","_createTextVNode","_cache","WxBadge","WxRowMenu","productEditorKey","provideProductEditor","editor","provide","useProductEditor","inject","categoryEditorKey","provideCatalogCategoryEditor","useCatalogCategoryEditor","route","useRoute","list","category","facetsFrom","snapshot","locked","dirty","written","localizedValue","address","parents","provideHistorySubject","provideRecordAddress","take","save","leaveGuard","onKeydown","useBodyKeys","watch","onBeforeUnmount","onBeforeRouteLeave","_Fragment","WxSkeleton","WxCard","WxScreenHead","WxBreadcrumb","WxBreadcrumbItem","_renderList","WxScreen","WxActionBar","WxSaveState","_useModel","useRecordAddress","main","chosen","mark","model","next","ids","_mergeProps","_ctx","page","canRestore","views","asked","mine","restore","bare","refOf","found","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","WxDate","registry","failed","facets","labels","complete","named","inherited","inheritedNames","toggleOwn","visible","findSource","from","setting","now","WxAlert","WxSwitch","WxSortableList","item","PAUSE","uploads","fetching","productId","timer","sent","captions","saveGallery","failure","carrying","caption","text","one","moved","files","patch","progress","fetchAddress","index","WxAction","WxUpload","product","holder","section","module","subtitle","holderLink","sku","reactive","ready","param","optionsOf","onCategory","apply","WxSelect","POLL","emit","__emit","BulkParamsDialog","run","starting","running","refused","asks","start","given","follow","poll","finish","WxDropdown","WxIcon","WxDropdownItem","WxProgress","FACET_PREFIX","readFacets","raw","min","max","end","range","writeFacet","CARDS","root","width","useElementWidth","selected","everything","pageNumber","perPage","ProductCreateDialog","view","sorts","sort","missing","priced","extra","asCards","categoryNames","column","wanted","narrow","order","clearFilters","rest","counted","options","valuesOf","valueLabel","boundOf","bound","money","applied","said","emptyText","rangeOf","treeChoice","bulkSelection","facetsQuery","clearSelection","onBulkFinished","stateType","price","unit","cell","BulkBar","WxInputNumber","WxFilterChips","_hoisted_7","_hoisted_8","_hoisted_9","WxTooltip","WxEntityCard","catalog","ProductsPage","ProductEditorPage","CategoriesPage","CategoryEditorPage","DeletedPage","CategoryField","FacetsField","GalleryField"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Messages } from '@webx-ui/module-admin';
|
|
2
|
+
/**
|
|
3
|
+
* The English this package speaks on its own, before the server's dictionary arrives, or without
|
|
4
|
+
* one. The server ships the same lines under `webx-catalog::` and overrides these;
|
|
5
|
+
* `messages.test.ts` keeps the two sets of keys equal.
|
|
6
|
+
*
|
|
7
|
+
* `module`, `states`, `product`, `category` and `units` are the server's groups, which the panel
|
|
8
|
+
* reads too — a column called "Article number" in the list and "Article number" on the form
|
|
9
|
+
* are one word. `panel` is what only the panel says.
|
|
10
|
+
*/
|
|
11
|
+
export declare const catalogMessages: Record<string, Messages>;
|