@asteby/metacore-runtime-react 23.7.0 → 23.8.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/CHANGELOG.md +21 -0
- package/dist/action-modal-dispatcher.js +14 -6
- package/dist/custom-stages.d.ts +13 -1
- package/dist/custom-stages.d.ts.map +1 -1
- package/dist/custom-stages.js +3 -3
- package/dist/dynamic-kanban.d.ts.map +1 -1
- package/dist/dynamic-kanban.js +259 -43
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/model-action-toolbar.d.ts.map +1 -1
- package/dist/model-action-toolbar.js +3 -1
- package/dist/stage-layout.d.ts +23 -0
- package/dist/stage-layout.d.ts.map +1 -0
- package/dist/stage-layout.js +70 -0
- package/package.json +1 -1
- package/src/__tests__/dynamic-kanban-lane-reorder.test.tsx +228 -0
- package/src/__tests__/model-action-toolbar-i18n.test.tsx +101 -0
- package/src/__tests__/stage-layout.test.tsx +210 -0
- package/src/action-modal-dispatcher.tsx +16 -8
- package/src/custom-stages.tsx +30 -3
- package/src/dynamic-kanban.tsx +474 -144
- package/src/index.ts +5 -0
- package/src/model-action-toolbar.tsx +9 -1
- package/src/stage-layout.ts +93 -0
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,SAAS,CAAA;AACvB,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EACH,aAAa,EACb,KAAK,kBAAkB,EACvB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAClB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACH,mBAAmB,EACnB,sBAAsB,EACtB,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,GACnC,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACH,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,SAAS,EACT,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,GAC7B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACH,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,oBAAoB,GAC5B,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACH,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,gBAAgB,GACxB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACH,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,GAC/B,MAAM,uBAAuB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EACH,qBAAqB,EACrB,KAAK,gBAAgB,GACxB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACH,kBAAkB,EAClB,eAAe,EACf,KAAK,uBAAuB,EAC5B,KAAK,eAAe,GACvB,MAAM,wBAAwB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,OAAO,EACH,mBAAmB,EACnB,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,WAAW,EAChB,KAAK,wBAAwB,GAChC,MAAM,wBAAwB,CAAA;AAC/B,cAAc,QAAQ,CAAA;AACtB,cAAc,mBAAmB,CAAA;AACjC,OAAO,EACH,mBAAmB,EACnB,MAAM,EACN,oBAAoB,EACpB,OAAO,EACP,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,KAAK,EACV,KAAK,wBAAwB,GAChC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,oBAAoB,EACpB,KAAK,0BAA0B,EAC/B,KAAK,iBAAiB,GACzB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,EACb,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,OAAO,EACZ,KAAK,SAAS,GACjB,MAAM,uBAAuB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,OAAO,EACH,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,GACtC,MAAM,+BAA+B,CAAA;AACtC,OAAO,EACH,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,GAC9B,MAAM,yBAAyB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,YAAY,EACR,kBAAkB,EAClB,YAAY,IAAI,yBAAyB,EACzC,iBAAiB,EACjB,oBAAoB,GACvB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACH,wBAAwB,EACxB,4BAA4B,EAC5B,cAAc,EACd,oBAAoB,EACpB,KAAK,qBAAqB,GAC7B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EACH,OAAO,EACP,QAAQ,EACR,cAAc,EACd,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,SAAS,EACT,UAAU,EACV,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,KAAK,OAAO,EACZ,KAAK,cAAc,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACH,cAAc,EACd,YAAY,EACZ,WAAW,EACX,UAAU,EACV,KAAK,mBAAmB,EACxB,KAAK,SAAS,IAAI,uBAAuB,GAC5C,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzE,YAAY,EAAE,wBAAwB,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAC5G,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,YAAY,EACR,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,GACxB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EACH,eAAe,EACf,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC9B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACH,eAAe,EACf,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,GACjB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACH,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,KAAK,qBAAqB,GAC7B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACH,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GAC3B,MAAM,4BAA4B,CAAA;AACnC,OAAO,EACH,sBAAsB,EACtB,uBAAuB,GAC1B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACH,kBAAkB,EAClB,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,GAChC,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACH,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,eAAe,GACvB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACH,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,GACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,qBAAqB,EACrB,KAAK,0BAA0B,GAClC,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACH,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,iBAAiB,GACzB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACH,aAAa,EACb,KAAK,kBAAkB,GAC1B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACH,gBAAgB,EAChB,KAAK,qBAAqB,GAC7B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACH,aAAa,EACb,eAAe,GAClB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACR,UAAU,EACV,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,GACvB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACH,UAAU,EACV,SAAS,EACT,UAAU,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,cAAc,EACd,KAAK,iBAAiB,GACzB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACH,cAAc,EACd,cAAc,EACd,SAAS,EACT,UAAU,EACV,KAAK,mBAAmB,GAC3B,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACH,UAAU,EACV,SAAS,EACT,WAAW,EACX,WAAW,EACX,KAAK,eAAe,GACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,aAAa,EACb,YAAY,EACZ,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,eAAe,GACvB,MAAM,yBAAyB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from './dynamic-table';
|
|
|
9
9
|
export { DynamicKanban, deriveStages, groupByStage, isTransitionAllowed, applyOptimisticMove, selectCardColumns, UNASSIGNED_LANE, } from './dynamic-kanban';
|
|
10
10
|
export { useStageAutomations, StageAutomationsButton, isTagColumn, automationFieldOptions, groupAutomationsByStage, activeAutomationCount, } from './stage-automations';
|
|
11
11
|
export { useCustomStages, splitCustomStages, mergeLaneStages, resolveSmartLanes, smartLaneParams, customStageFilterFields, isCustomStageDraftValid, slugifyStageKey, emptyCustomStageFilter, AddStageColumn, CustomStageLaneMenu, CustomStageDialog, CustomStageDeleteDialog, SmartLane, CUSTOM_STAGE_COLORS, CUSTOM_STAGE_FILTER_OPS, } from './custom-stages';
|
|
12
|
+
export { useStageLayout, } from './stage-layout';
|
|
12
13
|
export { DynamicView, resolveViewRenderer, readViewFromSearch, resolveActiveView, } from './dynamic-view';
|
|
13
14
|
export { useDynamicFilters, } from './use-dynamic-filters';
|
|
14
15
|
export * from './dynamic-form';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-action-toolbar.d.ts","sourceRoot":"","sources":["../src/model-action-toolbar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model-action-toolbar.d.ts","sourceRoot":"","sources":["../src/model-action-toolbar.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAiC,MAAM,SAAS,CAAA;AAE9E,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAExD,MAAM,WAAW,uBAAuB;IACpC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC5B,qEAAqE;IACrE,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAmBD;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,eAAe,EAAuB,EAClD,QAAQ,CAAC,EAAE,gBAAgB,EAAE,GAC9B,gBAAgB,EAAE,CA2BpB;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,OAAO,EACP,UAA+B,EAC/B,QAAQ,EACR,SAAS,GACZ,EAAE,uBAAuB,sCA0DzB"}
|
|
@@ -19,6 +19,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
19
19
|
// it internally, and bespoke host pages (e.g. ops `/m/$model`) mount it directly
|
|
20
20
|
// next to their own toolbar. Hosts never reimplement action-button plumbing.
|
|
21
21
|
import { useEffect, useMemo, useState } from 'react';
|
|
22
|
+
import { useTranslation } from 'react-i18next';
|
|
22
23
|
import { Button } from '@asteby/metacore-ui/primitives';
|
|
23
24
|
import { useApi } from './api-context';
|
|
24
25
|
import { useMetadataCache } from './metadata-cache';
|
|
@@ -71,6 +72,7 @@ export function useModelActions(model, placements = DEFAULT_PLACEMENTS, provided
|
|
|
71
72
|
return useMemo(() => all.filter((a) => placements.includes((a.placement ?? 'row'))), [all, placements]);
|
|
72
73
|
}
|
|
73
74
|
export function ModelActionToolbar({ model, endpoint, actions, placements = DEFAULT_PLACEMENTS, onChange, className, }) {
|
|
75
|
+
const { t } = useTranslation();
|
|
74
76
|
const all = useModelActions(model, placements, actions);
|
|
75
77
|
// Capability gating — always-true without a <PermissionsProvider>. Custom
|
|
76
78
|
// table/create actions map onto `lowercase(model).<action_key>`.
|
|
@@ -82,7 +84,7 @@ export function ModelActionToolbar({ model, endpoint, actions, placements = DEFA
|
|
|
82
84
|
return null;
|
|
83
85
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: className ?? 'flex items-center gap-2', children: surfaced.map((a) => {
|
|
84
86
|
const isCreate = (a.placement ?? 'row') === 'create';
|
|
85
|
-
return (_jsxs(Button, { variant: isCreate ? 'default' : 'outline', onClick: () => setActive(toActionMetadata(a)), style: a.color && !isCreate ? { borderColor: a.color, color: a.color } : undefined, children: [_jsx(DynamicIcon, { name: a.icon || (isCreate ? 'Plus' : 'Zap'), className: "mr-2 h-4 w-4" }), a.label] }, a.key));
|
|
87
|
+
return (_jsxs(Button, { variant: isCreate ? 'default' : 'outline', onClick: () => setActive(toActionMetadata(a)), style: a.color && !isCreate ? { borderColor: a.color, color: a.color } : undefined, children: [_jsx(DynamicIcon, { name: a.icon || (isCreate ? 'Plus' : 'Zap'), className: "mr-2 h-4 w-4" }), t(a.label, { defaultValue: a.label })] }, a.key));
|
|
86
88
|
}) }), active && (_jsx(ActionModalDispatcher, { open: !!active, onOpenChange: (open) => {
|
|
87
89
|
if (!open)
|
|
88
90
|
setActive(null);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface StageLayout {
|
|
2
|
+
model: string;
|
|
3
|
+
/** The full lane order — every lane key (stages + smart lanes) in order. */
|
|
4
|
+
stage_order: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface UseStageLayoutResult {
|
|
7
|
+
/** True only after a successful GET — gates the lane drag + reset affordance. */
|
|
8
|
+
available: boolean;
|
|
9
|
+
/** True when a custom order is stored server-side (drives the reset affordance). */
|
|
10
|
+
hasCustomLayout: boolean;
|
|
11
|
+
/** Persist the full lane order (the new order of every lane key). Throws on failure. */
|
|
12
|
+
save: (order: string[]) => Promise<void>;
|
|
13
|
+
/** Drop the stored order, reverting to the declared stage order. */
|
|
14
|
+
reset: () => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Loads a model's saved lane order (only to learn availability + whether a
|
|
18
|
+
* custom order exists) and exposes save/reset. A missing endpoint degrades to
|
|
19
|
+
* `available: false` so the board's lane drag stays off; a real save failure
|
|
20
|
+
* re-throws so the caller can revert its optimistic reorder.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useStageLayout(model: string): UseStageLayoutResult;
|
|
23
|
+
//# sourceMappingURL=stage-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-layout.d.ts","sourceRoot":"","sources":["../src/stage-layout.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,4EAA4E;IAC5E,WAAW,EAAE,MAAM,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACjC,iFAAiF;IACjF,SAAS,EAAE,OAAO,CAAA;IAClB,oFAAoF;IACpF,eAAe,EAAE,OAAO,CAAA;IACxB,wFAAwF;IACxF,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,oEAAoE;IACpE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAQD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB,CA6ClE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Stage layout — per-org persistence of the DynamicKanban lane order. Lets a
|
|
2
|
+
// user drag the board's columns (declared stages, custom stages and smart
|
|
3
|
+
// lanes alike) into any order; the chosen order is saved server-side and
|
|
4
|
+
// re-applied on load (the ops backend stamps it onto `metadata.stages[].order`
|
|
5
|
+
// / `smart_lanes[].order`, so the board already paints ordered — this hook only
|
|
6
|
+
// owns the drag + the optimistic PUT).
|
|
7
|
+
//
|
|
8
|
+
// Non-intrusive by design: mirrors `useStageAutomations`. If the host wires no
|
|
9
|
+
// `/stage-layout` endpoint, the GET 404s, `available` stays false, and the lane
|
|
10
|
+
// drag simply never turns on — the kanban keeps working untouched.
|
|
11
|
+
//
|
|
12
|
+
// Contract (matches the ops backend; envelope is {success, data} → read .data):
|
|
13
|
+
// GET /stage-layout?model=<m> → { model, stage_order: string[] } | null
|
|
14
|
+
// PUT /stage-layout { model, stage_order: string[] } (full order)
|
|
15
|
+
// DELETE /stage-layout?model=<m> → reset to the declared order
|
|
16
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
17
|
+
import { useApi } from './api-context';
|
|
18
|
+
function unwrap(res) {
|
|
19
|
+
const body = res?.data;
|
|
20
|
+
if (body && typeof body === 'object' && 'data' in body)
|
|
21
|
+
return body.data;
|
|
22
|
+
return body;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Loads a model's saved lane order (only to learn availability + whether a
|
|
26
|
+
* custom order exists) and exposes save/reset. A missing endpoint degrades to
|
|
27
|
+
* `available: false` so the board's lane drag stays off; a real save failure
|
|
28
|
+
* re-throws so the caller can revert its optimistic reorder.
|
|
29
|
+
*/
|
|
30
|
+
export function useStageLayout(model) {
|
|
31
|
+
const api = useApi();
|
|
32
|
+
const [available, setAvailable] = useState(false);
|
|
33
|
+
const [hasCustomLayout, setHasCustomLayout] = useState(false);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
let cancelled = false;
|
|
36
|
+
api
|
|
37
|
+
.get(`/stage-layout?model=${encodeURIComponent(model)}`)
|
|
38
|
+
.then((res) => {
|
|
39
|
+
if (cancelled)
|
|
40
|
+
return;
|
|
41
|
+
setAvailable(true);
|
|
42
|
+
const data = unwrap(res);
|
|
43
|
+
const order = data?.stage_order;
|
|
44
|
+
setHasCustomLayout(Array.isArray(order) && order.length > 0);
|
|
45
|
+
})
|
|
46
|
+
.catch(() => {
|
|
47
|
+
// Endpoint absent or errored — leave lane drag off.
|
|
48
|
+
if (!cancelled)
|
|
49
|
+
setAvailable(false);
|
|
50
|
+
});
|
|
51
|
+
return () => {
|
|
52
|
+
cancelled = true;
|
|
53
|
+
};
|
|
54
|
+
}, [api, model]);
|
|
55
|
+
const save = useCallback(async (order) => {
|
|
56
|
+
const res = (await api.put('/stage-layout', {
|
|
57
|
+
model,
|
|
58
|
+
stage_order: order,
|
|
59
|
+
}));
|
|
60
|
+
if (res?.data && res.data.success === false) {
|
|
61
|
+
throw new Error(res.data.message || 'stage_layout_save_failed');
|
|
62
|
+
}
|
|
63
|
+
setHasCustomLayout(true);
|
|
64
|
+
}, [api, model]);
|
|
65
|
+
const reset = useCallback(async () => {
|
|
66
|
+
await api.delete(`/stage-layout?model=${encodeURIComponent(model)}`);
|
|
67
|
+
setHasCustomLayout(false);
|
|
68
|
+
}, [api, model]);
|
|
69
|
+
return { available, hasCustomLayout, save, reset };
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
//
|
|
3
|
+
// DynamicKanban lane reordering (drag a column header to reorder lanes).
|
|
4
|
+
// happy-dom can't faithfully simulate a dnd-kit pointer drag, so we mock
|
|
5
|
+
// @dnd-kit/core + @dnd-kit/sortable down to a passthrough that CAPTURES the
|
|
6
|
+
// board's `onDragEnd`, then drive it with a synthetic lane / card drop. This
|
|
7
|
+
// exercises the real handler: optimistic reorder + `PUT /stage-layout` with the
|
|
8
|
+
// full new key order, revert on failure, and that a card drop still moves the
|
|
9
|
+
// card (not the lanes).
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
11
|
+
import { act, cleanup, render, screen, waitFor } from '@testing-library/react'
|
|
12
|
+
|
|
13
|
+
const I18N_T = (_k: string, opts?: { defaultValue?: string }) => opts?.defaultValue ?? _k
|
|
14
|
+
const I18N = { language: 'es' }
|
|
15
|
+
const USE_TRANSLATION = { t: I18N_T, i18n: I18N }
|
|
16
|
+
vi.mock('react-i18next', () => ({
|
|
17
|
+
useTranslation: () => USE_TRANSLATION,
|
|
18
|
+
}))
|
|
19
|
+
|
|
20
|
+
vi.mock('@tanstack/react-router', () => ({
|
|
21
|
+
useNavigate: () => () => {},
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
// Capture the board's drag callbacks so the test can fire a synthetic drop.
|
|
25
|
+
let captured: {
|
|
26
|
+
onDragEnd?: (e: any) => void | Promise<void>
|
|
27
|
+
onDragStart?: (e: any) => void
|
|
28
|
+
} = {}
|
|
29
|
+
vi.mock('@dnd-kit/core', () => ({
|
|
30
|
+
DndContext: ({ children, onDragEnd, onDragStart }: any) => {
|
|
31
|
+
captured.onDragEnd = onDragEnd
|
|
32
|
+
captured.onDragStart = onDragStart
|
|
33
|
+
return children
|
|
34
|
+
},
|
|
35
|
+
DragOverlay: ({ children }: any) => children ?? null,
|
|
36
|
+
PointerSensor: class {},
|
|
37
|
+
useSensor: () => ({}),
|
|
38
|
+
useSensors: () => [],
|
|
39
|
+
useDraggable: () => ({
|
|
40
|
+
attributes: {},
|
|
41
|
+
listeners: {},
|
|
42
|
+
setNodeRef: () => {},
|
|
43
|
+
isDragging: false,
|
|
44
|
+
}),
|
|
45
|
+
useDroppable: () => ({ setNodeRef: () => {}, isOver: false }),
|
|
46
|
+
}))
|
|
47
|
+
vi.mock('@dnd-kit/sortable', async (orig) => {
|
|
48
|
+
const actual = (await orig()) as Record<string, unknown>
|
|
49
|
+
return {
|
|
50
|
+
...actual,
|
|
51
|
+
SortableContext: ({ children }: any) => children,
|
|
52
|
+
useSortable: () => ({
|
|
53
|
+
setNodeRef: () => {},
|
|
54
|
+
setActivatorNodeRef: () => {},
|
|
55
|
+
attributes: {},
|
|
56
|
+
listeners: {},
|
|
57
|
+
transform: null,
|
|
58
|
+
transition: undefined,
|
|
59
|
+
isDragging: false,
|
|
60
|
+
isOver: false,
|
|
61
|
+
}),
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
import { DynamicKanban } from '../dynamic-kanban'
|
|
66
|
+
import { ApiProvider, type ApiClient } from '../api-context'
|
|
67
|
+
import { useMetadataCache } from '../metadata-cache'
|
|
68
|
+
import type { TableMetadata } from '../types'
|
|
69
|
+
|
|
70
|
+
const STAGES = [
|
|
71
|
+
{ key: 'backlog', label: 'Backlog', color: 'slate', order: 0 },
|
|
72
|
+
{ key: 'in_progress', label: 'In Progress', color: 'blue', order: 1 },
|
|
73
|
+
{ key: 'review', label: 'Review', color: 'amber', order: 2 },
|
|
74
|
+
{ key: 'done', label: 'Done', color: 'green', order: 3 },
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
function meta(): TableMetadata {
|
|
78
|
+
return {
|
|
79
|
+
title: 'Issues',
|
|
80
|
+
endpoint: '/data/issue',
|
|
81
|
+
view_type: 'kanban',
|
|
82
|
+
group_by: 'stage',
|
|
83
|
+
stages: STAGES,
|
|
84
|
+
transitions: [
|
|
85
|
+
{ from: 'backlog', to: 'in_progress' },
|
|
86
|
+
{ from: 'in_progress', to: 'review' },
|
|
87
|
+
{ from: 'review', to: 'done' },
|
|
88
|
+
],
|
|
89
|
+
columns: [
|
|
90
|
+
{ key: 'title', label: 'Title', type: 'text', sortable: true, filterable: false, searchable: true },
|
|
91
|
+
{
|
|
92
|
+
key: 'stage',
|
|
93
|
+
label: 'Stage',
|
|
94
|
+
type: 'status',
|
|
95
|
+
sortable: false,
|
|
96
|
+
filterable: true,
|
|
97
|
+
options: STAGES.map((s) => ({ value: s.key, label: s.label, color: s.color })),
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
actions: [],
|
|
101
|
+
perPageOptions: [50],
|
|
102
|
+
defaultPerPage: 50,
|
|
103
|
+
searchPlaceholder: 'Buscar...',
|
|
104
|
+
enableCRUDActions: true,
|
|
105
|
+
hasActions: false,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const CARDS = [
|
|
110
|
+
{ id: 1, title: 'Fix login bug', stage: 'backlog' },
|
|
111
|
+
{ id: 7, title: 'E2E tests', stage: 'review' },
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
function fakeApi(over: Partial<ApiClient> = {}): ApiClient {
|
|
115
|
+
const ok = (data: unknown) => ({ data: { success: true, data } })
|
|
116
|
+
return {
|
|
117
|
+
get: vi.fn(async (url: string) => {
|
|
118
|
+
if (url.startsWith('/metadata/table/')) return ok(meta())
|
|
119
|
+
if (url.startsWith('/stage-layout')) return ok({ model: 'issue', stage_order: null })
|
|
120
|
+
if (url.startsWith('/custom-stages')) return { data: { success: false } }
|
|
121
|
+
return ok(CARDS)
|
|
122
|
+
}),
|
|
123
|
+
post: vi.fn(async () => ok(null)),
|
|
124
|
+
put: vi.fn(async () => ok(null)),
|
|
125
|
+
delete: vi.fn(async () => ok(null)),
|
|
126
|
+
...over,
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const laneOrder = () =>
|
|
131
|
+
Array.from(document.querySelectorAll('[data-stage]')).map((el) =>
|
|
132
|
+
el.getAttribute('data-stage'),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
beforeEach(() => {
|
|
136
|
+
captured = {}
|
|
137
|
+
})
|
|
138
|
+
afterEach(cleanup)
|
|
139
|
+
|
|
140
|
+
describe('DynamicKanban lane reorder', () => {
|
|
141
|
+
it('an optimistic reorder PUTs the full new key order to /stage-layout', async () => {
|
|
142
|
+
useMetadataCache.getState().setMetadata('issue', meta())
|
|
143
|
+
const put = vi.fn(async () => ({ data: { success: true, data: null } }))
|
|
144
|
+
render(
|
|
145
|
+
<ApiProvider client={fakeApi({ put })}>
|
|
146
|
+
<DynamicKanban model="issue" />
|
|
147
|
+
</ApiProvider>,
|
|
148
|
+
)
|
|
149
|
+
await screen.findByText('Backlog')
|
|
150
|
+
// baseline order
|
|
151
|
+
await waitFor(() =>
|
|
152
|
+
expect(laneOrder()).toEqual(['backlog', 'in_progress', 'review', 'done']),
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
// drag "in_progress" onto "backlog" (move index 1 → 0)
|
|
156
|
+
await act(async () => {
|
|
157
|
+
await captured.onDragEnd!({
|
|
158
|
+
active: { id: 'in_progress', data: { current: { type: 'lane' } } },
|
|
159
|
+
over: { id: 'backlog' },
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
expect(put).toHaveBeenCalledWith('/stage-layout', {
|
|
164
|
+
model: 'issue',
|
|
165
|
+
stage_order: ['in_progress', 'backlog', 'review', 'done'],
|
|
166
|
+
})
|
|
167
|
+
// the board reflects the new order optimistically
|
|
168
|
+
expect(laneOrder()).toEqual(['in_progress', 'backlog', 'review', 'done'])
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('reverts the order when the PUT fails', async () => {
|
|
172
|
+
useMetadataCache.getState().setMetadata('issue', meta())
|
|
173
|
+
const put = vi.fn(async (url: string) => {
|
|
174
|
+
if (url === '/stage-layout') throw new Error('boom')
|
|
175
|
+
return { data: { success: true, data: null } }
|
|
176
|
+
})
|
|
177
|
+
render(
|
|
178
|
+
<ApiProvider client={fakeApi({ put })}>
|
|
179
|
+
<DynamicKanban model="issue" />
|
|
180
|
+
</ApiProvider>,
|
|
181
|
+
)
|
|
182
|
+
await screen.findByText('Backlog')
|
|
183
|
+
await waitFor(() =>
|
|
184
|
+
expect(laneOrder()).toEqual(['backlog', 'in_progress', 'review', 'done']),
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
await act(async () => {
|
|
188
|
+
await captured.onDragEnd!({
|
|
189
|
+
active: { id: 'done', data: { current: { type: 'lane' } } },
|
|
190
|
+
over: { id: 'backlog' },
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
expect(put).toHaveBeenCalledWith(
|
|
195
|
+
'/stage-layout',
|
|
196
|
+
expect.objectContaining({ stage_order: ['done', 'backlog', 'in_progress', 'review'] }),
|
|
197
|
+
)
|
|
198
|
+
// reverted back to the declared order
|
|
199
|
+
await waitFor(() =>
|
|
200
|
+
expect(laneOrder()).toEqual(['backlog', 'in_progress', 'review', 'done']),
|
|
201
|
+
)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('a card drop still moves the card (PUT to the record), not the lanes', async () => {
|
|
205
|
+
useMetadataCache.getState().setMetadata('issue', meta())
|
|
206
|
+
const put = vi.fn(async () => ({ data: { success: true, data: null } }))
|
|
207
|
+
render(
|
|
208
|
+
<ApiProvider client={fakeApi({ put })}>
|
|
209
|
+
<DynamicKanban model="issue" />
|
|
210
|
+
</ApiProvider>,
|
|
211
|
+
)
|
|
212
|
+
await screen.findByText('E2E tests')
|
|
213
|
+
|
|
214
|
+
// card 7 review -> done (a declared transition)
|
|
215
|
+
await act(async () => {
|
|
216
|
+
await captured.onDragEnd!({
|
|
217
|
+
active: { id: '7', data: { current: { type: 'card' } } },
|
|
218
|
+
over: { id: 'done' },
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
expect(put).toHaveBeenCalledWith('/data/issue/7', { stage: 'done' })
|
|
223
|
+
// no /stage-layout PUT for a card move
|
|
224
|
+
expect(put).not.toHaveBeenCalledWith('/stage-layout', expect.anything())
|
|
225
|
+
// lane order unchanged
|
|
226
|
+
expect(laneOrder()).toEqual(['backlog', 'in_progress', 'review', 'done'])
|
|
227
|
+
})
|
|
228
|
+
})
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
3
|
+
import { act, cleanup, render, screen, waitFor } from '@testing-library/react'
|
|
4
|
+
import i18next from 'i18next'
|
|
5
|
+
import { I18nextProvider } from 'react-i18next'
|
|
6
|
+
|
|
7
|
+
import { ModelActionToolbar } from '../model-action-toolbar'
|
|
8
|
+
import { ApiProvider } from '../api-context'
|
|
9
|
+
import type { ActionDefinition } from '../types'
|
|
10
|
+
|
|
11
|
+
afterEach(cleanup)
|
|
12
|
+
|
|
13
|
+
// Stub api client — the toolbar only calls it when it must fetch metadata, and
|
|
14
|
+
// we pass `actions` directly so it never does. Present only to satisfy useApi().
|
|
15
|
+
const api = {
|
|
16
|
+
get: async () => ({ data: { data: {} } }),
|
|
17
|
+
post: async () => ({ data: { success: true } }),
|
|
18
|
+
} as never
|
|
19
|
+
|
|
20
|
+
// A fresh i18next configured EXACTLY like the failing prod instance: keySeparator
|
|
21
|
+
// default and ignoreJSONStructure:false, so a flat literal key would NOT resolve
|
|
22
|
+
// — the fix must build/read a nested tree AND translate at render time.
|
|
23
|
+
function makeI18n() {
|
|
24
|
+
const inst = i18next.createInstance()
|
|
25
|
+
inst.init({
|
|
26
|
+
lng: 'es',
|
|
27
|
+
fallbackLng: 'es',
|
|
28
|
+
ignoreJSONStructure: false,
|
|
29
|
+
react: { bindI18nStore: 'added removed', useSuspense: false },
|
|
30
|
+
resources: { es: { translation: {} } },
|
|
31
|
+
})
|
|
32
|
+
return inst
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// The addon's create action exactly as the metadata endpoint ships it: the
|
|
36
|
+
// label is an i18n KEY, not display text (backend does not localize action
|
|
37
|
+
// labels — see the raw-key bug).
|
|
38
|
+
const createAction: ActionDefinition = {
|
|
39
|
+
key: 'create_issue',
|
|
40
|
+
label: 'integration_github.action.create_issue.label',
|
|
41
|
+
placement: 'create',
|
|
42
|
+
} as ActionDefinition
|
|
43
|
+
|
|
44
|
+
function renderToolbar(inst: ReturnType<typeof makeI18n>) {
|
|
45
|
+
return render(
|
|
46
|
+
<I18nextProvider i18n={inst}>
|
|
47
|
+
<ApiProvider client={api}>
|
|
48
|
+
<ModelActionToolbar model="github_issues" actions={[createAction]} />
|
|
49
|
+
</ApiProvider>
|
|
50
|
+
</I18nextProvider>,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe('ModelActionToolbar — translates addon action labels at render', () => {
|
|
55
|
+
it('shows the translation once the addon bundle lands (no raw key)', async () => {
|
|
56
|
+
const inst = makeI18n()
|
|
57
|
+
renderToolbar(inst)
|
|
58
|
+
|
|
59
|
+
// Before the addon bundle loads the toolbar has only the key; with the
|
|
60
|
+
// fix it renders the key text (t() falls back to defaultValue = the key).
|
|
61
|
+
// The point of the test is the TRANSITION below.
|
|
62
|
+
expect(
|
|
63
|
+
screen.getByText('integration_github.action.create_issue.label'),
|
|
64
|
+
).toBeTruthy()
|
|
65
|
+
|
|
66
|
+
// The addon locale bundle arrives asynchronously (OpsAddonLocaleLoader
|
|
67
|
+
// fetch → addResourceBundle). It is NESTED, as the host loader now merges
|
|
68
|
+
// it. This fires the i18next store 'added' event.
|
|
69
|
+
act(() => {
|
|
70
|
+
inst.addResourceBundle(
|
|
71
|
+
'es',
|
|
72
|
+
'translation',
|
|
73
|
+
{ integration_github: { action: { create_issue: { label: 'Crear issue' } } } },
|
|
74
|
+
true,
|
|
75
|
+
true,
|
|
76
|
+
)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// The toolbar must re-render and show the translated label — the exact
|
|
80
|
+
// behaviour that was missing (a bare {a.label} never re-derived).
|
|
81
|
+
await waitFor(() => expect(screen.getByText('Crear issue')).toBeTruthy())
|
|
82
|
+
expect(
|
|
83
|
+
screen.queryByText('integration_github.action.create_issue.label'),
|
|
84
|
+
).toBeNull()
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('leaves an already-localized label untouched (defaultValue passthrough)', () => {
|
|
88
|
+
const inst = makeI18n()
|
|
89
|
+
render(
|
|
90
|
+
<I18nextProvider i18n={inst}>
|
|
91
|
+
<ApiProvider client={api}>
|
|
92
|
+
<ModelActionToolbar
|
|
93
|
+
model="github_issues"
|
|
94
|
+
actions={[{ key: 'x', label: 'Crear issue', placement: 'create' } as ActionDefinition]}
|
|
95
|
+
/>
|
|
96
|
+
</ApiProvider>
|
|
97
|
+
</I18nextProvider>,
|
|
98
|
+
)
|
|
99
|
+
expect(screen.getByText('Crear issue')).toBeTruthy()
|
|
100
|
+
})
|
|
101
|
+
})
|