@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
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AdminModule } from '@webx-ui/module-admin';
|
|
2
|
+
export interface CatalogOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Where the catalogue lives inside the panel. The server's refusal of a taken article number
|
|
5
|
+
* links to `{path}/products/{id}` under the panel's own path, so a panel that moves it has to
|
|
6
|
+
* move the server's idea of it too — leave it unless there is a reason.
|
|
7
|
+
*/
|
|
8
|
+
path?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The catalogue as a section of the panel (§11): products, their categories as a tree, and
|
|
12
|
+
* «Deleted».
|
|
13
|
+
*
|
|
14
|
+
* One section and not three, because the server registers one module — `catalog` — and the
|
|
15
|
+
* navigation draws one entry per module. The products are where it opens; the tree and «Deleted»
|
|
16
|
+
* are reached from their head. The satellites (brands, stock, labels) stand beside it in the
|
|
17
|
+
* `catalog` group as sections of their own.
|
|
18
|
+
*
|
|
19
|
+
* The three node types are what only this module can draw on its two screens: a category picker
|
|
20
|
+
* that knows the tree, the «Filters» tab of a category (§6.2), and the gallery.
|
|
21
|
+
*/
|
|
22
|
+
export declare function catalog(options?: CatalogOptions): AdminModule;
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The last segment of an address on the site, without slashes: `/laptops/` → `laptops`,
|
|
3
|
+
* `https://shop.test/en/lamp-12` → `lamp-12`. The panel compares it with the slug being typed;
|
|
4
|
+
* the language prefix and the host in front of it are not part of what the slug field edits.
|
|
5
|
+
*/
|
|
6
|
+
export declare function lastSegment(url: string | null | undefined): string | null;
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ComputedRef, Ref } from 'vue';
|
|
2
|
+
import { AdminContext } from '@webx-ui/module-admin';
|
|
3
|
+
import { CategoryNode, FacetInfo, FacetRegistryAnswer, SortInfo } from './types';
|
|
4
|
+
export interface CategoryTree {
|
|
5
|
+
/** `null` until the first answer. */
|
|
6
|
+
nodes: Ref<CategoryNode[] | null>;
|
|
7
|
+
load(force?: boolean): Promise<CategoryNode[]>;
|
|
8
|
+
/** Put in what the server answered with — a move answers with the whole tree. */
|
|
9
|
+
take(nodes: CategoryNode[]): void;
|
|
10
|
+
/** Forget it; the next reader asks again. */
|
|
11
|
+
drop(): void;
|
|
12
|
+
}
|
|
13
|
+
export declare function useCategoryTree(admin: AdminContext): CategoryTree;
|
|
14
|
+
export interface FacetRegistry {
|
|
15
|
+
facets: ComputedRef<FacetInfo[] | null>;
|
|
16
|
+
/** The orders the list offers, in the registry's order; empty until the answer. */
|
|
17
|
+
sorts: ComputedRef<SortInfo[]>;
|
|
18
|
+
load(): Promise<FacetRegistryAnswer>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The facets every category can show (§7.1) and the sorts of the list (§7.2) — one answer, since
|
|
22
|
+
* the list needs both before it can draw its filter. The kind is lowercased on the way in: a panel
|
|
23
|
+
* comparing with 'range' should not care how the server cased its enum.
|
|
24
|
+
*/
|
|
25
|
+
export declare function useFacetRegistry(admin: AdminContext): FacetRegistry;
|
|
26
|
+
/** Every node of the tree, depth first, as the server ordered them. */
|
|
27
|
+
export declare function flatten(nodes: CategoryNode[]): CategoryNode[];
|
|
28
|
+
/** A node and the chain of its parents, the node first. Empty when it is not in the tree. */
|
|
29
|
+
export declare function ancestry(nodes: CategoryNode[], id: number): CategoryNode[];
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.wx-catalog-categories[data-v-b896daca]{min-width:0}.wx-catalog-categories__name[data-v-b896daca]{font-weight:var(--wx-font-weight-medium)}.wx-catalog-categories__name.is-hidden[data-v-b896daca]{color:var(--wx-text-muted)}.wx-catalog-categories__count[data-v-b896daca]{color:var(--wx-color-primary);font-variant-numeric:tabular-nums;text-decoration:none}.wx-catalog-categories__count[data-v-b896daca]:hover{text-decoration:underline}.wx-catalog-category-editor[data-v-45d5817b]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16));container-type:inline-size}.wx-catalog-category-editor__ghost[data-v-45d5817b]{max-width:420px}.wx-catalog-deleted[data-v-1fad643b]{min-width:0}.wx-catalog-deleted__name[data-v-1fad643b]{display:flex;flex-direction:column;min-width:0}.wx-catalog-deleted__title[data-v-1fad643b]{font-weight:var(--wx-font-weight-medium);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-deleted__code[data-v-1fad643b]{font-family:var(--wx-font-family-mono);font-size:var(--wx-font-size-sm);color:var(--wx-text-muted)}.wx-catalog-deleted__ref[data-v-1fad643b]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wx-space-4) var(--wx-space-8);min-width:0}.wx-catalog-facets[data-v-4ca00a4d]{display:flex;flex-direction:column;gap:var(--wx-space-12)}.wx-catalog-facets__own[data-v-4ca00a4d],.wx-catalog-facets__inherited[data-v-4ca00a4d]{display:flex;flex-direction:column;gap:var(--wx-space-4)}.wx-catalog-facets[data-v-4ca00a4d] .wx-sortable-list__content{display:flex;align-items:center;gap:var(--wx-space-8);min-width:0}.wx-catalog-facets__name[data-v-4ca00a4d]{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-facets__name.is-off[data-v-4ca00a4d]{color:var(--wx-text-muted)}.wx-catalog-gallery[data-v-9479a729]{display:flex;flex-direction:column;gap:var(--wx-space-16);container-type:inline-size}.wx-catalog-gallery[data-v-9479a729] .wx-sortable-list__content{min-width:0}.wx-catalog-gallery__item[data-v-9479a729]{display:grid;grid-template-columns:96px minmax(0,1fr);gap:var(--wx-space-16);align-items:start;padding-block:var(--wx-space-8)}.wx-catalog-gallery__thumb[data-v-9479a729]{position:relative;display:block;width:96px;aspect-ratio:1;overflow:clip;border-radius:var(--wx-radius-sm);background:var(--wx-bg-subtle);border:1px solid var(--wx-border-default)}.wx-catalog-gallery__thumb img[data-v-9479a729]{width:100%;height:100%;min-width:0;object-fit:contain;display:block}.wx-catalog-gallery__main[data-v-9479a729]{position:absolute;inset-inline-start:var(--wx-space-4);inset-block-start:var(--wx-space-4)}.wx-catalog-gallery__words[data-v-9479a729]{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--wx-space-8)}@container (min-width: 640px){.wx-catalog-gallery__words[data-v-9479a729]{grid-template-columns:repeat(2,minmax(0,1fr))}.wx-catalog-gallery__words>.wx-text[data-v-9479a729]{grid-column:1 / -1}}@container (max-width: 420px){.wx-catalog-gallery__item[data-v-9479a729]{grid-template-columns:minmax(0,1fr)}}.wx-catalog-gallery__address[data-v-9479a729]{display:flex;gap:var(--wx-space-8);align-items:center;max-width:560px}.wx-catalog-gallery__address[data-v-9479a729]>:first-child{flex:1;min-width:0}.wx-catalog-product[data-v-837dd378]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16));container-type:inline-size}.wx-catalog-product__ghost[data-v-837dd378]{max-width:420px}.wx-catalog-bulk-params__field[data-v-b83c3fb0]{margin-top:var(--wx-space-16)}.wx-catalog-bulk[data-v-94557c14]{display:contents}.wx-catalog-bulk__progress[data-v-94557c14]{display:grid;gap:var(--wx-space-4);flex:1 1 240px;min-width:0}.wx-catalog-bulk__refused[data-v-94557c14]{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--wx-space-8);flex-basis:100%;min-width:0}.wx-catalog-bulk__errors[data-v-94557c14]{flex-basis:100%;font-size:var(--wx-font-size-sm)}.wx-catalog-bulk__errors summary[data-v-94557c14]{cursor:pointer;color:var(--wx-text-muted)}.wx-catalog-bulk__errors ul[data-v-94557c14]{margin:var(--wx-space-8) 0 0;padding-inline-start:var(--wx-space-18);max-height:200px;overflow:auto}.wx-catalog-products[data-v-541fe844]{min-width:0}.wx-catalog-products__selection[data-v-541fe844]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wx-space-12);padding:var(--wx-space-8) var(--wx-space-16);border-bottom:1px solid var(--wx-border-default);background:var(--wx-bg-subtle)}.wx-catalog-products__image[data-v-541fe844]{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:var(--wx-radius-sm);overflow:clip;background:var(--wx-bg-subtle);color:var(--wx-text-muted);vertical-align:middle}.wx-catalog-products__image img[data-v-541fe844]{width:100%;height:100%;min-width:0;object-fit:cover}.wx-catalog-products__name[data-v-541fe844]{display:flex;flex-direction:column;min-width:0}.wx-catalog-products__title[data-v-541fe844]{font-weight:var(--wx-font-weight-medium);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-products__sku[data-v-541fe844]{font-family:var(--wx-font-family-mono);font-size:var(--wx-font-size-sm);color:var(--wx-text-muted);min-height:1em}.wx-catalog-products__price[data-v-541fe844]{display:inline-flex;flex-direction:column;align-items:flex-end;font-variant-numeric:tabular-nums}.wx-catalog-products__price[data-v-541fe844]>*{white-space:nowrap}.wx-catalog-products__price small[data-v-541fe844],.wx-catalog-products__price s[data-v-541fe844]{font-size:var(--wx-font-size-sm);color:var(--wx-text-muted)}.wx-catalog-products__range[data-v-541fe844]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--wx-space-8)}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { LocalizedValue, Paginated } from '@webx-ui/core';
|
|
2
|
+
import { ScreenModel } from '@webx-ui/schema';
|
|
3
|
+
/**
|
|
4
|
+
* Published · taken off the site · in «Deleted» (§5). "Published" is what was asked for, not what
|
|
5
|
+
* a visitor sees: a published product in no visible category answers like an unpublished one,
|
|
6
|
+
* and `visible` on the row is the one that says so.
|
|
7
|
+
*/
|
|
8
|
+
export type ProductState = 'published' | 'unpublished' | 'deleted';
|
|
9
|
+
/** A category as a product names it — possibly one in the bin, which a restore cannot bring along. */
|
|
10
|
+
export interface CategoryRef {
|
|
11
|
+
id: number;
|
|
12
|
+
name: string;
|
|
13
|
+
deleted: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One product as a row of the list and as the head of its editor (§11.2).
|
|
17
|
+
*
|
|
18
|
+
* `price`, `old_price` and `barcode` are absent — not null — when the site has them switched off,
|
|
19
|
+
* so the panel cannot show a column the site does not have.
|
|
20
|
+
*/
|
|
21
|
+
export interface ProductRow {
|
|
22
|
+
id: number;
|
|
23
|
+
/** In the panel's language, with the usual fallback. */
|
|
24
|
+
name: string;
|
|
25
|
+
sku: string | null;
|
|
26
|
+
barcode?: string | null;
|
|
27
|
+
price?: number | null;
|
|
28
|
+
old_price?: number | null;
|
|
29
|
+
unit: string | null;
|
|
30
|
+
priority: number;
|
|
31
|
+
is_published: boolean;
|
|
32
|
+
state: ProductState;
|
|
33
|
+
/** Published and in at least one visible category (§5). */
|
|
34
|
+
visible: boolean;
|
|
35
|
+
/** The main one — `null` is decision 3's "no category". */
|
|
36
|
+
category: CategoryRef | null;
|
|
37
|
+
image: {
|
|
38
|
+
id: number;
|
|
39
|
+
url: string;
|
|
40
|
+
thumb: string | null;
|
|
41
|
+
} | null;
|
|
42
|
+
/** On the site; an unpublished one's too, which is the trimmed page. `null` once deleted. */
|
|
43
|
+
url: string | null;
|
|
44
|
+
created_at: string | null;
|
|
45
|
+
updated_at: string | null;
|
|
46
|
+
deleted_at: string | null;
|
|
47
|
+
/** The satellites' columns (`ProductColumns`), by key. Absent while none is installed. */
|
|
48
|
+
columns?: Record<string, string | number | boolean | null>;
|
|
49
|
+
/** A row of `WxTable`, which reads cells by key. */
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
/** A column a satellite adds to the list (§7.4). The values ride on each row under its key. */
|
|
53
|
+
export interface ProductColumnInfo {
|
|
54
|
+
key: string;
|
|
55
|
+
label: string;
|
|
56
|
+
/** The key of the `Sorts` registry that orders by it, or `null`. */
|
|
57
|
+
sort?: string | null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* What one facet counts for the list as it is filtered, its own choice aside: the values of a
|
|
61
|
+
* terms or tree facet with their words and counts, the bounds of a range, the products a toggle
|
|
62
|
+
* would leave.
|
|
63
|
+
*/
|
|
64
|
+
export interface FacetCount {
|
|
65
|
+
key: string;
|
|
66
|
+
kind: FacetKind;
|
|
67
|
+
values?: {
|
|
68
|
+
value: string;
|
|
69
|
+
label: string;
|
|
70
|
+
count: number;
|
|
71
|
+
}[];
|
|
72
|
+
min?: number | null;
|
|
73
|
+
max?: number | null;
|
|
74
|
+
count?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The list: Laravel's paginator as it is, with the number of products nobody filed (decision 3),
|
|
78
|
+
* the facets' counts and the satellites' columns.
|
|
79
|
+
*/
|
|
80
|
+
export interface ProductsPage extends Paginated<ProductRow> {
|
|
81
|
+
counts: {
|
|
82
|
+
no_category: number;
|
|
83
|
+
};
|
|
84
|
+
facets?: Record<string, FacetCount>;
|
|
85
|
+
columns?: ProductColumnInfo[];
|
|
86
|
+
}
|
|
87
|
+
/** A key of the `Sorts` registry: `default`, `new`, `popular`, `price_asc` — whatever it holds. */
|
|
88
|
+
export type ProductSort = string;
|
|
89
|
+
/** One way to order the list, as the registry names it. */
|
|
90
|
+
export interface SortInfo {
|
|
91
|
+
key: string;
|
|
92
|
+
label: string;
|
|
93
|
+
}
|
|
94
|
+
/** One facet's choice in the list's filter: values, a range, or on. */
|
|
95
|
+
export type FacetChoice = Array<string | number> | {
|
|
96
|
+
min?: number | null;
|
|
97
|
+
max?: number | null;
|
|
98
|
+
} | true;
|
|
99
|
+
export interface ProductQuery {
|
|
100
|
+
q?: string;
|
|
101
|
+
state?: 'published' | 'unpublished' | 'no-category' | '';
|
|
102
|
+
sort?: ProductSort | null;
|
|
103
|
+
page?: number;
|
|
104
|
+
per_page?: number;
|
|
105
|
+
/** Facet key → what is chosen. Sent as `facets[key][]=…`, `facets[key][min]=…`; on is `facets[key][]=1`. */
|
|
106
|
+
facets?: Record<string, FacetChoice>;
|
|
107
|
+
}
|
|
108
|
+
/** One picture of the gallery; `alt` and `title` in every language at once (§11.1). */
|
|
109
|
+
export interface ProductImage {
|
|
110
|
+
id: number;
|
|
111
|
+
path: string;
|
|
112
|
+
url: string;
|
|
113
|
+
thumb: string | null;
|
|
114
|
+
alt: LocalizedValue;
|
|
115
|
+
title: LocalizedValue;
|
|
116
|
+
width: number | null;
|
|
117
|
+
height: number | null;
|
|
118
|
+
size: number | null;
|
|
119
|
+
position: number;
|
|
120
|
+
}
|
|
121
|
+
/** One product as its editor opens it. */
|
|
122
|
+
export interface ProductDetail {
|
|
123
|
+
product: ProductRow;
|
|
124
|
+
values: ScreenModel;
|
|
125
|
+
images: ProductImage[];
|
|
126
|
+
}
|
|
127
|
+
/** The 422 of a taken article number: who holds it and where to open them. */
|
|
128
|
+
export interface SkuHolder {
|
|
129
|
+
id: number;
|
|
130
|
+
name: string;
|
|
131
|
+
url: string;
|
|
132
|
+
deleted: boolean;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* What the tree and the editor both say about a category. `products_count` is live products in it
|
|
136
|
+
* and everything under it, main and additional alike, each product once.
|
|
137
|
+
*/
|
|
138
|
+
interface CategoryFields {
|
|
139
|
+
id: number;
|
|
140
|
+
parent_id: number | null;
|
|
141
|
+
name: string;
|
|
142
|
+
slug: string | null;
|
|
143
|
+
depth: number;
|
|
144
|
+
is_published: boolean;
|
|
145
|
+
/** Published, and so is every category above it (§6.3). */
|
|
146
|
+
visible: boolean;
|
|
147
|
+
products_count: number;
|
|
148
|
+
url: string | null;
|
|
149
|
+
}
|
|
150
|
+
/** One category of the tree (§6.1). */
|
|
151
|
+
export interface CategoryNode extends CategoryFields {
|
|
152
|
+
children: CategoryNode[];
|
|
153
|
+
/** A row of `WxTable` and a node of `WxTreeSelect`, both of which read by key. */
|
|
154
|
+
[key: string]: unknown;
|
|
155
|
+
}
|
|
156
|
+
/** One category as the head of its editor. */
|
|
157
|
+
export interface CategoryRow extends CategoryFields {
|
|
158
|
+
created_at: string | null;
|
|
159
|
+
updated_at: string | null;
|
|
160
|
+
deleted_at: string | null;
|
|
161
|
+
}
|
|
162
|
+
export interface CategoryDetail {
|
|
163
|
+
category: CategoryRow;
|
|
164
|
+
values: ScreenModel;
|
|
165
|
+
/**
|
|
166
|
+
* Whose facet setting it shows while it has none of its own: the nearest ancestor with one.
|
|
167
|
+
* `null` when it has its own, and when nobody above it has — every facet by default (§6.2).
|
|
168
|
+
*/
|
|
169
|
+
facets_from?: {
|
|
170
|
+
id: number;
|
|
171
|
+
name: string;
|
|
172
|
+
} | null;
|
|
173
|
+
}
|
|
174
|
+
/** A category's own facet setting: the facets in its order, each shown or not (§6.2). */
|
|
175
|
+
export interface FacetSetting {
|
|
176
|
+
key: string;
|
|
177
|
+
visible: boolean;
|
|
178
|
+
}
|
|
179
|
+
export type FacetKind = 'terms' | 'range' | 'toggle' | 'tree';
|
|
180
|
+
/**
|
|
181
|
+
* One facet of the registry. Its values are not here: the list counts them for what it shows
|
|
182
|
+
* (`ProductsPage.facets`), and the tree facet (the categories) is chosen from the tree itself.
|
|
183
|
+
*/
|
|
184
|
+
export interface FacetInfo {
|
|
185
|
+
key: string;
|
|
186
|
+
code: string;
|
|
187
|
+
kind: FacetKind;
|
|
188
|
+
label: string;
|
|
189
|
+
/** Whether its first level may be an open page of the storefront (§8.1 of the architecture). */
|
|
190
|
+
indexable?: boolean;
|
|
191
|
+
}
|
|
192
|
+
/** `GET /facets`: the registry of facets, and the sorts the list can be ordered by. */
|
|
193
|
+
export interface FacetRegistryAnswer {
|
|
194
|
+
facets: FacetInfo[];
|
|
195
|
+
sorts: SortInfo[];
|
|
196
|
+
}
|
|
197
|
+
/** A row of «Deleted» — products. */
|
|
198
|
+
export interface DeletedProduct {
|
|
199
|
+
id: number;
|
|
200
|
+
name: string;
|
|
201
|
+
sku: string | null;
|
|
202
|
+
category: CategoryRef | null;
|
|
203
|
+
deleted_at: string | null;
|
|
204
|
+
[key: string]: unknown;
|
|
205
|
+
}
|
|
206
|
+
/** A row of «Deleted» — categories. */
|
|
207
|
+
export interface DeletedCategory {
|
|
208
|
+
id: number;
|
|
209
|
+
name: string;
|
|
210
|
+
slug: string | null;
|
|
211
|
+
parent: CategoryRef | null;
|
|
212
|
+
deleted_at: string | null;
|
|
213
|
+
[key: string]: unknown;
|
|
214
|
+
}
|
|
215
|
+
export type DeletedKind = 'products' | 'categories';
|
|
216
|
+
/** What a bulk action asks for before it runs (`PartField` on the server). */
|
|
217
|
+
export interface BulkParam {
|
|
218
|
+
name: string;
|
|
219
|
+
/** `category` draws the tree; anything else with `values` a list; the rest a text field. */
|
|
220
|
+
type: string;
|
|
221
|
+
label: string;
|
|
222
|
+
rules?: string[];
|
|
223
|
+
/** The allowed values, or the tool that lists them — which the panel does not follow. */
|
|
224
|
+
values?: Array<string | number | {
|
|
225
|
+
value: string | number;
|
|
226
|
+
label: string;
|
|
227
|
+
}> | string;
|
|
228
|
+
}
|
|
229
|
+
/** One bulk action the server offers this administrator (§11.4): the core's or a satellite's. */
|
|
230
|
+
export interface BulkActionInfo {
|
|
231
|
+
key: string;
|
|
232
|
+
label: string;
|
|
233
|
+
permission: string;
|
|
234
|
+
/** It acts on the products in «Deleted» — a restore. */
|
|
235
|
+
trashed: boolean;
|
|
236
|
+
params: BulkParam[];
|
|
237
|
+
}
|
|
238
|
+
/** Rows ticked, or everything the list's query finds — turned into ids when the run starts. */
|
|
239
|
+
export type BulkSelection = {
|
|
240
|
+
ids: number[];
|
|
241
|
+
} | {
|
|
242
|
+
query: {
|
|
243
|
+
q?: string;
|
|
244
|
+
state?: string;
|
|
245
|
+
facets?: Record<string, Array<string | number> | {
|
|
246
|
+
min?: number | null;
|
|
247
|
+
max?: number | null;
|
|
248
|
+
}>;
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
export interface BulkRunError {
|
|
252
|
+
id: number;
|
|
253
|
+
name: string;
|
|
254
|
+
message: string;
|
|
255
|
+
}
|
|
256
|
+
/** A run: done inside the request (`id` null) or queued, polled until it is `done` or `failed`. */
|
|
257
|
+
export interface BulkRun {
|
|
258
|
+
id: number | null;
|
|
259
|
+
action: string;
|
|
260
|
+
label: string;
|
|
261
|
+
status: 'queued' | 'running' | 'done' | 'failed';
|
|
262
|
+
total: number;
|
|
263
|
+
done: number;
|
|
264
|
+
failed: number;
|
|
265
|
+
errors: BulkRunError[];
|
|
266
|
+
history_id: number | null;
|
|
267
|
+
created_at: string | null;
|
|
268
|
+
finished_at: string | null;
|
|
269
|
+
}
|
|
270
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@webx-ui/module-catalog",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The catalogue of the WebX UI admin panel: products with a gallery, a tree of categories with their filters, and the deleted ones waiting to come back.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": [
|
|
8
|
+
"*.css"
|
|
9
|
+
],
|
|
10
|
+
"keywords": [
|
|
11
|
+
"webx-ui",
|
|
12
|
+
"vue",
|
|
13
|
+
"admin",
|
|
14
|
+
"cms",
|
|
15
|
+
"catalog",
|
|
16
|
+
"e-commerce"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/webx-ui/webx-ui.git",
|
|
21
|
+
"directory": "packages/module-catalog"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/webx-ui/webx-ui/tree/main/packages/module-catalog",
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"module": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"import": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./style.css": "./dist/style.css",
|
|
39
|
+
"./dist/style.css": "./dist/style.css",
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"vue": "^3.5.0",
|
|
44
|
+
"vue-router": "^4.5.0"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@webx-ui/core": "^0.34.1",
|
|
48
|
+
"@webx-ui/module-admin": "^0.19.0",
|
|
49
|
+
"@webx-ui/schema": "^0.6.4"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^24.10.1",
|
|
53
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
54
|
+
"typescript": "^5.9.3",
|
|
55
|
+
"vite": "^7.1.14",
|
|
56
|
+
"vite-plugin-dts": "^4.5.4",
|
|
57
|
+
"vue": "^3.5.24",
|
|
58
|
+
"vue-router": "^4.5.1",
|
|
59
|
+
"vue-tsc": "^3.1.3"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "vite build",
|
|
63
|
+
"dev": "vite build --watch",
|
|
64
|
+
"typecheck": "vue-tsc -p tsconfig.json --noEmit"
|
|
65
|
+
}
|
|
66
|
+
}
|