@asteby/metacore-runtime-react 23.8.0 → 23.9.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/CHANGELOG.md +46 -0
- package/dist/custom-stages.d.ts +96 -1
- package/dist/custom-stages.d.ts.map +1 -1
- package/dist/custom-stages.js +259 -24
- package/dist/dynamic-form-schema.d.ts +18 -1
- package/dist/dynamic-form-schema.d.ts.map +1 -1
- package/dist/dynamic-form-schema.js +43 -0
- package/dist/dynamic-form.d.ts.map +1 -1
- package/dist/dynamic-form.js +30 -9
- package/dist/dynamic-kanban.d.ts +8 -0
- package/dist/dynamic-kanban.d.ts.map +1 -1
- package/dist/dynamic-kanban.js +188 -16
- package/dist/dynamic-line-items.d.ts.map +1 -1
- package/dist/dynamic-line-items.js +24 -3
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/stage-overrides.d.ts +25 -0
- package/dist/stage-overrides.d.ts.map +1 -0
- package/dist/stage-overrides.js +64 -0
- package/dist/types.d.ts +69 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/dependent-enum-form.test.tsx +84 -0
- package/src/__tests__/dependent-enum-options.test.ts +67 -0
- package/src/__tests__/dynamic-kanban.test.tsx +75 -0
- package/src/__tests__/stage-overrides.test.tsx +293 -0
- package/src/custom-stages.tsx +716 -109
- package/src/dynamic-form-schema.ts +44 -1
- package/src/dynamic-form.tsx +76 -28
- package/src/dynamic-kanban.tsx +236 -25
- package/src/dynamic-line-items.tsx +26 -2
- package/src/dynamic-table.tsx +4 -0
- package/src/index.ts +13 -0
- package/src/stage-overrides.ts +95 -0
- package/src/types.ts +63 -1
package/src/dynamic-table.tsx
CHANGED
|
@@ -209,6 +209,10 @@ export function DynamicTable({
|
|
|
209
209
|
if (colonIdx === -1) return value
|
|
210
210
|
const prefix = value.substring(0, colonIdx).toLowerCase()
|
|
211
211
|
const rest = value.substring(colonIdx + 1)
|
|
212
|
+
// `eq:` is the wire's explicit equality operator, but internally a
|
|
213
|
+
// select stores the bare value — unwrap it so `f_status=eq:reception`
|
|
214
|
+
// matches the option "reception" (header filter + chip label).
|
|
215
|
+
if (prefix === 'eq') return rest
|
|
212
216
|
const operator = urlAliasToOperator[prefix]
|
|
213
217
|
return operator ? `${operator}:${rest}` : value
|
|
214
218
|
}
|
package/src/index.ts
CHANGED
|
@@ -36,6 +36,7 @@ export {
|
|
|
36
36
|
mergeLaneStages,
|
|
37
37
|
resolveSmartLanes,
|
|
38
38
|
smartLaneParams,
|
|
39
|
+
cardMatchesStageFilters,
|
|
39
40
|
customStageFilterFields,
|
|
40
41
|
isCustomStageDraftValid,
|
|
41
42
|
slugifyStageKey,
|
|
@@ -44,6 +45,9 @@ export {
|
|
|
44
45
|
CustomStageLaneMenu,
|
|
45
46
|
CustomStageDialog,
|
|
46
47
|
CustomStageDeleteDialog,
|
|
48
|
+
StageConditionBuilder,
|
|
49
|
+
StageConfigDialog,
|
|
50
|
+
stageFilterOpSymbol,
|
|
47
51
|
SmartLane,
|
|
48
52
|
CUSTOM_STAGE_COLORS,
|
|
49
53
|
CUSTOM_STAGE_FILTER_OPS,
|
|
@@ -53,12 +57,21 @@ export {
|
|
|
53
57
|
type CustomStageFilter,
|
|
54
58
|
type CustomStageFilterOp,
|
|
55
59
|
type UseCustomStagesResult,
|
|
60
|
+
type StageConfigTarget,
|
|
61
|
+
type StageConfigKind,
|
|
62
|
+
type StageConditionBuilderProps,
|
|
63
|
+
type StageConfigDialogProps,
|
|
56
64
|
} from './custom-stages'
|
|
57
65
|
export {
|
|
58
66
|
useStageLayout,
|
|
59
67
|
type StageLayout,
|
|
60
68
|
type UseStageLayoutResult,
|
|
61
69
|
} from './stage-layout'
|
|
70
|
+
export {
|
|
71
|
+
useStageOverrides,
|
|
72
|
+
type StageOverridePatch,
|
|
73
|
+
type UseStageOverridesResult,
|
|
74
|
+
} from './stage-overrides'
|
|
62
75
|
export {
|
|
63
76
|
DynamicView,
|
|
64
77
|
resolveViewRenderer,
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Stage overrides — per-org customization of a model's DECLARED kanban lanes
|
|
2
|
+
// (Backlog, Done, …). A user can rename a lane, recolor it, and attach extra
|
|
3
|
+
// "conditions" (a field/operator/value builder) that narrow which cards the lane
|
|
4
|
+
// shows and counts — all without touching the addon manifest. The chosen values
|
|
5
|
+
// are stored server-side and the kernel serves each declared stage already
|
|
6
|
+
// carrying the overridden label/color (+ an `overridden` flag and the extra
|
|
7
|
+
// `filters`), so the board paints them straight from `metadata.stages`.
|
|
8
|
+
//
|
|
9
|
+
// Custom stages (`custom: true`) are NOT edited here — they keep their own CRUD
|
|
10
|
+
// (`/custom-stages`); this hook only owns the DECLARED-lane overrides.
|
|
11
|
+
//
|
|
12
|
+
// Non-intrusive by design: mirrors `useStageLayout`. If the host wires no
|
|
13
|
+
// `/stage-overrides` endpoint, the GET 404s, `available` stays false, and the
|
|
14
|
+
// per-lane gear (⚙) simply never renders on declared stages — the kanban keeps
|
|
15
|
+
// working untouched.
|
|
16
|
+
//
|
|
17
|
+
// Contract (matches the ops backend; envelope is {success, data} → read .data):
|
|
18
|
+
// GET /stage-overrides?model=<m> → [{ stage_key, label?, color?, filters? }] | null
|
|
19
|
+
// PUT /stage-overrides { model, stage_key, label?, color?, filters? } (upsert)
|
|
20
|
+
// DELETE /stage-overrides?model=<m>&stage_key=<k> → reset the lane to its declared default
|
|
21
|
+
import { useCallback, useEffect, useState } from 'react'
|
|
22
|
+
import { useApi } from './api-context'
|
|
23
|
+
import type { CustomStageFilter } from './custom-stages'
|
|
24
|
+
|
|
25
|
+
/** Fields a stage override can carry. All optional — send only what changed. */
|
|
26
|
+
export interface StageOverridePatch {
|
|
27
|
+
label?: string
|
|
28
|
+
color?: string
|
|
29
|
+
/** Extra lane conditions (same shape/ops as smart-lane filters). */
|
|
30
|
+
filters?: CustomStageFilter[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface UseStageOverridesResult {
|
|
34
|
+
/** True only after a successful GET — gates the per-lane gear on declared stages. */
|
|
35
|
+
available: boolean
|
|
36
|
+
/** Upsert a declared lane's override (label/color/conditions). Throws on failure. */
|
|
37
|
+
save: (stageKey: string, patch: StageOverridePatch) => Promise<void>
|
|
38
|
+
/** Reset a declared lane to its manifest default (drops the stored override). */
|
|
39
|
+
reset: (stageKey: string) => Promise<void>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Learns whether the host wired `/stage-overrides` (so the gear can appear on
|
|
44
|
+
* declared lanes) and exposes save/reset. A missing endpoint degrades to
|
|
45
|
+
* `available: false`; a real save/reset failure re-throws so the caller can
|
|
46
|
+
* surface an error + revert. The overridden VALUES themselves are read off
|
|
47
|
+
* `metadata.stages` (the kernel applies them), so this hook doesn't cache a list.
|
|
48
|
+
*/
|
|
49
|
+
export function useStageOverrides(model: string): UseStageOverridesResult {
|
|
50
|
+
const api = useApi()
|
|
51
|
+
const [available, setAvailable] = useState(false)
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
let cancelled = false
|
|
55
|
+
api
|
|
56
|
+
.get(`/stage-overrides?model=${encodeURIComponent(model)}`)
|
|
57
|
+
.then(() => {
|
|
58
|
+
if (!cancelled) setAvailable(true)
|
|
59
|
+
})
|
|
60
|
+
.catch(() => {
|
|
61
|
+
// Endpoint absent or errored — leave the gear off on declared lanes.
|
|
62
|
+
if (!cancelled) setAvailable(false)
|
|
63
|
+
})
|
|
64
|
+
return () => {
|
|
65
|
+
cancelled = true
|
|
66
|
+
}
|
|
67
|
+
}, [api, model])
|
|
68
|
+
|
|
69
|
+
const save = useCallback(
|
|
70
|
+
async (stageKey: string, patch: StageOverridePatch) => {
|
|
71
|
+
const res = (await api.put('/stage-overrides', {
|
|
72
|
+
model,
|
|
73
|
+
stage_key: stageKey,
|
|
74
|
+
...patch,
|
|
75
|
+
})) as { data?: { success?: boolean; message?: string } }
|
|
76
|
+
if (res?.data && res.data.success === false) {
|
|
77
|
+
throw new Error(res.data.message || 'stage_override_save_failed')
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
[api, model],
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
const reset = useCallback(
|
|
84
|
+
async (stageKey: string) => {
|
|
85
|
+
await api.delete(
|
|
86
|
+
`/stage-overrides?model=${encodeURIComponent(
|
|
87
|
+
model,
|
|
88
|
+
)}&stage_key=${encodeURIComponent(stageKey)}`,
|
|
89
|
+
)
|
|
90
|
+
},
|
|
91
|
+
[api, model],
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
return { available, save, reset }
|
|
95
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -77,6 +77,34 @@ export interface StageMeta {
|
|
|
77
77
|
* Editar/Eliminar menu on it.
|
|
78
78
|
*/
|
|
79
79
|
custom?: boolean
|
|
80
|
+
/**
|
|
81
|
+
* True when a per-org stage override (label/color/conditions) has been
|
|
82
|
+
* applied to this DECLARED lane (ops stage-overrides). The kernel serves the
|
|
83
|
+
* lane already carrying the overridden label/color; this flag only drives the
|
|
84
|
+
* "Restablecer etapa" affordance in the config dialog. Absent on hosts without
|
|
85
|
+
* stage overrides — purely additive.
|
|
86
|
+
*/
|
|
87
|
+
overridden?: boolean
|
|
88
|
+
/**
|
|
89
|
+
* Extra per-lane conditions layered on top of the stage's own `group_by`
|
|
90
|
+
* scope (ops stage-overrides). When present the lane queries its data — and
|
|
91
|
+
* counts its header — with the stage filter PLUS these conditions (serialized
|
|
92
|
+
* the same way as smart-lane filters). The lane stays a normal drop target;
|
|
93
|
+
* dropping a card only sets the stage value. Absent → the lane behaves as a
|
|
94
|
+
* plain declared stage. Snake_case ops as the kernel serves them.
|
|
95
|
+
*/
|
|
96
|
+
filters?: { field: string; op: string; value: string }[]
|
|
97
|
+
/**
|
|
98
|
+
* The manifest ORIGINAL (pre-override) label/color/conditions, served
|
|
99
|
+
* alongside an overridden declared lane so the "Restablecer al original"
|
|
100
|
+
* confirm can spell out exactly what reverts. Optional — hosts that don't
|
|
101
|
+
* snapshot the original simply omit it and the SDK shows a generic confirm.
|
|
102
|
+
*/
|
|
103
|
+
original?: {
|
|
104
|
+
label?: string
|
|
105
|
+
color?: string
|
|
106
|
+
filters?: { field: string; op: string; value: string }[]
|
|
107
|
+
}
|
|
80
108
|
}
|
|
81
109
|
|
|
82
110
|
/**
|
|
@@ -307,12 +335,46 @@ export type FieldWidget =
|
|
|
307
335
|
| 'switch'
|
|
308
336
|
| 'upload'
|
|
309
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Per-option visibility gate for a STATIC enum (`options[]`). The option is only
|
|
340
|
+
* offered when the value of a sibling field (`field`, defaulting to the
|
|
341
|
+
* containing field's `dependsOn`) passes: value ∈ `in` and value ∉ `notIn`.
|
|
342
|
+
* Comparison is by string. Mirrors the kernel v3 `option.when` block; the SDK
|
|
343
|
+
* tolerates both the snake_case (`not_in`) the kernel serves and camelCase.
|
|
344
|
+
* An option WITHOUT a `when` always applies (retrocompat).
|
|
345
|
+
*/
|
|
346
|
+
export interface OptionWhen {
|
|
347
|
+
/** Sibling field whose value gates this option. Falls back to `dependsOn`. */
|
|
348
|
+
field?: string
|
|
349
|
+
/** The option applies when the gating field's value is in this list. */
|
|
350
|
+
in?: string[]
|
|
351
|
+
/** The option applies when the gating field's value is NOT in this list. */
|
|
352
|
+
notIn?: string[]
|
|
353
|
+
/** snake_case alias served by the kernel manifest for `notIn`. */
|
|
354
|
+
not_in?: string[]
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* A single static enum option. `value`/`label` are the core pair; `icon`,
|
|
359
|
+
* `color` and `image` drive the option's leading visual where the renderer
|
|
360
|
+
* supports it. `when` gates the option's visibility by a sibling field's value
|
|
361
|
+
* (see {@link OptionWhen}) — used for dependent/cascading STATIC enums.
|
|
362
|
+
*/
|
|
363
|
+
export interface OptionDef {
|
|
364
|
+
value: string
|
|
365
|
+
label: string
|
|
366
|
+
icon?: string
|
|
367
|
+
color?: string
|
|
368
|
+
image?: string
|
|
369
|
+
when?: OptionWhen
|
|
370
|
+
}
|
|
371
|
+
|
|
310
372
|
export interface ActionFieldDef {
|
|
311
373
|
key: string
|
|
312
374
|
label: string
|
|
313
375
|
type: string
|
|
314
376
|
required?: boolean
|
|
315
|
-
options?:
|
|
377
|
+
options?: OptionDef[]
|
|
316
378
|
defaultValue?: any
|
|
317
379
|
placeholder?: string
|
|
318
380
|
searchEndpoint?: string
|