@cosmicdrift/kumiko-samples 0.402.0 → 0.403.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-samples",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.403.0",
|
|
4
4
|
"description": "Source trees of the Kumiko sample recipes, sample apps and bundled features in repo layout, for tooling such as few-shot corpus builds.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.403.0",
|
|
4
4
|
"description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -28,6 +28,11 @@ query and the fields to read, the query does the counting.
|
|
|
28
28
|
- **Fallback by reason**: `fallback: { forbidden, notFound }` renders a screen on
|
|
29
29
|
403/404 of the gate query; other reasons get the default notice or an error
|
|
30
30
|
banner with retry.
|
|
31
|
+
- **Named filter shared by tile and list**: the entity declares `namedFilters`,
|
|
32
|
+
the `ticket-queue` entityList lists the id in `namedFilters`, and the
|
|
33
|
+
`open-work` stat counts through the list's own query with `params.namedFilter`
|
|
34
|
+
and `navigate`. A click opens the queue filtered by the same rule, so tile and
|
|
35
|
+
list cannot drift.
|
|
31
36
|
|
|
32
37
|
## When to reach for it
|
|
33
38
|
|
|
@@ -21,10 +21,15 @@ export const ticketEntity = createEntity({
|
|
|
21
21
|
title: createTextField({ personal: false, reason: "is_business_data", required: true }),
|
|
22
22
|
status: createSelectField({ options: TICKET_STATUSES, default: "open", required: true }),
|
|
23
23
|
},
|
|
24
|
+
// Defined once: the queue list and the dashboard tile both read it.
|
|
25
|
+
namedFilters: {
|
|
26
|
+
"open-work": { filters: () => [{ field: "status", op: "eq", value: "open" }] },
|
|
27
|
+
},
|
|
24
28
|
});
|
|
25
29
|
|
|
26
30
|
export const TICKET_STATS_QUERY = "tickets:query:ticket:stats";
|
|
27
31
|
export const TICKET_CAPABILITIES_QUERY = "tickets:query:ticket:capabilities";
|
|
32
|
+
export const TICKET_LIST_QUERY = "tickets:query:ticket:list";
|
|
28
33
|
|
|
29
34
|
const readerRoles = { roles: ["Admin", "User"] } as const;
|
|
30
35
|
|
|
@@ -109,6 +114,9 @@ export const ticketFeature = defineFeature("tickets", (r) => {
|
|
|
109
114
|
"tickets.dashboard.open": { en: "Open" },
|
|
110
115
|
"tickets.dashboard.closed": { en: "Closed" },
|
|
111
116
|
"tickets.dashboard.total": { en: "All tickets" },
|
|
117
|
+
"tickets.dashboard.open-work": { en: "Open work" },
|
|
118
|
+
"tickets.filter.open-work": { en: "Open work" },
|
|
119
|
+
"screen:ticket-queue.title": { en: "Ticket queue" },
|
|
112
120
|
},
|
|
113
121
|
});
|
|
114
122
|
|
|
@@ -144,6 +152,16 @@ export const ticketFeature = defineFeature("tickets", (r) => {
|
|
|
144
152
|
query: TICKET_STATS_QUERY,
|
|
145
153
|
valueField: "total",
|
|
146
154
|
},
|
|
155
|
+
// Counts through the list's own query with the same named filter, then links to that list.
|
|
156
|
+
{
|
|
157
|
+
kind: "stat",
|
|
158
|
+
id: "open-work",
|
|
159
|
+
label: "tickets.dashboard.open-work",
|
|
160
|
+
query: TICKET_LIST_QUERY,
|
|
161
|
+
valueField: "total",
|
|
162
|
+
params: { namedFilter: "open-work", limit: 1, totalCount: true },
|
|
163
|
+
navigate: { screen: "ticket-queue", namedFilter: "open-work" },
|
|
164
|
+
},
|
|
147
165
|
],
|
|
148
166
|
access: readerRoles,
|
|
149
167
|
});
|
|
@@ -152,6 +170,15 @@ export const ticketFeature = defineFeature("tickets", (r) => {
|
|
|
152
170
|
// button, and a fallback chosen by reason.
|
|
153
171
|
const gate = { query: TICKET_CAPABILITIES_QUERY, field: "canClose", eq: true } as const;
|
|
154
172
|
|
|
173
|
+
r.screen({
|
|
174
|
+
id: "ticket-queue",
|
|
175
|
+
type: "entityList",
|
|
176
|
+
entity: "ticket",
|
|
177
|
+
columns: ["title", "status"],
|
|
178
|
+
namedFilters: [{ id: "open-work", label: "tickets.filter.open-work" }],
|
|
179
|
+
access: readerRoles,
|
|
180
|
+
});
|
|
181
|
+
|
|
155
182
|
// The list doubles as the fallback target: it has no visibleWhen of its own.
|
|
156
183
|
r.screen({
|
|
157
184
|
id: "ticket-list",
|