nucleus-core-ts 0.10.115 → 0.10.116

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 CHANGED
@@ -1 +1 @@
1
- 0.10.115
1
+ 0.10.116
@@ -477,6 +477,27 @@ export function PropertiesPanel({ nodeId, nodeData, onUpdateNode, onDeleteNode,
477
477
  /*#__PURE__*/ _jsxs("div", {
478
478
  className: theme.body,
479
479
  children: [
480
+ /*#__PURE__*/ _jsxs("p", {
481
+ className: theme.help,
482
+ children: [
483
+ nodeType === 'step' && say.stepHelp,
484
+ nodeType === 'verifier' && say.verifierHelp,
485
+ nodeType === 'notification' && say.notificationHelp
486
+ ]
487
+ }),
488
+ nodeType === 'step' && /* The one fact a step carries at runtime, and the operator cannot
489
+ * type it: it is derived from the arrows when the flow is saved. */ /*#__PURE__*/ _jsxs("p", {
490
+ className: theme.readOnlyRow,
491
+ children: [
492
+ /*#__PURE__*/ _jsx("span", {
493
+ children: say.stepOrderLabel
494
+ }),
495
+ /*#__PURE__*/ _jsx("span", {
496
+ className: theme.readOnlyValue,
497
+ children: Number(data.stepOrder) > 0 ? data.stepOrder : say.stepOrderUnset
498
+ })
499
+ ]
500
+ }),
480
501
  /*#__PURE__*/ _jsxs("div", {
481
502
  className: theme.section,
482
503
  children: [
@@ -149,7 +149,19 @@ function createNewNode(nodeType, position, say) {
149
149
  base.data = {
150
150
  ...base.data,
151
151
  trigger: 'on_step_reached',
152
- channels: []
152
+ channels: [
153
+ 'portal'
154
+ ],
155
+ /*
156
+ * The recipient the panel ALREADY shows.
157
+ *
158
+ * The properties panel renders `data.recipientType || 'all_verifiers'`,
159
+ * so a node nobody opened read "All Verifiers" while the field was
160
+ * undefined — and `buildSavePayload` only writes a recipient row when
161
+ * the field is set. The result was a notification node that drew
162
+ * correctly, saved, published green and reached nobody, with no error
163
+ * anywhere. Seeding it makes the screen's claim true.
164
+ */ recipientType: 'all_verifiers'
153
165
  };
154
166
  }
155
167
  return base;
@@ -252,14 +264,19 @@ function buildSavePayload(flowId, entityName, flowName, flowDescription, trigger
252
264
  channel: ch
253
265
  });
254
266
  }
255
- if (d.recipientType) {
256
- notification_recipients.push({
257
- rule_id: n.id,
258
- recipient_type: d.recipientType,
259
- recipient_user_id: d.recipientUserId,
260
- recipient_role: d.recipientRole
261
- });
262
- }
267
+ /*
268
+ * ALWAYS a recipient row, defaulting to what the panel displays.
269
+ *
270
+ * `if (d.recipientType)` skipped the row for every node the operator
271
+ * never opened, which is every node they dropped and wired without
272
+ * thinking about it — the commonest way to build a flow. A rule with no
273
+ * recipient resolves to an empty list and the send loop never runs.
274
+ */ notification_recipients.push({
275
+ rule_id: n.id,
276
+ recipient_type: d.recipientType || 'all_verifiers',
277
+ recipient_user_id: d.recipientUserId,
278
+ recipient_role: d.recipientRole
279
+ });
263
280
  }
264
281
  return {
265
282
  flow_id: flowId,
@@ -887,7 +904,7 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
887
904
  children: viewMode === 'designer' && store.activeTab === 'flow' && /*#__PURE__*/ _jsxs(_Fragment, {
888
905
  children: [
889
906
  /*#__PURE__*/ _jsx("span", {
890
- className: "text-[11px] text-white/50 font-medium",
907
+ className: cn('text-[11px] font-medium', themeMode === 'light' ? 'text-gray-600' : 'text-white/50'),
891
908
  children: flowName || say.untitledFlow
892
909
  }),
893
910
  selectedFlow?.is_draft !== undefined && /*#__PURE__*/ _jsx("span", {
@@ -1127,6 +1144,19 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
1127
1144
  isDraggingOver && /*#__PURE__*/ _jsx("div", {
1128
1145
  className: theme.canvas.dropIndicator
1129
1146
  }),
1147
+ !store.isLoadingGraph && nodes.length === 0 && /*#__PURE__*/ _jsxs("div", {
1148
+ className: theme.canvas.emptyHint,
1149
+ children: [
1150
+ /*#__PURE__*/ _jsx("p", {
1151
+ className: theme.canvas.emptyHintTitle,
1152
+ children: say.canvasEmptyTitle
1153
+ }),
1154
+ /*#__PURE__*/ _jsx("p", {
1155
+ className: theme.canvas.emptyHintBody,
1156
+ children: say.canvasEmptyBody
1157
+ })
1158
+ ]
1159
+ }),
1130
1160
  /*#__PURE__*/ _jsxs(ReactFlow, {
1131
1161
  nodes: nodes,
1132
1162
  edges: edges,
@@ -122,6 +122,22 @@ export type VerificationFlowLabels = {
122
122
  stepProperties: string;
123
123
  verifierProperties: string;
124
124
  notificationProperties: string;
125
+ /**
126
+ * What each kind of node IS, said where the operator is standing.
127
+ *
128
+ * The owner of this product asked, about his own screen, "what does the
129
+ * step node even do?" — and nothing on it could answer him. One paragraph
130
+ * at the top of each properties panel, plus the derived order a step
131
+ * cannot be given by hand.
132
+ */
133
+ stepHelp: string;
134
+ verifierHelp: string;
135
+ notificationHelp: string;
136
+ stepOrderLabel: string;
137
+ stepOrderUnset: string;
138
+ /** The blank canvas, which said nothing at all. */
139
+ canvasEmptyTitle: string;
140
+ canvasEmptyBody: string;
125
141
  sectionGeneral: string;
126
142
  sectionAssignment: string;
127
143
  sectionOptions: string;
@@ -101,6 +101,13 @@
101
101
  stepProperties: 'Step Properties',
102
102
  verifierProperties: 'Verifier Properties',
103
103
  notificationProperties: 'Notification Properties',
104
+ stepHelp: 'A step is one position in the chain. The record waits here until every verifier attached to this step has decided, then moves to the next one. Its number comes from the arrows between the steps, not from a field.',
105
+ verifierHelp: 'Who may decide a step. Connect it to a step — either direction — and every member of the role, or the one person you pick, is asked to approve.',
106
+ notificationHelp: 'Who hears about it. "Flow started" and "Flow completed" fire once for the whole flow wherever this node sits; the other three fire only for the step this node is connected to.',
107
+ stepOrderLabel: 'Position in the chain',
108
+ stepOrderUnset: 'set when you save',
109
+ canvasEmptyTitle: 'Draw the chain',
110
+ canvasEmptyBody: 'Drag a Step onto the canvas for each approval the record has to pass, connect the steps in order, then hang a Verifier on each step to say who decides it. A Notification node tells someone it happened.',
104
111
  sectionGeneral: 'General',
105
112
  sectionAssignment: 'Assignment',
106
113
  sectionOptions: 'Options',
@@ -47,6 +47,10 @@ export type VerificationFlowPageTheme = {
47
47
  container: string;
48
48
  background: string;
49
49
  dropIndicator: string;
50
+ /** What to draw, shown on an empty canvas. */
51
+ emptyHint: string;
52
+ emptyHintTitle: string;
53
+ emptyHintBody: string;
50
54
  };
51
55
  stepNode: {
52
56
  container: string;
@@ -90,6 +94,11 @@ export type VerificationFlowPageTheme = {
90
94
  headerTitle: string;
91
95
  closeButton: string;
92
96
  body: string;
97
+ /** One paragraph under the header saying what this kind of node does. */
98
+ help: string;
99
+ /** A fact the flow derives and the operator cannot type. */
100
+ readOnlyRow: string;
101
+ readOnlyValue: string;
93
102
  section: string;
94
103
  sectionTitle: string;
95
104
  label: string;
@@ -46,7 +46,10 @@ export const verificationFlowPageTheme = {
46
46
  canvas: {
47
47
  container: 'flex-1 relative bg-[#08080d]',
48
48
  background: 'bg-[#08080d]',
49
- dropIndicator: 'absolute inset-4 border-2 border-dashed border-white/10 rounded-2xl bg-white/[0.02] pointer-events-none z-10'
49
+ dropIndicator: 'absolute inset-4 border-2 border-dashed border-white/10 rounded-2xl bg-white/[0.02] pointer-events-none z-10',
50
+ emptyHint: 'pointer-events-none absolute left-1/2 top-1/2 z-10 w-[28rem] max-w-[calc(100%-3rem)] -translate-x-1/2 -translate-y-1/2 rounded-2xl border border-white/[0.08] bg-white/[0.04] px-6 py-5 text-center',
51
+ emptyHintTitle: 'text-[13px] font-semibold text-white/70',
52
+ emptyHintBody: 'mt-2 text-[12px] leading-relaxed text-white/40'
50
53
  },
51
54
  stepNode: {
52
55
  container: 'group relative rounded-2xl border border-blue-500/20 bg-gradient-to-br from-blue-500/[0.08] to-blue-600/[0.03] backdrop-blur-sm px-5 py-4 min-w-[200px] max-w-[260px] shadow-lg shadow-blue-500/[0.04] transition-all hover:border-blue-500/30 hover:shadow-blue-500/[0.08]',
@@ -90,6 +93,9 @@ export const verificationFlowPageTheme = {
90
93
  headerTitle: 'text-[12px] font-semibold text-white/80',
91
94
  closeButton: 'w-6 h-6 rounded-md flex items-center justify-center text-white/30 hover:text-white/60 hover:bg-white/[0.06] transition-all',
92
95
  body: 'flex-1 overflow-auto p-4 space-y-5',
96
+ help: 'rounded-lg bg-white/[0.04] px-3 py-2.5 text-[11px] leading-relaxed text-white/50',
97
+ readOnlyRow: 'flex items-baseline justify-between gap-3 rounded-lg bg-white/[0.04] px-3 py-2 text-[11px] text-white/50',
98
+ readOnlyValue: 'text-[12px] font-semibold tabular-nums text-white/80',
93
99
  section: 'space-y-2.5',
94
100
  sectionTitle: 'text-[10px] font-bold uppercase tracking-[0.15em] text-white/30 mb-2',
95
101
  label: 'block text-[11px] font-medium text-white/50 mb-1',
@@ -239,31 +245,55 @@ export const verificationFlowPageLightTheme = {
239
245
  canvas: {
240
246
  container: 'flex-1 relative bg-gray-50',
241
247
  background: 'bg-gray-50',
242
- dropIndicator: 'absolute inset-4 border-2 border-dashed border-gray-300 rounded-2xl bg-gray-100/50 pointer-events-none z-10'
248
+ dropIndicator: 'absolute inset-4 border-2 border-dashed border-gray-300 rounded-2xl bg-gray-100/50 pointer-events-none z-10',
249
+ emptyHint: 'pointer-events-none absolute left-1/2 top-1/2 z-10 w-[28rem] max-w-[calc(100%-3rem)] -translate-x-1/2 -translate-y-1/2 rounded-2xl border border-gray-200 bg-white px-6 py-5 text-center shadow-sm',
250
+ emptyHintTitle: 'text-[13px] font-semibold text-gray-800',
251
+ emptyHintBody: 'mt-2 text-[12px] leading-relaxed text-gray-500'
243
252
  },
244
- stepNode: {
253
+ /*
254
+ * The light nodes spread the dark ones and override the container, the type
255
+ * label, the name and the description — which left every BADGE and every
256
+ * HANDLE at its dark value on a white card. Measured: the order badge and
257
+ * the verifier's "role" chip came out around 1.5:1, i.e. the facts a node
258
+ * states were the least readable thing on it. Each light node now names
259
+ * its own badges and handles.
260
+ */ stepNode: {
245
261
  ...verificationFlowPageTheme.stepNode,
246
262
  container: 'group relative rounded-2xl border border-blue-200 bg-gradient-to-br from-blue-50 to-blue-100/50 px-5 py-4 min-w-[200px] max-w-[260px] shadow-sm transition-all hover:border-blue-300 hover:shadow-md',
247
263
  containerSelected: 'group relative rounded-2xl border-2 border-blue-400 bg-gradient-to-br from-blue-50 to-blue-100/50 px-5 py-4 min-w-[200px] max-w-[260px] shadow-md ring-4 ring-blue-100',
248
- typeLabel: 'text-[9px] font-bold uppercase tracking-[0.2em] text-blue-500',
264
+ icon: 'text-blue-600',
265
+ typeLabel: 'text-[9px] font-bold uppercase tracking-[0.2em] text-blue-600',
249
266
  nameLabel: 'text-[13px] font-semibold text-gray-800 mt-1.5 leading-tight',
250
- description: 'text-[11px] text-gray-500 mt-1 leading-relaxed line-clamp-2'
267
+ description: 'text-[11px] text-gray-500 mt-1 leading-relaxed line-clamp-2',
268
+ handleSource: '!w-3 !h-3 !bg-blue-500 !border-2 !border-white hover:!bg-blue-600',
269
+ handleTarget: '!w-3 !h-3 !bg-blue-500 !border-2 !border-white hover:!bg-blue-600',
270
+ orderBadge: 'absolute -top-2 -right-2 w-5 h-5 rounded-full bg-blue-600 text-[9px] font-bold text-white flex items-center justify-center'
251
271
  },
252
272
  verifierNode: {
253
273
  ...verificationFlowPageTheme.verifierNode,
254
274
  container: 'group relative rounded-2xl border border-amber-200 bg-gradient-to-br from-amber-50 to-orange-50 px-5 py-4 min-w-[200px] max-w-[260px] shadow-sm transition-all hover:border-amber-300 hover:shadow-md',
255
275
  containerSelected: 'group relative rounded-2xl border-2 border-amber-400 bg-gradient-to-br from-amber-50 to-orange-50 px-5 py-4 min-w-[200px] max-w-[260px] shadow-md ring-4 ring-amber-100',
276
+ icon: 'text-amber-600',
256
277
  typeLabel: 'text-[9px] font-bold uppercase tracking-[0.2em] text-amber-600',
257
278
  nameLabel: 'text-[13px] font-semibold text-gray-800 mt-1.5 leading-tight',
258
- description: 'text-[11px] text-gray-500 mt-1 leading-relaxed line-clamp-2'
279
+ description: 'text-[11px] text-gray-500 mt-1 leading-relaxed line-clamp-2',
280
+ assignedBadge: 'inline-flex items-center gap-1 rounded-md bg-amber-100 border border-amber-300 px-2 py-0.5 text-[10px] font-medium text-amber-800 mt-2',
281
+ signatureBadge: 'inline-flex items-center gap-1 rounded-md bg-rose-100 border border-rose-300 px-2 py-0.5 text-[10px] font-medium text-rose-800',
282
+ handleSource: '!w-3 !h-3 !bg-amber-500 !border-2 !border-white hover:!bg-amber-600',
283
+ handleTarget: '!w-3 !h-3 !bg-amber-500 !border-2 !border-white hover:!bg-amber-600'
259
284
  },
260
285
  notificationNode: {
261
286
  ...verificationFlowPageTheme.notificationNode,
262
287
  container: 'group relative rounded-2xl border border-violet-200 bg-gradient-to-br from-violet-50 to-purple-50 px-5 py-4 min-w-[200px] max-w-[260px] shadow-sm transition-all hover:border-violet-300 hover:shadow-md',
263
288
  containerSelected: 'group relative rounded-2xl border-2 border-violet-400 bg-gradient-to-br from-violet-50 to-purple-50 px-5 py-4 min-w-[200px] max-w-[260px] shadow-md ring-4 ring-violet-100',
289
+ icon: 'text-violet-600',
264
290
  typeLabel: 'text-[9px] font-bold uppercase tracking-[0.2em] text-violet-600',
265
291
  nameLabel: 'text-[13px] font-semibold text-gray-800 mt-1.5 leading-tight',
266
- description: 'text-[11px] text-gray-500 mt-1 leading-relaxed line-clamp-2'
292
+ description: 'text-[11px] text-gray-500 mt-1 leading-relaxed line-clamp-2',
293
+ channelBadge: 'inline-flex items-center rounded-md bg-violet-100 border border-violet-300 px-2 py-0.5 text-[10px] font-medium text-violet-800',
294
+ triggerBadge: 'inline-flex items-center rounded-md bg-gray-100 border border-gray-300 px-2 py-0.5 text-[10px] font-medium text-gray-700',
295
+ handleSource: '!w-3 !h-3 !bg-violet-500 !border-2 !border-white hover:!bg-violet-600',
296
+ handleTarget: '!w-3 !h-3 !bg-violet-500 !border-2 !border-white hover:!bg-violet-600'
267
297
  },
268
298
  propertiesPanel: {
269
299
  container: 'flex flex-col h-full',
@@ -271,6 +301,9 @@ export const verificationFlowPageLightTheme = {
271
301
  headerTitle: 'text-[12px] font-semibold text-gray-800',
272
302
  closeButton: 'w-6 h-6 rounded-md flex items-center justify-center text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-all',
273
303
  body: 'flex-1 overflow-auto p-4 space-y-5',
304
+ help: 'rounded-lg bg-gray-50 border border-gray-200 px-3 py-2.5 text-[11px] leading-relaxed text-gray-600',
305
+ readOnlyRow: 'flex items-baseline justify-between gap-3 rounded-lg bg-gray-50 border border-gray-200 px-3 py-2 text-[11px] text-gray-500',
306
+ readOnlyValue: 'text-[12px] font-semibold tabular-nums text-gray-800',
274
307
  section: 'space-y-2.5',
275
308
  sectionTitle: 'text-[10px] font-bold uppercase tracking-[0.15em] text-gray-400 mb-2',
276
309
  label: 'block text-[11px] font-medium text-gray-500 mb-1',