@cosmicdrift/kumiko-samples 0.383.0 → 0.384.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 +1 -1
- package/packages/bundled-features/package.json +6 -1
- package/packages/bundled-features/src/audit/changes.json +6 -0
- package/packages/bundled-features/src/audit/event-classification.ts +83 -0
- package/packages/bundled-features/src/audit/feature.ts +3 -2
- package/packages/bundled-features/src/audit/handlers/audit-events.ts +63 -5
- package/packages/bundled-features/src/audit/handlers/details-all-tenants.query.ts +6 -5
- package/packages/bundled-features/src/audit/handlers/details.query.ts +12 -6
- package/packages/bundled-features/src/audit/handlers/list-all-tenants.query.ts +20 -12
- package/packages/bundled-features/src/audit/handlers/list.query.ts +14 -3
- package/packages/bundled-features/src/audit/screens.ts +32 -4
- package/packages/bundled-features/src/audit/web/audit-event-cell.tsx +22 -0
- package/packages/bundled-features/src/audit/web/audit-event-labels.ts +30 -0
- package/packages/bundled-features/src/audit/web/client-plugin.tsx +10 -1
- package/packages/bundled-features/src/audit/web/constants.ts +11 -0
- package/packages/bundled-features/src/audit/web/i18n.ts +48 -1
- package/packages/bundled-features/src/auth-email-password/changes.json +6 -0
- package/packages/bundled-features/src/auth-email-password/feature.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/handlers/login-options.query.ts +19 -0
- package/packages/bundled-features/src/auth-email-password/index.ts +7 -1
- package/packages/bundled-features/src/auth-email-password/{auth-paths.ts → web/auth-paths.ts} +7 -4
- package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +7 -0
- package/packages/bundled-features/src/auth-email-password/web/constants.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/web/default-auth-pages-gate.tsx +31 -0
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +68 -42
- package/packages/bundled-features/src/jobs/changes.json +6 -0
- package/packages/bundled-features/src/jobs/feature.ts +34 -127
- package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +98 -0
- package/packages/bundled-features/src/jobs/handlers/consumers.query.ts +137 -0
- package/packages/bundled-features/src/jobs/screens.ts +262 -0
- package/packages/bundled-features/src/jobs/web/constants.ts +29 -0
- package/packages/bundled-features/src/jobs/web/i18n.ts +41 -0
- package/packages/bundled-features/src/secrets/i18n.ts +0 -3
- package/packages/bundled-features/src/sessions/changes.json +6 -0
- package/packages/bundled-features/src/sessions/constants.ts +3 -1
- package/packages/bundled-features/src/sessions/handlers/detail.query.ts +7 -3
- package/packages/bundled-features/src/sessions/handlers/list.query.ts +16 -10
- package/packages/bundled-features/src/sessions/handlers/mine.query.ts +15 -9
- package/packages/bundled-features/src/sessions/screens.ts +23 -8
- package/packages/bundled-features/src/sessions/web/client-plugin.tsx +17 -0
- package/packages/bundled-features/src/sessions/web/constants.ts +3 -0
- package/packages/bundled-features/src/sessions/web/default-translations.ts +8 -0
- package/packages/bundled-features/src/sessions/web/i18n.ts +5 -1
- package/packages/bundled-features/src/sessions/web/index.ts +1 -0
- package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +19 -0
- package/packages/bundled-features/src/sessions/web/user-agent.ts +74 -0
- package/packages/bundled-features/src/template-resolver/changes.json +6 -0
- package/packages/bundled-features/src/template-resolver/feature.ts +2 -0
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +34 -1
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-counts.query.ts +53 -0
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +51 -0
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +7 -38
- package/packages/bundled-features/src/template-resolver/web/qualified-names.ts +1 -0
- package/packages/bundled-features/src/user-data-rights/changes.json +18 -0
- package/packages/bundled-features/src/user-data-rights/feature.ts +33 -33
- package/packages/bundled-features/src/user-data-rights/web/i18n.ts +4 -1
- package/samples/apps/showcase/src/features/items/schema/item.ts +8 -2
- package/samples/apps/ui-walkthrough/src/features/tasks/schema/task.ts +2 -2
- package/samples/apps/use-all-bundled/feature-manifest.json +4 -0
- package/samples/apps/use-all-bundled/src/app/client.tsx +2 -0
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +2 -1
- package/samples/apps/use-all-bundled/src/app/invoice-reports-feature.ts +30 -0
- package/samples/apps/use-all-bundled/src/app/seed.ts +51 -0
- package/samples/apps/workspaces/src/features/demo/schema/order.ts +2 -2
- package/samples/recipes/custom-fields-basic/src/feature.ts +13 -3
- package/samples/recipes/designer-demo/src/feature.ts +6 -2
|
@@ -399,7 +399,9 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
399
399
|
},
|
|
400
400
|
},
|
|
401
401
|
dormant: true,
|
|
402
|
-
description:
|
|
402
|
+
description: showDeletion
|
|
403
|
+
? "userDataRights.privacyCenter.subtitle"
|
|
404
|
+
: "userDataRights.privacyCenter.subtitleWithoutDeletion",
|
|
403
405
|
fieldLabels: {
|
|
404
406
|
status: i18nKey("userDataRights.privacyCenter.field.status"),
|
|
405
407
|
gracePeriodEnd: i18nKey("userDataRights.privacyCenter.field.gracePeriodEnd"),
|
|
@@ -425,6 +427,17 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
425
427
|
renderer: { format: "enumOption", keyPrefix: STATUS_OPTION_KEY_PREFIX },
|
|
426
428
|
},
|
|
427
429
|
],
|
|
430
|
+
actions: [
|
|
431
|
+
{
|
|
432
|
+
id: "restrict",
|
|
433
|
+
icon: "lock",
|
|
434
|
+
label: i18nKey("userDataRights.privacyCenter.restriction.restrict"),
|
|
435
|
+
handler: UserDataRightsHandlers.restrictAccount,
|
|
436
|
+
confirm: i18nKey("userDataRights.privacyCenter.restriction.dialogDescription"),
|
|
437
|
+
visible: { field: "status", ne: "restricted" },
|
|
438
|
+
style: "secondary",
|
|
439
|
+
},
|
|
440
|
+
],
|
|
428
441
|
},
|
|
429
442
|
...(showDeletion
|
|
430
443
|
? [
|
|
@@ -441,43 +454,30 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
441
454
|
visible: { field: "status", eq: "deletionRequested" },
|
|
442
455
|
},
|
|
443
456
|
],
|
|
457
|
+
actions: [
|
|
458
|
+
{
|
|
459
|
+
id: "request-deletion",
|
|
460
|
+
label: i18nKey("userDataRights.privacyCenter.deletion.delete"),
|
|
461
|
+
handler: UserDataRightsHandlers.requestDeletion,
|
|
462
|
+
confirm: i18nKey("userDataRights.privacyCenter.deletion.dialogDescription"),
|
|
463
|
+
visible: { field: "status", ne: "deletionRequested" },
|
|
464
|
+
style: "danger" as const,
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
id: "cancel-deletion",
|
|
468
|
+
label: i18nKey("userDataRights.privacyCenter.deletion.cancel"),
|
|
469
|
+
handler: UserDataRightsHandlers.cancelDeletion,
|
|
470
|
+
visible: { field: "status", eq: "deletionRequested" },
|
|
471
|
+
style: "secondary" as const,
|
|
472
|
+
// Declared: the id's last segment ("deletion") would otherwise resolve to the destructive trash icon.
|
|
473
|
+
icon: "x" as const,
|
|
474
|
+
},
|
|
475
|
+
],
|
|
444
476
|
},
|
|
445
477
|
]
|
|
446
478
|
: []),
|
|
447
479
|
],
|
|
448
480
|
},
|
|
449
|
-
actions: [
|
|
450
|
-
{
|
|
451
|
-
id: "restrict",
|
|
452
|
-
icon: "lock",
|
|
453
|
-
label: i18nKey("userDataRights.privacyCenter.restriction.restrict"),
|
|
454
|
-
handler: UserDataRightsHandlers.restrictAccount,
|
|
455
|
-
confirm: i18nKey("userDataRights.privacyCenter.restriction.dialogDescription"),
|
|
456
|
-
visible: { field: "status", ne: "restricted" },
|
|
457
|
-
style: "danger",
|
|
458
|
-
},
|
|
459
|
-
...(showDeletion
|
|
460
|
-
? [
|
|
461
|
-
{
|
|
462
|
-
id: "request-deletion",
|
|
463
|
-
label: i18nKey("userDataRights.privacyCenter.deletion.delete"),
|
|
464
|
-
handler: UserDataRightsHandlers.requestDeletion,
|
|
465
|
-
confirm: i18nKey("userDataRights.privacyCenter.deletion.dialogDescription"),
|
|
466
|
-
visible: { field: "status", ne: "deletionRequested" },
|
|
467
|
-
style: "danger" as const,
|
|
468
|
-
},
|
|
469
|
-
{
|
|
470
|
-
id: "cancel-deletion",
|
|
471
|
-
label: i18nKey("userDataRights.privacyCenter.deletion.cancel"),
|
|
472
|
-
handler: UserDataRightsHandlers.cancelDeletion,
|
|
473
|
-
visible: { field: "status", eq: "deletionRequested" },
|
|
474
|
-
style: "secondary" as const,
|
|
475
|
-
// Declared: the id's last segment ("deletion") would otherwise resolve to the destructive trash icon.
|
|
476
|
-
icon: "x" as const,
|
|
477
|
-
},
|
|
478
|
-
]
|
|
479
|
-
: []),
|
|
480
|
-
],
|
|
481
481
|
});
|
|
482
482
|
|
|
483
483
|
// Magic-link path (anonymous): the email link carries the token as a
|
|
@@ -14,7 +14,10 @@ export const USER_DATA_RIGHTS_I18N: Readonly<Record<string, LocalizedString>> =
|
|
|
14
14
|
"screen:download-attempt-list.title": { en: "Download attempts" },
|
|
15
15
|
"screen:privacy-center.title": { en: "Privacy" },
|
|
16
16
|
"userDataRights.privacyCenter.subtitle": {
|
|
17
|
-
en: "
|
|
17
|
+
en: "Download a copy of your data (Art. 20), restrict processing of your account (Art. 18) or delete it (Art. 17).",
|
|
18
|
+
},
|
|
19
|
+
"userDataRights.privacyCenter.subtitleWithoutDeletion": {
|
|
20
|
+
en: "Download a copy of your data (Art. 20) or restrict processing of your account (Art. 18).",
|
|
18
21
|
},
|
|
19
22
|
"user-data-rights:entity:export-job:field:userId": { en: "User" },
|
|
20
23
|
"user-data-rights:entity:export-job:field:status": { en: "Status" },
|
|
@@ -19,8 +19,14 @@ export const itemEntity = {
|
|
|
19
19
|
description:
|
|
20
20
|
"A showcase task item carrying a title, free-text notes, a numeric priority, a done flag, a due date and a draft/active/blocked/done status, plus an optional parent item and a list of related items.",
|
|
21
21
|
fields: {
|
|
22
|
-
title: {
|
|
23
|
-
|
|
22
|
+
title: {
|
|
23
|
+
type: "text",
|
|
24
|
+
required: true,
|
|
25
|
+
sortable: true,
|
|
26
|
+
searchable: true,
|
|
27
|
+
allowPlaintext: "is_business_data",
|
|
28
|
+
},
|
|
29
|
+
notes: { type: "text", multiline: { rows: 4 }, allowPlaintext: "is_business_data" },
|
|
24
30
|
priority: { type: "number", default: 1, sortable: true, filterable: true },
|
|
25
31
|
isDone: { type: "boolean", default: false, sortable: true, filterable: true },
|
|
26
32
|
dueDate: { type: "date", sortable: true, filterable: true },
|
|
@@ -29,12 +29,12 @@ export const taskEntity = {
|
|
|
29
29
|
table: "read_ui_walkthrough_tasks",
|
|
30
30
|
|
|
31
31
|
fields: {
|
|
32
|
-
title: { type: "text", required: true, sortable: true },
|
|
32
|
+
title: { type: "text", required: true, sortable: true, allowPlaintext: "is_business_data" },
|
|
33
33
|
status: { type: "select", options: TASK_STATUSES, display: "radio", sortable: true },
|
|
34
34
|
area: { type: "select", options: TASK_AREAS },
|
|
35
35
|
priority: { type: "number" },
|
|
36
36
|
isUrgent: { type: "boolean", default: false },
|
|
37
|
-
notes: { type: "text" },
|
|
37
|
+
notes: { type: "text", allowPlaintext: "is_business_data" },
|
|
38
38
|
},
|
|
39
39
|
} as unknown as EntityDefinition;
|
|
40
40
|
|
|
@@ -1473,6 +1473,10 @@
|
|
|
1473
1473
|
"configKeys": [],
|
|
1474
1474
|
"secrets": [],
|
|
1475
1475
|
"writeHandlers": [
|
|
1476
|
+
"jobs:write:consumer-disable",
|
|
1477
|
+
"jobs:write:consumer-enable",
|
|
1478
|
+
"jobs:write:consumer-restart",
|
|
1479
|
+
"jobs:write:consumer-skip",
|
|
1476
1480
|
"jobs:write:retry",
|
|
1477
1481
|
"jobs:write:trigger"
|
|
1478
1482
|
],
|
|
@@ -27,6 +27,7 @@ import { deliveryClient } from "@cosmicdrift/kumiko-bundled-features/delivery/we
|
|
|
27
27
|
import { featureTogglesClient } from "@cosmicdrift/kumiko-bundled-features/feature-toggles/web";
|
|
28
28
|
import { foldersClient } from "@cosmicdrift/kumiko-bundled-features/folders/web";
|
|
29
29
|
import { jobsClient } from "@cosmicdrift/kumiko-bundled-features/jobs/web";
|
|
30
|
+
import { sessionsClient } from "@cosmicdrift/kumiko-bundled-features/sessions/web";
|
|
30
31
|
import { tagsClient } from "@cosmicdrift/kumiko-bundled-features/tags/web";
|
|
31
32
|
import { textBlocksClient } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
32
33
|
import { tenantClient } from "@cosmicdrift/kumiko-bundled-features/tenant/web";
|
|
@@ -103,6 +104,7 @@ createKumikoApp({
|
|
|
103
104
|
adminShellClient(),
|
|
104
105
|
tenantClient(),
|
|
105
106
|
auditClient(),
|
|
107
|
+
sessionsClient(),
|
|
106
108
|
billingFoundationClient(),
|
|
107
109
|
jobsClient(),
|
|
108
110
|
deliveryClient(),
|
|
@@ -15,6 +15,7 @@ import type { RunDevAppOptions } from "@cosmicdrift/kumiko-dev-server";
|
|
|
15
15
|
import { SYSTEM_TENANT_ID, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
16
16
|
import { AUTH_COMPOSE_OPTIONS, BOOT_FEATURES } from "../run-config";
|
|
17
17
|
import { ADMIN_EMAIL, ADMIN_PASSWORD, BETA_TENANT_ID, DEV_TENANT_ID } from "./auth-constants";
|
|
18
|
+
import { invoiceReportsFeature } from "./invoice-reports-feature";
|
|
18
19
|
import { notesFeature } from "./notes-feature";
|
|
19
20
|
import { appScreensFeature } from "./screens-feature";
|
|
20
21
|
import { seedScreenshotData } from "./seed";
|
|
@@ -27,7 +28,7 @@ import { seedScreenshotData } from "./seed";
|
|
|
27
28
|
export const devAppOptions = {
|
|
28
29
|
// notesFeature is dev-only (app-owned tag host) — see notes-feature.ts for why
|
|
29
30
|
// it stays out of APP_FEATURES. appScreensFeature places the user-profile screen.
|
|
30
|
-
features: [...BOOT_FEATURES, appScreensFeature, notesFeature],
|
|
31
|
+
features: [...BOOT_FEATURES, appScreensFeature, notesFeature, invoiceReportsFeature],
|
|
31
32
|
featureToggles: true,
|
|
32
33
|
port: Number.parseInt(process.env["PORT"] ?? "4186", 10),
|
|
33
34
|
clientEntry: "./src/app/client.tsx",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// @runtime dev
|
|
2
|
+
//
|
|
3
|
+
// Dev-/screenshot-only host for realistic event consumers. The consumers never
|
|
4
|
+
// receive an event here; the screenshot seed parks them in the dead/disabled
|
|
5
|
+
// states the jobs:event-consumers screen is meant to show.
|
|
6
|
+
|
|
7
|
+
import { entityEventName } from "@cosmicdrift/kumiko-framework/db";
|
|
8
|
+
import { defineFeature, type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
|
+
|
|
10
|
+
export const INVOICE_TOTALS_CONSUMER = "invoice-totals";
|
|
11
|
+
export const OVERDUE_REMINDERS_CONSUMER = "overdue-reminders";
|
|
12
|
+
export const CUSTOMER_STATEMENTS_CONSUMER = "customer-statements";
|
|
13
|
+
|
|
14
|
+
const noop = async (): Promise<void> => {};
|
|
15
|
+
|
|
16
|
+
export const invoiceReportsFeature: FeatureDefinition = defineFeature("invoice-reports", (r) => {
|
|
17
|
+
r.describe(
|
|
18
|
+
"Dev-only host for the invoice read models whose consumer state the screenshot seed sets.",
|
|
19
|
+
);
|
|
20
|
+
for (const name of [
|
|
21
|
+
INVOICE_TOTALS_CONSUMER,
|
|
22
|
+
OVERDUE_REMINDERS_CONSUMER,
|
|
23
|
+
CUSTOMER_STATEMENTS_CONSUMER,
|
|
24
|
+
]) {
|
|
25
|
+
r.multiStreamProjection({
|
|
26
|
+
name,
|
|
27
|
+
apply: { [entityEventName("invoice", "created")]: noop },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
type DbConnection,
|
|
31
31
|
fetchOne,
|
|
32
32
|
insertOne,
|
|
33
|
+
upsertOnConflict,
|
|
33
34
|
} from "@cosmicdrift/kumiko-framework/db";
|
|
34
35
|
import {
|
|
35
36
|
createEntityExecutor,
|
|
@@ -37,11 +38,17 @@ import {
|
|
|
37
38
|
SYSTEM_TENANT_ID,
|
|
38
39
|
type TenantId,
|
|
39
40
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
41
|
+
import {
|
|
42
|
+
ConsumerStatuses,
|
|
43
|
+
eventConsumerStateTable,
|
|
44
|
+
SHARED_INSTANCE_SENTINEL,
|
|
45
|
+
} from "@cosmicdrift/kumiko-framework/pipeline";
|
|
40
46
|
import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
41
47
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
42
48
|
import { unsafeCreateEntityTable } from "@cosmicdrift/kumiko-testing/stack";
|
|
43
49
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
44
50
|
import { ADMIN_EMAIL, BETA_TENANT_ID, DEMO_NOTE_ID, DEV_TENANT_ID } from "./auth-constants";
|
|
51
|
+
import { INVOICE_TOTALS_CONSUMER, OVERDUE_REMINDERS_CONSUMER } from "./invoice-reports-feature";
|
|
45
52
|
import { noteEntity } from "./notes-feature";
|
|
46
53
|
import { seedPdfDocuments } from "./seed-documents";
|
|
47
54
|
|
|
@@ -266,6 +273,48 @@ const PRIVACY_BODY = [
|
|
|
266
273
|
"Access, rectification, erasure, restriction, portability, objection.",
|
|
267
274
|
].join("\n");
|
|
268
275
|
|
|
276
|
+
// Dispatcher state, not an event-sourced table: parks two invoice consumers the
|
|
277
|
+
// way a failing handler and an operator pause would leave them, so the
|
|
278
|
+
// jobs:event-consumers screens have a dead and a paused row to show.
|
|
279
|
+
async function seedEventConsumerStates(stack: Parameters<SeedFn>[0]): Promise<void> {
|
|
280
|
+
const qualifiedNameOf = (consumer: string): string => {
|
|
281
|
+
const found = [...stack.registry.getAllMultiStreamProjections().keys()].find(
|
|
282
|
+
(name) => name === consumer || name.endsWith(`:${consumer}`),
|
|
283
|
+
);
|
|
284
|
+
if (!found) throw new Error(`seedEventConsumerStates: consumer "${consumer}" not registered`);
|
|
285
|
+
return found;
|
|
286
|
+
};
|
|
287
|
+
const parked = [
|
|
288
|
+
{
|
|
289
|
+
consumer: INVOICE_TOTALS_CONSUMER,
|
|
290
|
+
status: ConsumerStatuses.dead,
|
|
291
|
+
attempts: 5,
|
|
292
|
+
lastError:
|
|
293
|
+
'TypeError: Cannot read properties of undefined (reading "amount") while applying invoice.created (event 48213): payload.lineItems[2].netPrice.amount is missing',
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
consumer: OVERDUE_REMINDERS_CONSUMER,
|
|
297
|
+
status: ConsumerStatuses.disabled,
|
|
298
|
+
attempts: 0,
|
|
299
|
+
lastError: null,
|
|
300
|
+
},
|
|
301
|
+
];
|
|
302
|
+
for (const { consumer, status, attempts, lastError } of parked) {
|
|
303
|
+
await upsertOnConflict(
|
|
304
|
+
stack.db,
|
|
305
|
+
eventConsumerStateTable,
|
|
306
|
+
{
|
|
307
|
+
name: qualifiedNameOf(consumer),
|
|
308
|
+
instanceId: SHARED_INSTANCE_SENTINEL,
|
|
309
|
+
status,
|
|
310
|
+
attempts,
|
|
311
|
+
lastError,
|
|
312
|
+
},
|
|
313
|
+
{ conflictKeys: ["name", "instanceId"], update: { status, attempts, lastError } },
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
269
318
|
export const seedScreenshotData: SeedFn = async (stack) => {
|
|
270
319
|
const devTenant = DEV_TENANT_ID as TenantId;
|
|
271
320
|
const betaTenant = BETA_TENANT_ID as TenantId;
|
|
@@ -384,6 +433,8 @@ export const seedScreenshotData: SeedFn = async (stack) => {
|
|
|
384
433
|
// custom-fields + folders extension sections on note-edit.
|
|
385
434
|
await seedCustomFieldsAndFolders(stack, devTenant, devAdminId);
|
|
386
435
|
|
|
436
|
+
await seedEventConsumerStates(stack);
|
|
437
|
+
|
|
387
438
|
// personal-access-tokens list for the admin (active tenant = dev).
|
|
388
439
|
await seedApiTokens(stack.db, devTenant);
|
|
389
440
|
|
|
@@ -12,8 +12,8 @@ import type {
|
|
|
12
12
|
export const orderEntity = {
|
|
13
13
|
table: "read_ws_orders",
|
|
14
14
|
fields: {
|
|
15
|
-
label: { type: "text", required: true, sortable: true },
|
|
16
|
-
status: { type: "text", sortable: true },
|
|
15
|
+
label: { type: "text", required: true, sortable: true, allowPlaintext: "is_business_data" },
|
|
16
|
+
status: { type: "text", sortable: true, allowPlaintext: "is_business_data" },
|
|
17
17
|
notes: { type: "text", allowPlaintext: "is_business_data" },
|
|
18
18
|
},
|
|
19
19
|
} as unknown as EntityDefinition;
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
wireCustomFieldsFor,
|
|
25
25
|
} from "@cosmicdrift/kumiko-bundled-features/custom-fields";
|
|
26
26
|
import { buildEntityTable, createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
27
|
-
import { createEntity, defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
27
|
+
import { createEntity, createTextField, defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
28
28
|
import { z } from "zod";
|
|
29
29
|
|
|
30
30
|
// --- Entity ---
|
|
@@ -39,7 +39,12 @@ import { z } from "zod";
|
|
|
39
39
|
export const propertyEntity = createEntity({
|
|
40
40
|
table: "read_sample_cf_properties",
|
|
41
41
|
fields: {
|
|
42
|
-
name: {
|
|
42
|
+
name: createTextField({
|
|
43
|
+
required: true,
|
|
44
|
+
maxLength: 200,
|
|
45
|
+
personal: false,
|
|
46
|
+
reason: "property_name_is_business_data",
|
|
47
|
+
}),
|
|
43
48
|
customFields: customFieldsField(),
|
|
44
49
|
},
|
|
45
50
|
});
|
|
@@ -59,7 +64,12 @@ export const propertyFeature = defineFeature("property-management", (r) => {
|
|
|
59
64
|
name: "property",
|
|
60
65
|
table: "read_sample_cf_properties",
|
|
61
66
|
fields: {
|
|
62
|
-
name: {
|
|
67
|
+
name: createTextField({
|
|
68
|
+
required: true,
|
|
69
|
+
maxLength: 200,
|
|
70
|
+
personal: false,
|
|
71
|
+
reason: "property_name_is_business_data",
|
|
72
|
+
}),
|
|
63
73
|
customFields: { type: "jsonb" },
|
|
64
74
|
},
|
|
65
75
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// - nav → ID/Label/Screen-Card
|
|
7
7
|
// Plus optionalRequires + metric als JSON-Dump-Fallback.
|
|
8
8
|
|
|
9
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
|
+
import { createTextField, defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
12
|
defineFeature("designerDemo", (r) => {
|
|
@@ -15,7 +15,11 @@ defineFeature("designerDemo", (r) => {
|
|
|
15
15
|
r.entity({
|
|
16
16
|
name: "task",
|
|
17
17
|
fields: {
|
|
18
|
-
title: {
|
|
18
|
+
title: createTextField({
|
|
19
|
+
required: true,
|
|
20
|
+
personal: false,
|
|
21
|
+
reason: "demo_task_title_is_not_personal_data",
|
|
22
|
+
}),
|
|
19
23
|
done: { type: "boolean", default: false },
|
|
20
24
|
priority: { type: "select", options: ["low", "medium", "high"], default: "medium" },
|
|
21
25
|
},
|