nucleus-core-ts 0.10.117 → 0.10.118
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/.build-ok +1 -1
- package/dist/fe/components/VerificationFlowPage/components/VerificationEntityList.d.ts +8 -2
- package/dist/fe/components/VerificationFlowPage/components/VerificationEntityList.js +100 -2
- package/dist/fe/components/VerificationFlowPage/components/VerificationFlowPage.d.ts +1 -1
- package/dist/fe/components/VerificationFlowPage/components/VerificationFlowPage.js +3 -2
- package/dist/fe/components/VerificationFlowPage/labels.d.ts +5 -0
- package/dist/fe/components/VerificationFlowPage/labels.js +4 -0
- package/dist/fe/components/VerificationFlowPage/types/index.d.ts +22 -0
- package/dist/index.js +2 -2
- package/dist/server.js +2 -2
- package/dist/src/Server/internalHeaders.d.ts +1 -1
- package/package.json +1 -1
package/dist/.build-ok
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.10.
|
|
1
|
+
0.10.118
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VerificationFlowLabels } from '../labels';
|
|
2
|
-
import type { VerificationBulkStatusItem, VerificationEntityStatusesAction } from '../types';
|
|
2
|
+
import type { VerificationBulkStatusItem, VerificationCancelAction, VerificationEntityStatusesAction } from '../types';
|
|
3
3
|
export type VerificationEntityListTheme = {
|
|
4
4
|
container: string;
|
|
5
5
|
header: string;
|
|
@@ -46,5 +46,11 @@ export type VerificationEntityListProps = {
|
|
|
46
46
|
pageSize?: number;
|
|
47
47
|
/** Spread over the English defaults; omit it and the list stays English. */
|
|
48
48
|
labels?: Partial<VerificationFlowLabels>;
|
|
49
|
+
/**
|
|
50
|
+
* Ends a chain that cannot finish. This list is the only screen that knows
|
|
51
|
+
* which chains are still `active`, so it is where the exit belongs — until
|
|
52
|
+
* now the API had one and the product offered none.
|
|
53
|
+
*/
|
|
54
|
+
cancelAction?: VerificationCancelAction;
|
|
49
55
|
};
|
|
50
|
-
export declare function VerificationEntityList({ entityName, entityStatusesAction, theme: themeOverrides, themeMode, onEntityClick, pageSize, labels, }: VerificationEntityListProps): import("react/jsx-runtime").JSX.Element;
|
|
56
|
+
export declare function VerificationEntityList({ entityName, entityStatusesAction, theme: themeOverrides, themeMode, onEntityClick, pageSize, labels, cancelAction, }: VerificationEntityListProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -97,7 +97,7 @@ const lightTheme = {
|
|
|
97
97
|
};
|
|
98
98
|
return map[status] ?? status;
|
|
99
99
|
}
|
|
100
|
-
export function VerificationEntityList({ entityName, entityStatusesAction, theme: themeOverrides, themeMode = 'dark', onEntityClick, pageSize = 20, labels }) {
|
|
100
|
+
export function VerificationEntityList({ entityName, entityStatusesAction, theme: themeOverrides, themeMode = 'dark', onEntityClick, pageSize = 20, labels, cancelAction }) {
|
|
101
101
|
const baseTheme = themeMode === 'light' ? lightTheme : darkTheme;
|
|
102
102
|
const t = {
|
|
103
103
|
...baseTheme,
|
|
@@ -109,6 +109,10 @@ export function VerificationEntityList({ entityName, entityStatusesAction, theme
|
|
|
109
109
|
};
|
|
110
110
|
const [activeTab, setActiveTab] = useState('all');
|
|
111
111
|
const [currentPage, setCurrentPage] = useState(1);
|
|
112
|
+
// Which row is asking for confirmation, and what it is being told.
|
|
113
|
+
const [cancellingId, setCancellingId] = useState(null);
|
|
114
|
+
const [cancelReason, setCancelReason] = useState('');
|
|
115
|
+
const [cancelNote, setCancelNote] = useState(null);
|
|
112
116
|
const loadStatuses = useEffectEvent((status, page)=>{
|
|
113
117
|
entityStatusesAction.start({
|
|
114
118
|
payload: {
|
|
@@ -128,6 +132,39 @@ export function VerificationEntityList({ entityName, entityStatusesAction, theme
|
|
|
128
132
|
setCurrentPage(page);
|
|
129
133
|
loadStatuses(activeTab === 'all' ? undefined : activeTab, page);
|
|
130
134
|
});
|
|
135
|
+
const sendCancel = useEffectEvent((item)=>{
|
|
136
|
+
if (!cancelAction) return;
|
|
137
|
+
setCancelNote(null);
|
|
138
|
+
cancelAction.start({
|
|
139
|
+
payload: {
|
|
140
|
+
entity_name: item.entity_name,
|
|
141
|
+
entity_id: item.entity_id,
|
|
142
|
+
...cancelReason ? {
|
|
143
|
+
reason: cancelReason
|
|
144
|
+
} : {}
|
|
145
|
+
},
|
|
146
|
+
onAfterHandle: (res)=>{
|
|
147
|
+
/*
|
|
148
|
+
* A refusal — "only the person who started this verification, or a
|
|
149
|
+
* godmin, can cancel it" — arrives as a body, not always as a status,
|
|
150
|
+
* so it is read from the body. The row is NOT closed on a refusal:
|
|
151
|
+
* closing it here is the bug that made every other decision screen
|
|
152
|
+
* look like it had worked.
|
|
153
|
+
*/ const response = res;
|
|
154
|
+
if (response?.success === false) {
|
|
155
|
+
setCancelNote(response.message || say.cancelChainFailed);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
setCancellingId(null);
|
|
159
|
+
setCancelReason('');
|
|
160
|
+
loadStatuses(activeTab === 'all' ? undefined : activeTab, currentPage);
|
|
161
|
+
},
|
|
162
|
+
onErrorHandle: (err)=>{
|
|
163
|
+
const msg = err?.message;
|
|
164
|
+
setCancelNote(msg || say.cancelChainFailed);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
131
168
|
useEffect(()=>{
|
|
132
169
|
loadStatuses(undefined, 1);
|
|
133
170
|
}, []);
|
|
@@ -294,7 +331,68 @@ export function VerificationEntityList({ entityName, entityStatusesAction, theme
|
|
|
294
331
|
/*#__PURE__*/ _jsx("span", {
|
|
295
332
|
className: `${t.statusBadge} ${getStatusBadgeClass(item.status)}`,
|
|
296
333
|
children: statusLabel(say, item.status)
|
|
297
|
-
})
|
|
334
|
+
}),
|
|
335
|
+
cancelAction && item.status === 'active' ? cancellingId === item.instance_id ? // No handlers on this wrapper: the row above is a button
|
|
336
|
+
// when `onEntityClick` is set, so each INTERACTIVE child
|
|
337
|
+
// stops the bubble itself rather than a bare div doing it
|
|
338
|
+
// for them.
|
|
339
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
340
|
+
className: "flex flex-col items-stretch gap-2 shrink-0",
|
|
341
|
+
children: [
|
|
342
|
+
/*#__PURE__*/ _jsx("p", {
|
|
343
|
+
className: t.metaLabel,
|
|
344
|
+
children: say.cancelChainConfirm
|
|
345
|
+
}),
|
|
346
|
+
/*#__PURE__*/ _jsx("input", {
|
|
347
|
+
type: "text",
|
|
348
|
+
value: cancelReason,
|
|
349
|
+
placeholder: say.cancelChainReasonPlaceholder,
|
|
350
|
+
onClick: (e)=>e.stopPropagation(),
|
|
351
|
+
onKeyDown: (e)=>e.stopPropagation(),
|
|
352
|
+
onChange: (e)=>setCancelReason(e.target.value),
|
|
353
|
+
className: themeMode === 'light' ? 'rounded-lg border border-gray-200 bg-gray-50 px-2 py-1 text-[11px] text-gray-800 outline-none focus:border-gray-400' : 'rounded-lg border border-white/[0.08] bg-white/[0.04] px-2 py-1 text-[11px] text-white/80 outline-none focus:border-white/20'
|
|
354
|
+
}),
|
|
355
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
356
|
+
className: "flex items-center gap-2",
|
|
357
|
+
children: [
|
|
358
|
+
/*#__PURE__*/ _jsx("button", {
|
|
359
|
+
type: "button",
|
|
360
|
+
onClick: (e)=>{
|
|
361
|
+
e.stopPropagation();
|
|
362
|
+
sendCancel(item);
|
|
363
|
+
},
|
|
364
|
+
className: themeMode === 'light' ? 'rounded-lg border border-red-200 bg-red-50 px-2.5 py-1 text-[11px] font-medium text-red-600 hover:bg-red-100' : 'rounded-lg border border-red-500/30 bg-red-500/20 px-2.5 py-1 text-[11px] font-medium text-red-400 hover:bg-red-500/30',
|
|
365
|
+
children: say.cancelChain
|
|
366
|
+
}),
|
|
367
|
+
/*#__PURE__*/ _jsx("button", {
|
|
368
|
+
type: "button",
|
|
369
|
+
onClick: (e)=>{
|
|
370
|
+
e.stopPropagation();
|
|
371
|
+
setCancellingId(null);
|
|
372
|
+
setCancelReason('');
|
|
373
|
+
setCancelNote(null);
|
|
374
|
+
},
|
|
375
|
+
className: themeMode === 'light' ? 'rounded-lg border border-gray-200 bg-gray-50 px-2.5 py-1 text-[11px] font-medium text-gray-500 hover:bg-gray-100' : 'rounded-lg border border-white/[0.08] bg-white/[0.06] px-2.5 py-1 text-[11px] font-medium text-white/50 hover:bg-white/[0.1]',
|
|
376
|
+
children: say.cancel
|
|
377
|
+
})
|
|
378
|
+
]
|
|
379
|
+
}),
|
|
380
|
+
cancelNote ? /*#__PURE__*/ _jsx("p", {
|
|
381
|
+
role: "alert",
|
|
382
|
+
className: themeMode === 'light' ? 'text-[11px] leading-4 text-amber-900' : 'text-[11px] leading-4 text-amber-200',
|
|
383
|
+
children: cancelNote
|
|
384
|
+
}) : null
|
|
385
|
+
]
|
|
386
|
+
}) : /*#__PURE__*/ _jsx("button", {
|
|
387
|
+
type: "button",
|
|
388
|
+
onClick: (e)=>{
|
|
389
|
+
e.stopPropagation();
|
|
390
|
+
setCancellingId(item.instance_id);
|
|
391
|
+
setCancelNote(null);
|
|
392
|
+
},
|
|
393
|
+
className: themeMode === 'light' ? 'shrink-0 rounded-lg border border-gray-200 bg-white px-2.5 py-1 text-[11px] font-medium text-gray-600 hover:bg-gray-100' : 'shrink-0 rounded-lg border border-white/[0.08] bg-white/[0.04] px-2.5 py-1 text-[11px] font-medium text-white/60 hover:bg-white/[0.1]',
|
|
394
|
+
children: say.cancelChain
|
|
395
|
+
}) : null
|
|
298
396
|
]
|
|
299
397
|
}, item.instance_id);
|
|
300
398
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import '@xyflow/react/dist/style.css';
|
|
2
2
|
import type { ReactElement } from 'react';
|
|
3
3
|
import type { VerificationFlowPageProps } from '../types';
|
|
4
|
-
export declare function VerificationFlowPage({ entityName, title, subtitle, flowListAction, flowGetAction, flowSaveAction, flowPublishAction, flowUnpublishAction, flowDeleteAction, pendingAction, decideAction, uploadSignatureAction, listUsersAction, listRolesAction, entityStatusesAction, onFlowSelected, onDecisionMade, onEntityClick, onBack, showPending, showEntityStatuses, className, themeMode, labels, describeEntity, entityHref, availableChannels, initialTab, }: VerificationFlowPageProps): ReactElement;
|
|
4
|
+
export declare function VerificationFlowPage({ entityName, title, subtitle, flowListAction, flowGetAction, flowSaveAction, flowPublishAction, flowUnpublishAction, flowDeleteAction, pendingAction, decideAction, uploadSignatureAction, listUsersAction, listRolesAction, entityStatusesAction, onFlowSelected, onDecisionMade, onEntityClick, onBack, showPending, showEntityStatuses, className, themeMode, labels, describeEntity, entityHref, availableChannels, initialTab, cancelAction, }: VerificationFlowPageProps): ReactElement;
|
|
@@ -297,7 +297,7 @@ function buildSavePayload(flowId, entityName, flowName, flowDescription, trigger
|
|
|
297
297
|
};
|
|
298
298
|
}
|
|
299
299
|
// ─── Main Component ───────────────────────────────────────────────
|
|
300
|
-
export function VerificationFlowPage({ entityName, title, subtitle, flowListAction, flowGetAction, flowSaveAction, flowPublishAction, flowUnpublishAction, flowDeleteAction, pendingAction, decideAction, uploadSignatureAction, listUsersAction, listRolesAction, entityStatusesAction, onFlowSelected, onDecisionMade, onEntityClick, onBack, showPending = true, showEntityStatuses = false, className, themeMode = 'dark', labels, describeEntity, entityHref, availableChannels, initialTab }) {
|
|
300
|
+
export function VerificationFlowPage({ entityName, title, subtitle, flowListAction, flowGetAction, flowSaveAction, flowPublishAction, flowUnpublishAction, flowDeleteAction, pendingAction, decideAction, uploadSignatureAction, listUsersAction, listRolesAction, entityStatusesAction, onFlowSelected, onDecisionMade, onEntityClick, onBack, showPending = true, showEntityStatuses = false, className, themeMode = 'dark', labels, describeEntity, entityHref, availableChannels, initialTab, cancelAction }) {
|
|
301
301
|
const theme = getVerificationFlowTheme(themeMode);
|
|
302
302
|
setActiveTheme(theme);
|
|
303
303
|
const say = {
|
|
@@ -1323,7 +1323,8 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
|
|
|
1323
1323
|
entityStatusesAction: entityStatusesAction,
|
|
1324
1324
|
onEntityClick: onEntityClick,
|
|
1325
1325
|
themeMode: themeMode,
|
|
1326
|
-
labels: say
|
|
1326
|
+
labels: say,
|
|
1327
|
+
cancelAction: cancelAction
|
|
1327
1328
|
})
|
|
1328
1329
|
})
|
|
1329
1330
|
]
|
|
@@ -192,6 +192,11 @@ export type VerificationFlowLabels = {
|
|
|
192
192
|
openRecord: string;
|
|
193
193
|
/** Shown beside a channel this deployment cannot deliver on. */
|
|
194
194
|
channelUnavailable: string;
|
|
195
|
+
/** Ends a chain nobody can finish. Starter or godmin only. */
|
|
196
|
+
cancelChain: string;
|
|
197
|
+
cancelChainConfirm: string;
|
|
198
|
+
cancelChainReasonPlaceholder: string;
|
|
199
|
+
cancelChainFailed: string;
|
|
195
200
|
verificationStatusTitle: string;
|
|
196
201
|
/** "12 records for orders" — count and entity, both inside the label. */
|
|
197
202
|
recordCount: (count: number, entityName: string) => string;
|
|
@@ -152,6 +152,10 @@
|
|
|
152
152
|
pendingRecordLabel: 'Record',
|
|
153
153
|
openRecord: 'Open the record',
|
|
154
154
|
channelUnavailable: 'not available on this installation',
|
|
155
|
+
cancelChain: 'End this review',
|
|
156
|
+
cancelChainConfirm: 'End this review? The record goes back to pending and a new chain can be started. The decisions already made are kept.',
|
|
157
|
+
cancelChainReasonPlaceholder: 'Why (optional)',
|
|
158
|
+
cancelChainFailed: 'The review could not be ended.',
|
|
155
159
|
verificationStatusTitle: 'Verification Status',
|
|
156
160
|
recordCount: (count, entityName)=>`${count} record${count !== 1 ? 's' : ''} for ${entityName}`,
|
|
157
161
|
noRecordsIconTitle: 'No records',
|
|
@@ -33,6 +33,23 @@ export type VerificationDecideAction = GenericAction<VerificationDecidePayload &
|
|
|
33
33
|
entity_id: string;
|
|
34
34
|
}, VerificationDecideResponse>;
|
|
35
35
|
export type VerificationPendingAction = GenericAction<undefined, VerificationPendingResponse>;
|
|
36
|
+
/**
|
|
37
|
+
* Closes a chain nobody can finish any more.
|
|
38
|
+
*
|
|
39
|
+
* The API has had this since the engine did; no screen in the product ever
|
|
40
|
+
* called it. So a chain that stranded — an emptied role, a withdrawn flow, a
|
|
41
|
+
* step whose only candidate the chain itself bars — could be ended by nothing
|
|
42
|
+
* a person can press, and the record stayed `pending` for good. The route
|
|
43
|
+
* allows the person who started the chain, or a godmin, and nobody else.
|
|
44
|
+
*/
|
|
45
|
+
export type VerificationCancelAction = GenericAction<{
|
|
46
|
+
entity_name: string;
|
|
47
|
+
entity_id: string;
|
|
48
|
+
reason?: string;
|
|
49
|
+
}, {
|
|
50
|
+
success: boolean;
|
|
51
|
+
message?: string;
|
|
52
|
+
}>;
|
|
36
53
|
/**
|
|
37
54
|
* Uploads the file a verifier signs with, and hands back its id.
|
|
38
55
|
*
|
|
@@ -267,6 +284,11 @@ export type VerificationFlowPageProps = {
|
|
|
267
284
|
* arrived says so here.
|
|
268
285
|
*/
|
|
269
286
|
initialTab?: 'flow' | 'pending' | 'statuses';
|
|
287
|
+
/**
|
|
288
|
+
* Lets the starter (or a godmin) end a chain that cannot finish. Omit it and
|
|
289
|
+
* the records list has no cancel control, which is what shipped until now.
|
|
290
|
+
*/
|
|
291
|
+
cancelAction?: VerificationCancelAction;
|
|
270
292
|
};
|
|
271
293
|
export type DraggedNodeType = NodeType | null;
|
|
272
294
|
export type VerificationFlowPageState = {
|