@cosmicdrift/kumiko-renderer 0.327.0 → 0.328.1
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/dist/app/action-form-shim.d.ts +14 -0
- package/{src/app/action-form-shim.ts → dist/app/action-form-shim.js} +26 -44
- package/dist/app/app-features-context.d.ts +8 -0
- package/dist/app/app-features-context.js +16 -0
- package/dist/app/column-renderers.d.ts +30 -0
- package/dist/app/column-renderers.js +34 -0
- package/dist/app/config-edit-shim.d.ts +11 -0
- package/{src/app/config-edit-shim.ts → dist/app/config-edit-shim.js} +12 -25
- package/dist/app/content-editors.d.ts +38 -0
- package/dist/app/content-editors.js +26 -0
- package/dist/app/content-preview.d.ts +11 -0
- package/dist/app/content-preview.js +30 -0
- package/dist/app/custom-screens.d.ts +11 -0
- package/dist/app/custom-screens.js +20 -0
- package/dist/app/dashboard-body.d.ts +16 -0
- package/dist/app/dashboard-body.js +11 -0
- package/dist/app/extension-form-submit.d.ts +32 -0
- package/dist/app/extension-form-submit.js +73 -0
- package/dist/app/extension-sections.d.ts +72 -0
- package/dist/app/extension-sections.js +34 -0
- package/dist/app/feature-schema.d.ts +4 -0
- package/{src/app/feature-schema.ts → dist/app/feature-schema.js} +12 -22
- package/dist/app/form-schema.d.ts +4 -0
- package/dist/app/form-schema.js +85 -0
- package/dist/app/kumiko-screen.d.ts +43 -0
- package/dist/app/kumiko-screen.js +2206 -0
- package/dist/app/layout-fields.d.ts +3 -0
- package/dist/app/layout-fields.js +20 -0
- package/dist/app/list-facets.d.ts +48 -0
- package/dist/app/list-facets.js +185 -0
- package/dist/app/nav.d.ts +61 -0
- package/dist/app/nav.js +139 -0
- package/dist/app/projection-detail-shim.d.ts +8 -0
- package/dist/app/projection-detail-shim.js +71 -0
- package/dist/app/projection-list-shim.d.ts +13 -0
- package/{src/app/projection-list-shim.ts → dist/app/projection-list-shim.js} +26 -38
- package/dist/app/qn.d.ts +7 -0
- package/{src/app/qn.ts → dist/app/qn.js} +9 -11
- package/dist/app/qualify-screen-id.d.ts +2 -0
- package/{src/app/qualify-screen-id.ts → dist/app/qualify-screen-id.js} +5 -6
- package/dist/app/reference-facet-bridge.d.ts +10 -0
- package/dist/app/reference-facet-bridge.js +22 -0
- package/dist/app/return-to.d.ts +31 -0
- package/dist/app/return-to.js +188 -0
- package/dist/app/row-actions.d.ts +77 -0
- package/dist/app/row-actions.js +416 -0
- package/dist/app/screen-access.d.ts +8 -0
- package/dist/app/screen-access.js +48 -0
- package/dist/app/secret-mint-body.d.ts +10 -0
- package/dist/app/secret-mint-body.js +140 -0
- package/dist/app/secrets-edit-body.d.ts +8 -0
- package/dist/app/secrets-edit-body.js +76 -0
- package/dist/app/use-embedded-screen.d.ts +6 -0
- package/dist/app/use-embedded-screen.js +19 -0
- package/dist/app/variable-chips.d.ts +7 -0
- package/dist/app/variable-chips.js +16 -0
- package/dist/app/write-failed-error.d.ts +6 -0
- package/dist/app/write-failed-error.js +21 -0
- package/dist/components/embedded-list-field.d.ts +10 -0
- package/dist/components/embedded-list-field.js +259 -0
- package/dist/components/grid-cell-for-field.d.ts +25 -0
- package/dist/components/grid-cell-for-field.js +31 -0
- package/dist/components/multi-select-checkboxes.d.ts +14 -0
- package/dist/components/multi-select-checkboxes.js +36 -0
- package/dist/components/reference-create-dialog.d.ts +13 -0
- package/dist/components/reference-create-dialog.js +46 -0
- package/dist/components/related-list-section.d.ts +25 -0
- package/dist/components/related-list-section.js +273 -0
- package/dist/components/render-edit-action-button.d.ts +22 -0
- package/dist/components/render-edit-action-button.js +43 -0
- package/dist/components/render-edit-logic.d.ts +6 -0
- package/dist/components/render-edit-logic.js +63 -0
- package/dist/components/render-edit-types.d.ts +209 -0
- package/dist/components/render-edit-types.js +1 -0
- package/dist/components/render-edit.d.ts +6 -0
- package/dist/components/render-edit.js +1169 -0
- package/dist/components/render-field.d.ts +38 -0
- package/dist/components/render-field.js +544 -0
- package/dist/components/render-list.d.ts +117 -0
- package/dist/components/render-list.js +232 -0
- package/dist/components/write-form-section.d.ts +17 -0
- package/dist/components/write-form-section.js +104 -0
- package/dist/context/dispatcher-context.d.ts +10 -0
- package/{src/context/dispatcher-context.tsx → dist/context/dispatcher-context.js} +16 -29
- package/dist/context/draft-storage-context.d.ts +12 -0
- package/dist/context/draft-storage-context.js +18 -0
- package/dist/context/user-roles-context.d.ts +7 -0
- package/{src/context/user-roles-context.tsx → dist/context/user-roles-context.js} +7 -15
- package/dist/format-when.d.ts +1 -0
- package/{src/format-when.ts → dist/format-when.js} +7 -7
- package/dist/hooks/reference-limits.d.ts +3 -0
- package/{src/hooks/reference-limits.ts → dist/hooks/reference-limits.js} +0 -1
- package/dist/hooks/use-ai-text.d.ts +52 -0
- package/dist/hooks/use-ai-text.js +90 -0
- package/dist/hooks/use-disclosure.d.ts +7 -0
- package/dist/hooks/use-disclosure.js +8 -0
- package/dist/hooks/use-form.d.ts +7 -0
- package/dist/hooks/use-form.js +36 -0
- package/dist/hooks/use-list-url-state.d.ts +43 -0
- package/dist/hooks/use-list-url-state.js +131 -0
- package/dist/hooks/use-mutation.d.ts +9 -0
- package/dist/hooks/use-mutation.js +37 -0
- package/dist/hooks/use-query.d.ts +14 -0
- package/dist/hooks/use-query.js +118 -0
- package/dist/hooks/use-reference-lookup.d.ts +14 -0
- package/dist/hooks/use-reference-lookup.js +63 -0
- package/dist/hooks/use-store.d.ts +3 -0
- package/dist/hooks/use-store.js +38 -0
- package/dist/hooks/use-stream-handler.d.ts +14 -0
- package/dist/hooks/use-stream-handler.js +93 -0
- package/dist/i18n-defaults.d.ts +2 -0
- package/dist/i18n-defaults.js +201 -0
- package/dist/i18n.d.ts +64 -0
- package/dist/i18n.js +166 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +55 -0
- package/dist/inside-drawer.d.ts +2 -0
- package/dist/inside-drawer.js +9 -0
- package/dist/page-header-slot.d.ts +2 -0
- package/dist/page-header-slot.js +9 -0
- package/dist/primitives.d.ts +1351 -0
- package/dist/primitives.js +73 -0
- package/dist/screen-fills-height.d.ts +3 -0
- package/dist/screen-fills-height.js +3 -0
- package/dist/share-links.d.ts +4 -0
- package/dist/share-links.js +11 -0
- package/dist/sort-by-accessor.d.ts +5 -0
- package/dist/sort-by-accessor.js +16 -0
- package/dist/sse/live-events.d.ts +23 -0
- package/dist/sse/live-events.js +28 -0
- package/dist/tokens.d.ts +83 -0
- package/dist/tokens.js +80 -0
- package/package.json +16 -9
- package/src/changes.json +52 -0
- package/src/__tests__/error-i18n-defaults.test.ts +0 -82
- package/src/__tests__/format-when.test.ts +0 -12
- package/src/__tests__/i18n.test.tsx +0 -283
- package/src/__tests__/merge-search-params-into-initial.test.ts +0 -525
- package/src/__tests__/qn.test.ts +0 -83
- package/src/__tests__/share-links.test.ts +0 -26
- package/src/__tests__/sort-by-accessor.test.ts +0 -48
- package/src/__tests__/stringify-nav-params.test.ts +0 -33
- package/src/__tests__/use-list-url-state.test.tsx +0 -250
- package/src/app/__tests__/action-form-field-labels.test.tsx +0 -92
- package/src/app/__tests__/action-form-shim.test.ts +0 -137
- package/src/app/__tests__/build-list-query-payload.test.ts +0 -107
- package/src/app/__tests__/config-edit-shim.test.ts +0 -57
- package/src/app/__tests__/content-editors.test.tsx +0 -128
- package/src/app/__tests__/content-preview.test.tsx +0 -184
- package/src/app/__tests__/entity-edit-create-search-params.test.tsx +0 -236
- package/src/app/__tests__/entity-edit-jsonb-embedded-submit.test.tsx +0 -239
- package/src/app/__tests__/entity-list-create-singleton.test.tsx +0 -128
- package/src/app/__tests__/entity-list-row-action-entity-target.test.tsx +0 -424
- package/src/app/__tests__/entity-list-row-action-icon.test.tsx +0 -248
- package/src/app/__tests__/entity-list-row-action-kumiko-actions-view.test.tsx +0 -162
- package/src/app/__tests__/entity-list-row-action-refetch.test.tsx +0 -401
- package/src/app/__tests__/entity-list-screen-padding.test.tsx +0 -111
- package/src/app/__tests__/feature-schema.test.ts +0 -40
- package/src/app/__tests__/form-schema.test.ts +0 -247
- package/src/app/__tests__/list-daterange-facet.test.ts +0 -165
- package/src/app/__tests__/list-filter-facets.test.tsx +0 -521
- package/src/app/__tests__/nav.test.ts +0 -198
- package/src/app/__tests__/projection-detail-actions.test.tsx +0 -719
- package/src/app/__tests__/projection-detail-reference-field.test.tsx +0 -165
- package/src/app/__tests__/projection-detail-shim.test.ts +0 -188
- package/src/app/__tests__/projection-detail-singleton.test.tsx +0 -191
- package/src/app/__tests__/projection-list-bad-shape.test.tsx +0 -152
- package/src/app/__tests__/projection-list-reference-column.test.tsx +0 -219
- package/src/app/__tests__/projection-list-search-sort.test.tsx +0 -212
- package/src/app/__tests__/qualified-names.test.ts +0 -37
- package/src/app/__tests__/return-to.test.ts +0 -396
- package/src/app/__tests__/row-actions-navigate-tab.test.ts +0 -223
- package/src/app/__tests__/row-default-edit-action.test.tsx +0 -324
- package/src/app/__tests__/screen-access-allows.test.ts +0 -34
- package/src/app/__tests__/secret-mint-body.test.tsx +0 -404
- package/src/app/__tests__/variable-chips.test.tsx +0 -70
- package/src/app/app-features-context.tsx +0 -25
- package/src/app/column-renderers.tsx +0 -68
- package/src/app/content-editors.tsx +0 -85
- package/src/app/content-preview.tsx +0 -67
- package/src/app/custom-screens.tsx +0 -29
- package/src/app/dashboard-body.tsx +0 -33
- package/src/app/extension-form-submit.tsx +0 -123
- package/src/app/extension-sections.tsx +0 -111
- package/src/app/form-schema.ts +0 -91
- package/src/app/kumiko-screen.tsx +0 -3614
- package/src/app/layout-fields.ts +0 -31
- package/src/app/list-facets.ts +0 -259
- package/src/app/nav.tsx +0 -258
- package/src/app/projection-detail-shim.ts +0 -85
- package/src/app/reference-facet-bridge.tsx +0 -58
- package/src/app/return-to.tsx +0 -234
- package/src/app/row-actions.ts +0 -639
- package/src/app/screen-access.ts +0 -63
- package/src/app/secret-mint-body.tsx +0 -259
- package/src/app/secrets-edit-body.tsx +0 -194
- package/src/app/use-embedded-screen.ts +0 -27
- package/src/app/variable-chips.tsx +0 -39
- package/src/app/write-failed-error.ts +0 -27
- package/src/components/__tests__/embedded-list-field.test.tsx +0 -531
- package/src/components/__tests__/multi-select-checkboxes.test.tsx +0 -162
- package/src/components/__tests__/related-list-section-empty-state.test.tsx +0 -143
- package/src/components/__tests__/related-list-section.test.tsx +0 -1669
- package/src/components/__tests__/render-edit-action-button.test.tsx +0 -205
- package/src/components/__tests__/render-edit-hidden-section.test.tsx +0 -128
- package/src/components/__tests__/render-edit-logic.test.ts +0 -314
- package/src/components/__tests__/render-edit-screen-description.test.tsx +0 -152
- package/src/components/__tests__/render-edit-submit-actions.test.tsx +0 -460
- package/src/components/__tests__/render-field-app-locale.test.tsx +0 -142
- package/src/components/__tests__/render-field-enum-option.test.tsx +0 -99
- package/src/components/__tests__/render-field-icon-derivation.test.tsx +0 -119
- package/src/components/__tests__/render-field-json-format.test.tsx +0 -164
- package/src/components/__tests__/render-field-money-embedded-list-consistency.test.tsx +0 -212
- package/src/components/__tests__/render-field-money-roundtrip.test.tsx +0 -217
- package/src/components/__tests__/render-field-number-grouping.test.tsx +0 -76
- package/src/components/__tests__/render-field-number-unit.test.tsx +0 -227
- package/src/components/__tests__/render-field-password-format.test.tsx +0 -101
- package/src/components/__tests__/render-field-select-display.test.tsx +0 -134
- package/src/components/__tests__/render-field-unit-format.test.tsx +0 -107
- package/src/components/__tests__/render-field-unsupported-types.test.tsx +0 -195
- package/src/components/__tests__/render-list-toolbar-icon-only.test.tsx +0 -146
- package/src/components/__tests__/write-form-section.test.tsx +0 -375
- package/src/components/embedded-list-field.tsx +0 -354
- package/src/components/grid-cell-for-field.tsx +0 -60
- package/src/components/multi-select-checkboxes.tsx +0 -93
- package/src/components/reference-create-dialog.tsx +0 -91
- package/src/components/related-list-section.tsx +0 -467
- package/src/components/render-edit-action-button.tsx +0 -106
- package/src/components/render-edit-logic.ts +0 -85
- package/src/components/render-edit-types.ts +0 -216
- package/src/components/render-edit.tsx +0 -1700
- package/src/components/render-field.tsx +0 -942
- package/src/components/render-list.tsx +0 -561
- package/src/components/write-form-section.tsx +0 -199
- package/src/context/draft-storage-context.tsx +0 -39
- package/src/hooks/__tests__/use-ai-text.test.tsx +0 -177
- package/src/hooks/__tests__/use-disclosure.test.tsx +0 -25
- package/src/hooks/__tests__/use-form.test.tsx +0 -65
- package/src/hooks/__tests__/use-mutation.test.tsx +0 -77
- package/src/hooks/__tests__/use-stream-handler.test.tsx +0 -107
- package/src/hooks/use-ai-text.ts +0 -172
- package/src/hooks/use-disclosure.ts +0 -20
- package/src/hooks/use-form.ts +0 -78
- package/src/hooks/use-list-url-state.ts +0 -171
- package/src/hooks/use-mutation.ts +0 -61
- package/src/hooks/use-query.ts +0 -132
- package/src/hooks/use-reference-lookup.ts +0 -76
- package/src/hooks/use-store.ts +0 -48
- package/src/hooks/use-stream-handler.ts +0 -134
- package/src/i18n-defaults.ts +0 -220
- package/src/i18n.tsx +0 -286
- package/src/index.ts +0 -272
- package/src/primitives.tsx +0 -1446
- package/src/share-links.ts +0 -12
- package/src/sort-by-accessor.ts +0 -20
- package/src/sse/live-events.tsx +0 -56
- package/src/tokens.tsx +0 -170
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
// fw#2228: RowActionNavigate can now name an ObjectTarget (`entity`) instead
|
|
2
|
-
// of a ScreenTarget (`screen`). This renders the real entityList pipeline
|
|
3
|
-
// (KumikoScreen → EntityListBody) and asserts a click on the entity-target
|
|
4
|
-
// row action calls nav.navigate with `{ entity, id }` — resolution to an
|
|
5
|
-
// actual screen is the NavApi impl's job (renderer-web's resolveTarget), not
|
|
6
|
-
// this platform-neutral package's. Mirrors
|
|
7
|
-
// entity-list-row-action-kumiko-actions-view.test.tsx's harness.
|
|
8
|
-
|
|
9
|
-
import { describe, expect, test } from "bun:test";
|
|
10
|
-
import type {
|
|
11
|
-
EntityDefinition,
|
|
12
|
-
EntityListScreenDefinition,
|
|
13
|
-
ProjectionDetailScreenDefinition,
|
|
14
|
-
ProjectionListScreenDefinition,
|
|
15
|
-
RowActionNavigate,
|
|
16
|
-
} from "@cosmicdrift/kumiko-framework/ui-types";
|
|
17
|
-
import type { Dispatcher } from "@cosmicdrift/kumiko-headless";
|
|
18
|
-
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
19
|
-
import type { ComponentType, ReactNode } from "react";
|
|
20
|
-
import { DispatcherProvider } from "../../context/dispatcher-context";
|
|
21
|
-
import { createStaticLocaleResolver, LocaleProvider } from "../../i18n";
|
|
22
|
-
import { kumikoDefaultTranslations } from "../../i18n-defaults";
|
|
23
|
-
import {
|
|
24
|
-
type ButtonProps,
|
|
25
|
-
type CardProps,
|
|
26
|
-
type CorePrimitives,
|
|
27
|
-
type DataTableProps,
|
|
28
|
-
type DataTableRowAction,
|
|
29
|
-
type FormProps,
|
|
30
|
-
PrimitivesProvider,
|
|
31
|
-
} from "../../primitives";
|
|
32
|
-
import type { FeatureSchema } from "../feature-schema";
|
|
33
|
-
import { KumikoScreen } from "../kumiko-screen";
|
|
34
|
-
import type { NavTarget } from "../nav";
|
|
35
|
-
import { NavProvider } from "../nav";
|
|
36
|
-
|
|
37
|
-
function stubDispatcher(): Dispatcher {
|
|
38
|
-
return {
|
|
39
|
-
write: (async () => ({ isSuccess: true, data: {} })) as unknown as Dispatcher["write"],
|
|
40
|
-
query: (async () => ({
|
|
41
|
-
isSuccess: true,
|
|
42
|
-
data: {
|
|
43
|
-
rows: [{ id: "invoice-42", customerId: "cust-7", status: "open" }],
|
|
44
|
-
nextCursor: null,
|
|
45
|
-
total: 1,
|
|
46
|
-
},
|
|
47
|
-
})) as unknown as Dispatcher["query"],
|
|
48
|
-
batch: (async () => ({ isSuccess: true, results: [] })) as unknown as Dispatcher["batch"],
|
|
49
|
-
statusStore: {
|
|
50
|
-
getState: () => "online",
|
|
51
|
-
subscribe: () => () => {},
|
|
52
|
-
} as unknown as Dispatcher["statusStore"],
|
|
53
|
-
async *stream() {},
|
|
54
|
-
pendingWrites: () => [],
|
|
55
|
-
pendingFiles: () => [],
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let capturedRowActions: readonly DataTableRowAction[] | undefined;
|
|
60
|
-
const captureDataTable: ComponentType<DataTableProps> = (props) => {
|
|
61
|
-
capturedRowActions = props.rowActions;
|
|
62
|
-
return null;
|
|
63
|
-
};
|
|
64
|
-
const noop = (): ReactNode => null;
|
|
65
|
-
const passChildren = ({ children }: { readonly children?: ReactNode }): ReactNode => children;
|
|
66
|
-
// Card's title/subtitle/headerActions arrive as `slots` instead of raw
|
|
67
|
-
// JSX children.
|
|
68
|
-
const cardWithSlots: ComponentType<CardProps> = ({ slots, children }) => (
|
|
69
|
-
<>
|
|
70
|
-
{slots?.title}
|
|
71
|
-
{slots?.subtitle}
|
|
72
|
-
{slots?.headerActions}
|
|
73
|
-
{children}
|
|
74
|
-
</>
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
const testPrimitives: CorePrimitives = {
|
|
78
|
-
Button: noop,
|
|
79
|
-
Banner: passChildren,
|
|
80
|
-
Field: passChildren,
|
|
81
|
-
Input: noop,
|
|
82
|
-
DataTable: captureDataTable,
|
|
83
|
-
Form: passChildren,
|
|
84
|
-
Section: passChildren,
|
|
85
|
-
Card: cardWithSlots,
|
|
86
|
-
Grid: passChildren,
|
|
87
|
-
GridCell: passChildren,
|
|
88
|
-
Text: passChildren,
|
|
89
|
-
Heading: noop,
|
|
90
|
-
Dialog: noop,
|
|
91
|
-
Modal: noop,
|
|
92
|
-
Lightbox: noop,
|
|
93
|
-
ConfigSourceBadge: noop,
|
|
94
|
-
ConfigCascadeView: noop,
|
|
95
|
-
Link: noop,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
function buildSchema(rowAction: EntityListScreenDefinition["rowActions"]): FeatureSchema {
|
|
99
|
-
const entity: EntityDefinition = {
|
|
100
|
-
fields: {
|
|
101
|
-
customerId: {
|
|
102
|
-
type: "text",
|
|
103
|
-
maxLength: 50,
|
|
104
|
-
required: false,
|
|
105
|
-
searchable: false,
|
|
106
|
-
sortable: false,
|
|
107
|
-
},
|
|
108
|
-
status: { type: "text", maxLength: 50, required: false, searchable: false, sortable: false },
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
const listScreen: EntityListScreenDefinition = {
|
|
112
|
-
id: "invoice-list",
|
|
113
|
-
type: "entityList",
|
|
114
|
-
entity: "invoice",
|
|
115
|
-
columns: ["status"],
|
|
116
|
-
rowActions: rowAction,
|
|
117
|
-
};
|
|
118
|
-
return {
|
|
119
|
-
featureName: "billing",
|
|
120
|
-
entities: { invoice: entity },
|
|
121
|
-
screens: [listScreen],
|
|
122
|
-
} as FeatureSchema;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function renderListScreen(schema: FeatureSchema, navigateSpy: (target: NavTarget) => void): void {
|
|
126
|
-
render(
|
|
127
|
-
<LocaleProvider
|
|
128
|
-
resolver={createStaticLocaleResolver({ locale: "en" })}
|
|
129
|
-
fallbackBundles={[kumikoDefaultTranslations]}
|
|
130
|
-
>
|
|
131
|
-
<DispatcherProvider dispatcher={stubDispatcher()}>
|
|
132
|
-
<NavProvider
|
|
133
|
-
value={{
|
|
134
|
-
route: { screenId: "billing:invoice-list" },
|
|
135
|
-
navigate: navigateSpy,
|
|
136
|
-
replace: () => {},
|
|
137
|
-
hrefFor: () => "",
|
|
138
|
-
searchParams: {},
|
|
139
|
-
setSearchParams: () => {},
|
|
140
|
-
}}
|
|
141
|
-
>
|
|
142
|
-
<PrimitivesProvider value={testPrimitives}>
|
|
143
|
-
<KumikoScreen schema={schema} qn="billing:screen:invoice-list" />
|
|
144
|
-
</PrimitivesProvider>
|
|
145
|
-
</NavProvider>
|
|
146
|
-
</DispatcherProvider>
|
|
147
|
-
</LocaleProvider>,
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function requireAction(id: string): DataTableRowAction {
|
|
152
|
-
const action = capturedRowActions?.find((a) => a.id === id);
|
|
153
|
-
if (!action) throw new Error(`expected the '${id}' row action to be captured`);
|
|
154
|
-
return action;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
describe("entityList navigate row-action with an entity-target (fw#2228)", () => {
|
|
158
|
-
test("clicking the row action calls nav.navigate with { entity, id }, not a screenId", async () => {
|
|
159
|
-
capturedRowActions = undefined;
|
|
160
|
-
const navigateCalls: NavTarget[] = [];
|
|
161
|
-
|
|
162
|
-
renderListScreen(
|
|
163
|
-
buildSchema([
|
|
164
|
-
{ kind: "navigate", id: "view", label: "kumiko.actions.view", entity: "invoice" },
|
|
165
|
-
]),
|
|
166
|
-
(target) => navigateCalls.push(target),
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
await waitFor(() => {
|
|
170
|
-
expect(capturedRowActions).toBeDefined();
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
await requireAction("view").onTrigger({
|
|
174
|
-
id: "invoice-42",
|
|
175
|
-
values: { id: "invoice-42", customerId: "cust-7", status: "open" },
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
expect(navigateCalls).toHaveLength(1);
|
|
179
|
-
expect(navigateCalls[0]).toEqual({ entity: "invoice", id: "invoice-42" });
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
test("an explicit entityId field-name still overrides the row['id'] default", async () => {
|
|
183
|
-
capturedRowActions = undefined;
|
|
184
|
-
const navigateCalls: NavTarget[] = [];
|
|
185
|
-
|
|
186
|
-
renderListScreen(
|
|
187
|
-
buildSchema([
|
|
188
|
-
{
|
|
189
|
-
kind: "navigate",
|
|
190
|
-
id: "view-customer",
|
|
191
|
-
label: "kumiko.actions.view",
|
|
192
|
-
entity: "customer",
|
|
193
|
-
entityId: "customerId",
|
|
194
|
-
},
|
|
195
|
-
]),
|
|
196
|
-
(target) => navigateCalls.push(target),
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
await waitFor(() => {
|
|
200
|
-
expect(capturedRowActions).toBeDefined();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
await requireAction("view-customer").onTrigger({
|
|
204
|
-
id: "invoice-42",
|
|
205
|
-
values: { id: "invoice-42", customerId: "cust-7" },
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
expect(navigateCalls).toEqual([{ entity: "customer", id: "cust-7" }]);
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// projectionList.runNavigate has NO row["id"] fallback (unlike EntityListBody
|
|
213
|
-
// above) — a projectionList row comes from an arbitrary query without a
|
|
214
|
-
// guaranteed "id" field, so an entity-target there requires an explicit
|
|
215
|
-
// entityId. This proves that path resolves { entity, id } correctly and
|
|
216
|
-
// still forwards `params` via setSearchParams.
|
|
217
|
-
function buildProjectionListSchema(rowAction: RowActionNavigate): FeatureSchema {
|
|
218
|
-
const listScreen: ProjectionListScreenDefinition = {
|
|
219
|
-
id: "invoice-projection-list",
|
|
220
|
-
type: "projectionList",
|
|
221
|
-
query: "billing:query:invoice:list",
|
|
222
|
-
columns: [{ field: "status", label: "Status" }],
|
|
223
|
-
rowActions: [rowAction],
|
|
224
|
-
};
|
|
225
|
-
return {
|
|
226
|
-
featureName: "billing",
|
|
227
|
-
entities: {},
|
|
228
|
-
screens: [listScreen],
|
|
229
|
-
} as FeatureSchema;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function renderProjectionListScreen(
|
|
233
|
-
schema: FeatureSchema,
|
|
234
|
-
navigateSpy: (target: NavTarget) => void,
|
|
235
|
-
setSearchParamsSpy: (params: Record<string, string | null>) => void,
|
|
236
|
-
): void {
|
|
237
|
-
render(
|
|
238
|
-
<LocaleProvider
|
|
239
|
-
resolver={createStaticLocaleResolver({ locale: "en" })}
|
|
240
|
-
fallbackBundles={[kumikoDefaultTranslations]}
|
|
241
|
-
>
|
|
242
|
-
<DispatcherProvider dispatcher={stubDispatcher()}>
|
|
243
|
-
<NavProvider
|
|
244
|
-
value={{
|
|
245
|
-
route: { screenId: "billing:invoice-projection-list" },
|
|
246
|
-
navigate: navigateSpy,
|
|
247
|
-
replace: () => {},
|
|
248
|
-
hrefFor: () => "",
|
|
249
|
-
searchParams: {},
|
|
250
|
-
setSearchParams: setSearchParamsSpy,
|
|
251
|
-
}}
|
|
252
|
-
>
|
|
253
|
-
<PrimitivesProvider value={testPrimitives}>
|
|
254
|
-
<KumikoScreen schema={schema} qn="billing:screen:invoice-projection-list" />
|
|
255
|
-
</PrimitivesProvider>
|
|
256
|
-
</NavProvider>
|
|
257
|
-
</DispatcherProvider>
|
|
258
|
-
</LocaleProvider>,
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
describe("projectionList navigate row-action with an entity-target (fw#2228)", () => {
|
|
263
|
-
test("entity-target with entityId calls nav.navigate with { entity, id } and forwards params via setSearchParams", async () => {
|
|
264
|
-
capturedRowActions = undefined;
|
|
265
|
-
const navigateCalls: NavTarget[] = [];
|
|
266
|
-
const searchParamsCalls: Record<string, string | null>[] = [];
|
|
267
|
-
|
|
268
|
-
renderProjectionListScreen(
|
|
269
|
-
buildProjectionListSchema({
|
|
270
|
-
kind: "navigate",
|
|
271
|
-
id: "view",
|
|
272
|
-
label: "kumiko.actions.view",
|
|
273
|
-
entity: "invoice",
|
|
274
|
-
entityId: "invoiceId",
|
|
275
|
-
params: { pick: ["status"] },
|
|
276
|
-
}),
|
|
277
|
-
(target) => navigateCalls.push(target),
|
|
278
|
-
(params) => searchParamsCalls.push(params),
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
await waitFor(() => {
|
|
282
|
-
expect(capturedRowActions).toBeDefined();
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
await requireAction("view").onTrigger({
|
|
286
|
-
id: "proj-1",
|
|
287
|
-
values: { id: "proj-1", invoiceId: "invoice-42", status: "open" },
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
expect(navigateCalls).toEqual([{ entity: "invoice", id: "invoice-42" }]);
|
|
291
|
-
expect(searchParamsCalls).toEqual([{ status: "open" }]);
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// projectionDetail's header actions run through the same entity-target
|
|
296
|
-
// resolution (ProjectionDetailBody, no record["id"] fallback either) as a
|
|
297
|
-
// distinct code path from both entityList and projectionList above — this
|
|
298
|
-
// renders the real KumikoScreen → ProjectionDetailBody → RenderEdit pipeline
|
|
299
|
-
// and clicks the real action button.
|
|
300
|
-
const TestButton: ComponentType<ButtonProps> = ({ children, onClick, testId }) => (
|
|
301
|
-
<button type="button" data-testid={testId} onClick={() => void onClick?.()}>
|
|
302
|
-
{children}
|
|
303
|
-
</button>
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
// headerRegion carries projectionDetail's header actions since fw#2713 — a
|
|
307
|
-
// stub that only forwards children/actions/secondaryActions drops them
|
|
308
|
-
// silently, as this test's own action button did until it grew this slot.
|
|
309
|
-
const FormWithActions: ComponentType<FormProps> = ({
|
|
310
|
-
children,
|
|
311
|
-
actions,
|
|
312
|
-
secondaryActions,
|
|
313
|
-
headerRegion,
|
|
314
|
-
}) => (
|
|
315
|
-
<>
|
|
316
|
-
{headerRegion !== undefined && <div data-testid="form-header">{headerRegion}</div>}
|
|
317
|
-
<div data-testid="form-body">{children}</div>
|
|
318
|
-
<div data-testid="form-actions">
|
|
319
|
-
{secondaryActions}
|
|
320
|
-
{actions}
|
|
321
|
-
</div>
|
|
322
|
-
</>
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
const detailTestPrimitives: CorePrimitives = {
|
|
326
|
-
...testPrimitives,
|
|
327
|
-
Button: TestButton,
|
|
328
|
-
Form: FormWithActions,
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
function detailStubDispatcher(record: Readonly<Record<string, unknown>>): Dispatcher {
|
|
332
|
-
return {
|
|
333
|
-
write: (async () => ({ isSuccess: true, data: {} })) as unknown as Dispatcher["write"],
|
|
334
|
-
query: (async () => ({ isSuccess: true, data: record })) as unknown as Dispatcher["query"],
|
|
335
|
-
batch: (async () => ({ isSuccess: true, results: [] })) as unknown as Dispatcher["batch"],
|
|
336
|
-
statusStore: {
|
|
337
|
-
getState: () => "online",
|
|
338
|
-
subscribe: () => () => {},
|
|
339
|
-
} as unknown as Dispatcher["statusStore"],
|
|
340
|
-
async *stream() {},
|
|
341
|
-
pendingWrites: () => [],
|
|
342
|
-
pendingFiles: () => [],
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
function buildProjectionDetailSchema(action: RowActionNavigate): FeatureSchema {
|
|
347
|
-
const detailScreen: ProjectionDetailScreenDefinition = {
|
|
348
|
-
id: "invoice-detail",
|
|
349
|
-
type: "projectionDetail",
|
|
350
|
-
query: "billing:query:invoice:detail",
|
|
351
|
-
layout: { sections: [{ title: "s", fields: ["status"] }] },
|
|
352
|
-
actions: [action],
|
|
353
|
-
};
|
|
354
|
-
return {
|
|
355
|
-
featureName: "billing",
|
|
356
|
-
entities: {},
|
|
357
|
-
screens: [detailScreen],
|
|
358
|
-
} as FeatureSchema;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
function renderProjectionDetailScreen(
|
|
362
|
-
schema: FeatureSchema,
|
|
363
|
-
record: Readonly<Record<string, unknown>>,
|
|
364
|
-
navigateSpy: (target: NavTarget) => void,
|
|
365
|
-
setSearchParamsSpy: (params: Record<string, string | null>) => void,
|
|
366
|
-
): void {
|
|
367
|
-
render(
|
|
368
|
-
<LocaleProvider
|
|
369
|
-
resolver={createStaticLocaleResolver({ locale: "en" })}
|
|
370
|
-
fallbackBundles={[kumikoDefaultTranslations]}
|
|
371
|
-
>
|
|
372
|
-
<DispatcherProvider dispatcher={detailStubDispatcher(record)}>
|
|
373
|
-
<NavProvider
|
|
374
|
-
value={{
|
|
375
|
-
route: { screenId: "billing:invoice-detail" },
|
|
376
|
-
navigate: navigateSpy,
|
|
377
|
-
replace: () => {},
|
|
378
|
-
hrefFor: () => "",
|
|
379
|
-
searchParams: {},
|
|
380
|
-
setSearchParams: setSearchParamsSpy,
|
|
381
|
-
}}
|
|
382
|
-
>
|
|
383
|
-
<PrimitivesProvider value={detailTestPrimitives}>
|
|
384
|
-
<KumikoScreen
|
|
385
|
-
schema={schema}
|
|
386
|
-
qn="billing:screen:invoice-detail"
|
|
387
|
-
entityId={String(record["id"])}
|
|
388
|
-
/>
|
|
389
|
-
</PrimitivesProvider>
|
|
390
|
-
</NavProvider>
|
|
391
|
-
</DispatcherProvider>
|
|
392
|
-
</LocaleProvider>,
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
describe("projectionDetail navigate action with an entity-target (fw#2228)", () => {
|
|
397
|
-
test("entity-target with entityId calls nav.navigate with { entity, id } and forwards params via setSearchParams", async () => {
|
|
398
|
-
const navigateCalls: NavTarget[] = [];
|
|
399
|
-
const searchParamsCalls: Record<string, string | null>[] = [];
|
|
400
|
-
|
|
401
|
-
renderProjectionDetailScreen(
|
|
402
|
-
buildProjectionDetailSchema({
|
|
403
|
-
kind: "navigate",
|
|
404
|
-
id: "view-customer",
|
|
405
|
-
label: "kumiko.actions.view",
|
|
406
|
-
entity: "customer",
|
|
407
|
-
entityId: "customerId",
|
|
408
|
-
params: { pick: ["status"] },
|
|
409
|
-
}),
|
|
410
|
-
{ id: "invoice-42", customerId: "cust-7", status: "open" },
|
|
411
|
-
(target) => navigateCalls.push(target),
|
|
412
|
-
(params) => searchParamsCalls.push(params),
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
await waitFor(() => expect(screen.queryByText("Loading…")).toBeNull());
|
|
416
|
-
|
|
417
|
-
await act(async () => {
|
|
418
|
-
fireEvent.click(screen.getByTestId("render-edit-action-view-customer"));
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
expect(navigateCalls).toEqual([{ entity: "customer", id: "cust-7" }]);
|
|
422
|
-
expect(searchParamsCalls).toEqual([{ status: "open" }]);
|
|
423
|
-
});
|
|
424
|
-
});
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
// fw-ui-defaults: RowAction had no icon field at all, so every framework-
|
|
2
|
-
// generated action button rendered as a same-looking text button. This
|
|
3
|
-
// renders the real entityList pipeline (KumikoScreen → EntityListBody) and
|
|
4
|
-
// asserts on the resolved `icon` KumikoScreen attaches to each
|
|
5
|
-
// DataTableRowAction — the id-derived default (ACTION_ICON_BY_ID in
|
|
6
|
-
// kumiko-screen.tsx) for an action with no declared icon, the declared icon
|
|
7
|
-
// overriding that default for one that has it, and the full id / last
|
|
8
|
-
// segment / first segment fallback order for compound ids (fw#2749).
|
|
9
|
-
|
|
10
|
-
import { describe, expect, test } from "bun:test";
|
|
11
|
-
import type {
|
|
12
|
-
EntityDefinition,
|
|
13
|
-
EntityListScreenDefinition,
|
|
14
|
-
} from "@cosmicdrift/kumiko-framework/ui-types";
|
|
15
|
-
import type { Dispatcher } from "@cosmicdrift/kumiko-headless";
|
|
16
|
-
import { render, waitFor } from "@testing-library/react";
|
|
17
|
-
import type { ComponentType, ReactNode } from "react";
|
|
18
|
-
import { DispatcherProvider } from "../../context/dispatcher-context";
|
|
19
|
-
import { createStaticLocaleResolver, LocaleProvider } from "../../i18n";
|
|
20
|
-
import { kumikoDefaultTranslations } from "../../i18n-defaults";
|
|
21
|
-
import {
|
|
22
|
-
type CorePrimitives,
|
|
23
|
-
type DataTableProps,
|
|
24
|
-
type DataTableRowAction,
|
|
25
|
-
PrimitivesProvider,
|
|
26
|
-
} from "../../primitives";
|
|
27
|
-
import type { FeatureSchema } from "../feature-schema";
|
|
28
|
-
import { KumikoScreen } from "../kumiko-screen";
|
|
29
|
-
import { NavProvider } from "../nav";
|
|
30
|
-
|
|
31
|
-
function stubDispatcher(): Dispatcher {
|
|
32
|
-
return {
|
|
33
|
-
write: (async () => ({ isSuccess: true, data: {} })) as unknown as Dispatcher["write"],
|
|
34
|
-
query: (async () => ({
|
|
35
|
-
isSuccess: true,
|
|
36
|
-
data: { rows: [{ id: "row-1" }], nextCursor: null, total: 1 },
|
|
37
|
-
})) as unknown as Dispatcher["query"],
|
|
38
|
-
batch: (async () => ({ isSuccess: true, results: [] })) as unknown as Dispatcher["batch"],
|
|
39
|
-
statusStore: {
|
|
40
|
-
getState: () => "online",
|
|
41
|
-
subscribe: () => () => {},
|
|
42
|
-
} as unknown as Dispatcher["statusStore"],
|
|
43
|
-
async *stream() {},
|
|
44
|
-
pendingWrites: () => [],
|
|
45
|
-
pendingFiles: () => [],
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let capturedRowActions: readonly DataTableRowAction[] | undefined;
|
|
50
|
-
const captureDataTable: ComponentType<DataTableProps> = (props) => {
|
|
51
|
-
capturedRowActions = props.rowActions;
|
|
52
|
-
return null;
|
|
53
|
-
};
|
|
54
|
-
const noop = (): ReactNode => null;
|
|
55
|
-
const passChildren = ({ children }: { readonly children?: ReactNode }): ReactNode => children;
|
|
56
|
-
|
|
57
|
-
const testPrimitives: CorePrimitives = {
|
|
58
|
-
Button: noop,
|
|
59
|
-
Banner: passChildren,
|
|
60
|
-
Field: passChildren,
|
|
61
|
-
Input: noop,
|
|
62
|
-
DataTable: captureDataTable,
|
|
63
|
-
Form: passChildren,
|
|
64
|
-
Section: passChildren,
|
|
65
|
-
Card: passChildren,
|
|
66
|
-
Grid: passChildren,
|
|
67
|
-
GridCell: passChildren,
|
|
68
|
-
Text: passChildren,
|
|
69
|
-
Heading: noop,
|
|
70
|
-
Dialog: noop,
|
|
71
|
-
Modal: noop,
|
|
72
|
-
Lightbox: noop,
|
|
73
|
-
ConfigSourceBadge: noop,
|
|
74
|
-
ConfigCascadeView: noop,
|
|
75
|
-
Link: noop,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
function buildSchema(): FeatureSchema {
|
|
79
|
-
const entity: EntityDefinition = {
|
|
80
|
-
fields: {
|
|
81
|
-
name: { type: "text", maxLength: 50, required: false, searchable: false, sortable: false },
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
const listScreen: EntityListScreenDefinition = {
|
|
85
|
-
id: "widget-list",
|
|
86
|
-
type: "entityList",
|
|
87
|
-
entity: "widget",
|
|
88
|
-
columns: ["name"],
|
|
89
|
-
rowActions: [
|
|
90
|
-
// No declared icon — must fall back to ACTION_ICON_BY_ID["delete"].
|
|
91
|
-
{
|
|
92
|
-
id: "delete",
|
|
93
|
-
label: "Delete",
|
|
94
|
-
handler: "icon-fixture:write:widget:delete",
|
|
95
|
-
},
|
|
96
|
-
// Declared icon on an id that DOES have an id-derived default
|
|
97
|
-
// ("edit" -> pencil) — the declared icon must win.
|
|
98
|
-
{
|
|
99
|
-
kind: "navigate",
|
|
100
|
-
id: "edit",
|
|
101
|
-
label: "Edit",
|
|
102
|
-
screen: "widget-edit",
|
|
103
|
-
icon: "archive",
|
|
104
|
-
},
|
|
105
|
-
// Full id and last segment ("item") have no entry — falls through to
|
|
106
|
-
// the first segment ("add" -> plus).
|
|
107
|
-
{
|
|
108
|
-
id: "add-item",
|
|
109
|
-
label: "Add Item",
|
|
110
|
-
handler: "icon-fixture:write:widget:add-item",
|
|
111
|
-
},
|
|
112
|
-
// Same fallback, different verb ("open" -> eye).
|
|
113
|
-
{
|
|
114
|
-
kind: "navigate",
|
|
115
|
-
id: "open-lease",
|
|
116
|
-
label: "Open Lease",
|
|
117
|
-
screen: "widget-edit",
|
|
118
|
-
},
|
|
119
|
-
// Neither the full id nor either segment ("order", "ship") has an
|
|
120
|
-
// entry — the new stage must not invent an icon.
|
|
121
|
-
{
|
|
122
|
-
kind: "navigate",
|
|
123
|
-
id: "order-ship",
|
|
124
|
-
label: "Order Ship",
|
|
125
|
-
screen: "widget-edit",
|
|
126
|
-
},
|
|
127
|
-
// Last segment ("copy") and first segment ("send") both have entries —
|
|
128
|
-
// the last segment must keep priority over the new first-segment stage.
|
|
129
|
-
{
|
|
130
|
-
kind: "navigate",
|
|
131
|
-
id: "send-copy",
|
|
132
|
-
label: "Send Copy",
|
|
133
|
-
screen: "widget-edit",
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
};
|
|
137
|
-
return {
|
|
138
|
-
featureName: "icon-fixture",
|
|
139
|
-
entities: { widget: entity },
|
|
140
|
-
screens: [listScreen],
|
|
141
|
-
} as FeatureSchema;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function renderListScreen(): void {
|
|
145
|
-
render(
|
|
146
|
-
<LocaleProvider
|
|
147
|
-
resolver={createStaticLocaleResolver({ locale: "en" })}
|
|
148
|
-
fallbackBundles={[kumikoDefaultTranslations]}
|
|
149
|
-
>
|
|
150
|
-
<DispatcherProvider dispatcher={stubDispatcher()}>
|
|
151
|
-
<NavProvider
|
|
152
|
-
value={{
|
|
153
|
-
route: { screenId: "icon-fixture:screen:widget-list" },
|
|
154
|
-
navigate: () => {},
|
|
155
|
-
replace: () => {},
|
|
156
|
-
hrefFor: () => "",
|
|
157
|
-
searchParams: {},
|
|
158
|
-
setSearchParams: () => {},
|
|
159
|
-
}}
|
|
160
|
-
>
|
|
161
|
-
<PrimitivesProvider value={testPrimitives}>
|
|
162
|
-
<KumikoScreen schema={buildSchema()} qn="icon-fixture:screen:widget-list" />
|
|
163
|
-
</PrimitivesProvider>
|
|
164
|
-
</NavProvider>
|
|
165
|
-
</DispatcherProvider>
|
|
166
|
-
</LocaleProvider>,
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function requireAction(id: string): DataTableRowAction {
|
|
171
|
-
const action = capturedRowActions?.find((a) => a.id === id);
|
|
172
|
-
if (!action) throw new Error(`expected the '${id}' row action to be captured`);
|
|
173
|
-
return action;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
describe("entityList rowActions resolve an icon (fw-ui-defaults)", () => {
|
|
177
|
-
test("an action with no declared icon derives it from its id ('delete' -> trash)", async () => {
|
|
178
|
-
capturedRowActions = undefined;
|
|
179
|
-
|
|
180
|
-
renderListScreen();
|
|
181
|
-
|
|
182
|
-
await waitFor(() => {
|
|
183
|
-
expect(capturedRowActions).toBeDefined();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
expect(requireAction("delete").icon).toBe("trash");
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
test("a declared icon overrides the id-derived default ('edit' would derive pencil)", async () => {
|
|
190
|
-
capturedRowActions = undefined;
|
|
191
|
-
|
|
192
|
-
renderListScreen();
|
|
193
|
-
|
|
194
|
-
await waitFor(() => {
|
|
195
|
-
expect(capturedRowActions).toBeDefined();
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
expect(requireAction("edit").icon).toBe("archive");
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test("an id whose full form and last segment miss falls back to its first segment ('add-item' -> plus)", async () => {
|
|
202
|
-
capturedRowActions = undefined;
|
|
203
|
-
|
|
204
|
-
renderListScreen();
|
|
205
|
-
|
|
206
|
-
await waitFor(() => {
|
|
207
|
-
expect(capturedRowActions).toBeDefined();
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
expect(requireAction("add-item").icon).toBe("plus");
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
test("the first-segment fallback also applies to 'open-lease' -> eye", async () => {
|
|
214
|
-
capturedRowActions = undefined;
|
|
215
|
-
|
|
216
|
-
renderListScreen();
|
|
217
|
-
|
|
218
|
-
await waitFor(() => {
|
|
219
|
-
expect(capturedRowActions).toBeDefined();
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
expect(requireAction("open-lease").icon).toBe("eye");
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
test("an id with no matching segment stays without an icon ('order-ship')", async () => {
|
|
226
|
-
capturedRowActions = undefined;
|
|
227
|
-
|
|
228
|
-
renderListScreen();
|
|
229
|
-
|
|
230
|
-
await waitFor(() => {
|
|
231
|
-
expect(capturedRowActions).toBeDefined();
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
expect(requireAction("order-ship").icon).toBeUndefined();
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
test("the last segment keeps priority over the first ('send-copy' -> copy, not send)", async () => {
|
|
238
|
-
capturedRowActions = undefined;
|
|
239
|
-
|
|
240
|
-
renderListScreen();
|
|
241
|
-
|
|
242
|
-
await waitFor(() => {
|
|
243
|
-
expect(capturedRowActions).toBeDefined();
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
expect(requireAction("send-copy").icon).toBe("copy");
|
|
247
|
-
});
|
|
248
|
-
});
|