nucleus-core-ts 0.8.110 → 0.8.112

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.
@@ -206,11 +206,6 @@ export function NotificationFlowNode({ data }) {
206
206
  children: ch
207
207
  }, ch))
208
208
  ]
209
- }),
210
- /*#__PURE__*/ _jsx(Handle, {
211
- type: "source",
212
- position: Position.Right,
213
- className: theme.handleSource
214
209
  })
215
210
  ]
216
211
  });
@@ -75,10 +75,18 @@ function ChannelMultiSelect({ selected, onChange }) {
75
75
  return /*#__PURE__*/ _jsxs("div", {
76
76
  className: "relative",
77
77
  children: [
78
- /*#__PURE__*/ _jsxs("button", {
79
- type: "button",
80
- className: theme.container,
78
+ /*#__PURE__*/ _jsxs("div", {
79
+ role: "combobox",
80
+ tabIndex: 0,
81
+ "aria-expanded": isOpen,
82
+ className: `${theme.container} cursor-pointer`,
81
83
  onClick: ()=>setIsOpen(!isOpen),
84
+ onKeyDown: (e)=>{
85
+ if (e.key === "Enter" || e.key === " ") {
86
+ e.preventDefault();
87
+ setIsOpen(!isOpen);
88
+ }
89
+ },
82
90
  children: [
83
91
  selected.length === 0 && /*#__PURE__*/ _jsx("span", {
84
92
  className: "text-[10px] text-white/20",
@@ -88,13 +96,20 @@ function ChannelMultiSelect({ selected, onChange }) {
88
96
  className: theme.badge,
89
97
  children: [
90
98
  ch,
91
- /*#__PURE__*/ _jsx("button", {
92
- type: "button",
99
+ /*#__PURE__*/ _jsx("span", {
100
+ role: "button",
101
+ tabIndex: 0,
93
102
  className: theme.badgeRemove,
94
103
  onClick: (e)=>{
95
104
  e.stopPropagation();
96
105
  remove(ch);
97
106
  },
107
+ onKeyDown: (e)=>{
108
+ if (e.key === "Enter" || e.key === " ") {
109
+ e.stopPropagation();
110
+ remove(ch);
111
+ }
112
+ },
98
113
  children: "×"
99
114
  })
100
115
  ]
@@ -131,20 +146,23 @@ function UserSearchList({ listUsersAction, selectedUserId, onSelect }) {
131
146
  payload: {
132
147
  page: pageNum,
133
148
  limit: 20,
134
- search
149
+ search: search || undefined
135
150
  },
136
151
  onAfterHandle: (res)=>{
137
- const result = res;
138
- const newUsers = result.data?.data || [];
152
+ const resObj = res;
153
+ const dataObj = resObj.data;
154
+ const items = dataObj?.items || dataObj?.data || [];
155
+ const meta = dataObj?.meta;
156
+ const nextPage = meta?.hasNextPage === true || items.length >= 20;
139
157
  if (pageNum === 1) {
140
- setUsers(newUsers);
158
+ setUsers(items);
141
159
  } else {
142
160
  setUsers((prev)=>[
143
161
  ...prev,
144
- ...newUsers
162
+ ...items
145
163
  ]);
146
164
  }
147
- setHasMore(result.data?.hasMore || false);
165
+ setHasMore(nextPage && items.length > 0);
148
166
  setIsLoading(false);
149
167
  },
150
168
  onErrorHandle: ()=>{
@@ -234,20 +252,23 @@ function RoleSearchList({ listRolesAction, selectedRole, onSelect }) {
234
252
  payload: {
235
253
  page: pageNum,
236
254
  limit: 20,
237
- search
255
+ search: search || undefined
238
256
  },
239
257
  onAfterHandle: (res)=>{
240
- const result = res;
241
- const newRoles = result.data?.data || [];
258
+ const resObj = res;
259
+ const dataObj = resObj.data;
260
+ const items = dataObj?.items || dataObj?.data || [];
261
+ const meta = dataObj?.meta;
262
+ const nextPage = meta?.hasNextPage === true || items.length >= 20;
242
263
  if (pageNum === 1) {
243
- setRoles(newRoles);
264
+ setRoles(items);
244
265
  } else {
245
266
  setRoles((prev)=>[
246
267
  ...prev,
247
- ...newRoles
268
+ ...items
248
269
  ]);
249
270
  }
250
- setHasMore(result.data?.hasMore || false);
271
+ setHasMore(nextPage && items.length > 0);
251
272
  setIsLoading(false);
252
273
  },
253
274
  onErrorHandle: ()=>{
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { ReactFlow, Background, Controls, MiniMap, applyNodeChanges, applyEdgeChanges, addEdge, MarkerType } from "@xyflow/react";
4
4
  import "@xyflow/react/dist/style.css";
5
5
  import { useEffect, useEffectEvent, useRef, useState } from "react";
@@ -102,134 +102,6 @@ function edgesToFlow(flowEdges) {
102
102
  label: e.label || undefined
103
103
  }));
104
104
  }
105
- function generateDemoFlow() {
106
- const nodes = [
107
- {
108
- id: "start",
109
- type: "step",
110
- position: {
111
- x: 0,
112
- y: 100
113
- },
114
- data: {
115
- label: "Entity Created",
116
- nodeType: "step",
117
- stepOrder: 0,
118
- description: "Trigger: on create",
119
- selected: false
120
- }
121
- },
122
- {
123
- id: "review",
124
- type: "verifier",
125
- position: {
126
- x: 320,
127
- y: 50
128
- },
129
- data: {
130
- label: "Manager Approval",
131
- nodeType: "verifier",
132
- stepOrder: 1,
133
- description: "Role: manager",
134
- verifierType: "role",
135
- verifierRole: "manager",
136
- requireSignature: false,
137
- allMustApprove: false,
138
- selected: false
139
- }
140
- },
141
- {
142
- id: "qa",
143
- type: "verifier",
144
- position: {
145
- x: 320,
146
- y: 220
147
- },
148
- data: {
149
- label: "QA Check",
150
- nodeType: "verifier",
151
- stepOrder: 2,
152
- description: "Role: qa_team",
153
- verifierType: "role",
154
- verifierRole: "qa_team",
155
- requireSignature: true,
156
- allMustApprove: false,
157
- selected: false
158
- }
159
- },
160
- {
161
- id: "notify",
162
- type: "notification",
163
- position: {
164
- x: 640,
165
- y: 100
166
- },
167
- data: {
168
- label: "Notify Stakeholders",
169
- nodeType: "notification",
170
- stepOrder: 3,
171
- description: "Send alerts",
172
- trigger: "on_approved",
173
- channels: [
174
- "portal",
175
- "email"
176
- ],
177
- selected: false
178
- }
179
- },
180
- {
181
- id: "complete",
182
- type: "step",
183
- position: {
184
- x: 960,
185
- y: 100
186
- },
187
- data: {
188
- label: "Verified",
189
- nodeType: "step",
190
- stepOrder: 4,
191
- description: "Entity verified",
192
- selected: false
193
- }
194
- }
195
- ];
196
- const edges = [
197
- {
198
- id: "e1",
199
- source: "start",
200
- target: "review",
201
- ...defaultEdgeOptions
202
- },
203
- {
204
- id: "e2",
205
- source: "start",
206
- target: "qa",
207
- ...defaultEdgeOptions
208
- },
209
- {
210
- id: "e3",
211
- source: "review",
212
- target: "notify",
213
- ...defaultEdgeOptions
214
- },
215
- {
216
- id: "e4",
217
- source: "qa",
218
- target: "notify",
219
- ...defaultEdgeOptions
220
- },
221
- {
222
- id: "e5",
223
- source: "notify",
224
- target: "complete",
225
- ...defaultEdgeOptions
226
- }
227
- ];
228
- return {
229
- nodes,
230
- edges
231
- };
232
- }
233
105
  function createNewNode(nodeType, position) {
234
106
  const labels = {
235
107
  step: "New Step",
@@ -266,7 +138,7 @@ function createNewNode(nodeType, position) {
266
138
  }
267
139
  return base;
268
140
  }
269
- function buildSavePayload(flowId, nodes, edges) {
141
+ function buildSavePayload(flowId, entityName, flowName, flowDescription, triggerOn, isDraft, viewport, nodes, edges) {
270
142
  const steps = nodes.map((n)=>{
271
143
  const d = n.data;
272
144
  return {
@@ -337,6 +209,12 @@ function buildSavePayload(flowId, nodes, edges) {
337
209
  }
338
210
  return {
339
211
  flow_id: flowId,
212
+ entity_name: entityName,
213
+ name: flowName,
214
+ description: flowDescription,
215
+ trigger_on: triggerOn,
216
+ is_draft: isDraft,
217
+ viewport,
340
218
  graph: {
341
219
  steps,
342
220
  edges: flowEdges,
@@ -354,6 +232,9 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
354
232
  const [nodes, setNodes] = useState([]);
355
233
  const [edges, setEdges] = useState([]);
356
234
  const [isDraggingOver, setIsDraggingOver] = useState(false);
235
+ const [flowName, setFlowName] = useState("");
236
+ const [flowDescription, setFlowDescription] = useState("");
237
+ const [flowTriggerOn, setFlowTriggerOn] = useState("create");
357
238
  const reactFlowWrapper = useRef(null);
358
239
  const reactFlowInstance = useRef(null);
359
240
  const resolvedTitle = title || `${entityName} Verification`;
@@ -444,14 +325,26 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
444
325
  });
445
326
  // ─── Save & Publish ───────────────────────────────────────────
446
327
  const handleSave = useEffectEvent(()=>{
447
- if (!flowSaveAction || !store.selectedFlowId) return;
328
+ if (!flowSaveAction) return;
329
+ let flowId = store.selectedFlowId;
330
+ if (!flowId) {
331
+ flowId = crypto.randomUUID();
332
+ store.setSelectedFlowId(flowId);
333
+ }
334
+ const name = flowName || `${entityName} Flow`;
448
335
  store.setIsSaving(true);
449
- const payload = buildSavePayload(store.selectedFlowId, nodes, edges);
336
+ const viewport = reactFlowInstance.current ? reactFlowInstance.current.getViewport() : undefined;
337
+ const payload = buildSavePayload(flowId, entityName, name, flowDescription, flowTriggerOn, true, viewport, nodes, edges);
450
338
  flowSaveAction.start({
451
339
  payload: payload,
452
- onAfterHandle: ()=>{
340
+ onAfterHandle: (res)=>{
341
+ const resObj = res;
342
+ if (resObj.flow_id) {
343
+ store.setSelectedFlowId(resObj.flow_id);
344
+ }
453
345
  store.setIsSaving(false);
454
346
  store.setIsDirty(false);
347
+ loadFlows();
455
348
  },
456
349
  onErrorHandle: ()=>{
457
350
  store.setIsSaving(false);
@@ -473,9 +366,8 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
473
366
  const loadFlows = useEffectEvent(()=>{
474
367
  store.setLoadingFlows(true);
475
368
  const fallback = ()=>{
476
- const demo = generateDemoFlow();
477
- setNodes(demo.nodes);
478
- setEdges(demo.edges);
369
+ setNodes([]);
370
+ setEdges([]);
479
371
  store.setLoadingFlows(false);
480
372
  };
481
373
  flowListAction.start({
@@ -508,15 +400,20 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
508
400
  },
509
401
  onAfterHandle: (res)=>{
510
402
  const resObj = res;
403
+ const flow = resObj.data?.flow;
404
+ if (flow) {
405
+ setFlowName(flow.name || "");
406
+ setFlowDescription(flow.description || "");
407
+ setFlowTriggerOn(flow.trigger_on || "create");
408
+ }
511
409
  const graph = resObj.data?.graph;
512
410
  if (graph?.steps && graph.steps.length > 0) {
513
411
  store.setGraphData(graph);
514
412
  setNodes(stepsToNodes(graph.steps, graph, null));
515
413
  setEdges(edgesToFlow(graph.edges));
516
414
  } else {
517
- const demo = generateDemoFlow();
518
- setNodes(demo.nodes);
519
- setEdges(demo.edges);
415
+ setNodes([]);
416
+ setEdges([]);
520
417
  }
521
418
  store.setLoadingGraph(false);
522
419
  store.setIsDirty(false);
@@ -576,39 +473,91 @@ export function VerificationFlowPage({ entityName, title, subtitle, flowListActi
576
473
  })
577
474
  ]
578
475
  }),
579
- /*#__PURE__*/ _jsxs("div", {
476
+ /*#__PURE__*/ _jsx("div", {
580
477
  className: theme.header.actions,
581
- children: [
582
- store.activeTab === "flow" && store.flows.length > 0 && /*#__PURE__*/ _jsx("select", {
583
- className: theme.flowSelector.select,
584
- value: store.selectedFlowId || "",
585
- onChange: (e)=>{
586
- store.setSelectedFlowId(e.target.value);
587
- onFlowSelected?.(e.target.value);
588
- },
589
- children: store.flows.map((f)=>/*#__PURE__*/ _jsxs("option", {
590
- value: f.id,
591
- children: [
592
- f.name,
593
- " ",
594
- f.is_draft ? "(Draft)" : ""
595
- ]
596
- }, f.id))
597
- }),
598
- store.activeTab === "flow" && flowSaveAction && /*#__PURE__*/ _jsx("button", {
599
- type: "button",
600
- onClick: handleSave,
601
- disabled: store.isSaving || !store.isDirty,
602
- className: store.isDirty ? theme.header.saveButton : theme.header.saveButtonDisabled,
603
- children: store.isSaving ? "Saving..." : "Save"
604
- }),
605
- store.activeTab === "flow" && flowPublishAction && selectedFlow?.is_draft && /*#__PURE__*/ _jsx("button", {
606
- type: "button",
607
- onClick: handlePublish,
608
- className: theme.header.publishButton,
609
- children: "Publish"
610
- })
611
- ]
478
+ children: store.activeTab === "flow" && /*#__PURE__*/ _jsxs(_Fragment, {
479
+ children: [
480
+ store.flows.length > 0 && /*#__PURE__*/ _jsx("select", {
481
+ className: theme.flowSelector.select,
482
+ value: store.selectedFlowId || "",
483
+ onChange: (e)=>{
484
+ store.setSelectedFlowId(e.target.value);
485
+ onFlowSelected?.(e.target.value);
486
+ },
487
+ children: store.flows.map((f)=>/*#__PURE__*/ _jsxs("option", {
488
+ value: f.id,
489
+ children: [
490
+ f.name,
491
+ " ",
492
+ f.is_draft ? "(Draft)" : ""
493
+ ]
494
+ }, f.id))
495
+ }),
496
+ flowSaveAction && /*#__PURE__*/ _jsx("button", {
497
+ type: "button",
498
+ className: "px-2.5 py-1 text-[10px] rounded-md bg-white/[0.06] text-white/60 hover:bg-white/[0.1] border border-white/[0.06] transition-colors",
499
+ onClick: ()=>{
500
+ store.setSelectedFlowId(null);
501
+ setFlowName(`${entityName} Flow`);
502
+ setFlowDescription("");
503
+ setFlowTriggerOn("create");
504
+ setNodes([]);
505
+ setEdges([]);
506
+ store.setIsDirty(true);
507
+ },
508
+ children: "+ New Flow"
509
+ }),
510
+ /*#__PURE__*/ _jsx("input", {
511
+ type: "text",
512
+ className: "px-2.5 py-1 text-[10px] rounded-md bg-white/[0.04] text-white/80 border border-white/[0.08] w-36 placeholder:text-white/20",
513
+ placeholder: "Flow name...",
514
+ value: flowName,
515
+ onChange: (e)=>{
516
+ setFlowName(e.target.value);
517
+ store.setIsDirty(true);
518
+ }
519
+ }),
520
+ /*#__PURE__*/ _jsxs("select", {
521
+ className: "px-2 py-1 text-[10px] rounded-md bg-white/[0.04] text-white/60 border border-white/[0.08]",
522
+ value: flowTriggerOn,
523
+ onChange: (e)=>{
524
+ setFlowTriggerOn(e.target.value);
525
+ store.setIsDirty(true);
526
+ },
527
+ children: [
528
+ /*#__PURE__*/ _jsx("option", {
529
+ value: "create",
530
+ children: "On Create"
531
+ }),
532
+ /*#__PURE__*/ _jsx("option", {
533
+ value: "update",
534
+ children: "On Update"
535
+ }),
536
+ /*#__PURE__*/ _jsx("option", {
537
+ value: "delete",
538
+ children: "On Delete"
539
+ }),
540
+ /*#__PURE__*/ _jsx("option", {
541
+ value: "manual",
542
+ children: "Manual"
543
+ })
544
+ ]
545
+ }),
546
+ flowSaveAction && /*#__PURE__*/ _jsx("button", {
547
+ type: "button",
548
+ onClick: handleSave,
549
+ disabled: store.isSaving || !store.isDirty,
550
+ className: store.isDirty ? theme.header.saveButton : theme.header.saveButtonDisabled,
551
+ children: store.isSaving ? "Saving..." : "Save"
552
+ }),
553
+ flowPublishAction && selectedFlow?.is_draft && /*#__PURE__*/ _jsx("button", {
554
+ type: "button",
555
+ onClick: handlePublish,
556
+ className: theme.header.publishButton,
557
+ children: "Publish"
558
+ })
559
+ ]
560
+ })
612
561
  })
613
562
  ]
614
563
  }),
@@ -141,8 +141,8 @@ export type PaginatedResponse<T> = {
141
141
  limit: number;
142
142
  hasMore: boolean;
143
143
  };
144
- export type ListUsersAction = GenericAction<PaginatedPayload, PaginatedResponse<UserItem>>;
145
- export type ListRolesAction = GenericAction<PaginatedPayload, PaginatedResponse<RoleItem>>;
144
+ export type ListUsersAction = GenericAction<any, any>;
145
+ export type ListRolesAction = GenericAction<any, any>;
146
146
  export type PendingItem = {
147
147
  instance_id: string;
148
148
  entity_name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.8.110",
3
+ "version": "0.8.112",
4
4
  "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
5
  "author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -69,7 +69,7 @@
69
69
  "@types/three": "latest",
70
70
  "bun-plugin-tailwind": "latest",
71
71
  "drizzle-kit": "latest",
72
- "javascript-obfuscator": "^4.2.2",
72
+ "javascript-obfuscator": "latest",
73
73
  "lucide-react": "latest",
74
74
  "three": "latest"
75
75
  },
@@ -88,7 +88,7 @@
88
88
  "@elysiajs/static": "latest",
89
89
  "@elysiajs/swagger": "latest",
90
90
  "@gsap/react": "latest",
91
- "@xyflow/react": "^12.10.1",
91
+ "@xyflow/react": "latest",
92
92
  "drizzle-orm": "latest",
93
93
  "googleapis": "latest",
94
94
  "gsap": "latest",