@startsimpli/ui 0.4.21 → 0.4.23

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.
@@ -0,0 +1,151 @@
1
+ 'use client';
2
+
3
+ import { useMemo } from 'react';
4
+ import { Hash, User, StickyNote, Boxes } from 'lucide-react';
5
+ import { cn } from '../../lib/utils';
6
+ import { Badge } from '../ui/badge';
7
+
8
+ /**
9
+ * Minimal, in-package shape of a workflow version. Mirrors the subset of the
10
+ * backend version record the history view actually reads — kept local so the
11
+ * component carries no app type coupling.
12
+ */
13
+ export interface WorkflowVersion {
14
+ uuid: string;
15
+ versionNumber: number;
16
+ timestamp: string;
17
+ isPublished?: boolean;
18
+ versionNote?: string | null;
19
+ createdBy?: {
20
+ firstName?: string | null;
21
+ lastName?: string | null;
22
+ email: string;
23
+ } | null;
24
+ /** Opaque workflow definition; only `nodes.length` is read for display. */
25
+ workflowData?: Record<string, unknown> | null;
26
+ }
27
+
28
+ export interface WorkflowVersionHistoryProps {
29
+ versions: WorkflowVersion[];
30
+ /**
31
+ * Formats a version's ISO timestamp for display. Supplied by the consumer
32
+ * so this component stays free of date/locale dependencies. Defaults to the
33
+ * raw timestamp string when omitted.
34
+ */
35
+ formatTimestamp?: (timestamp: string) => string;
36
+ className?: string;
37
+ }
38
+
39
+ export function WorkflowVersionHistory({
40
+ versions,
41
+ formatTimestamp,
42
+ className,
43
+ }: WorkflowVersionHistoryProps) {
44
+ const sorted = useMemo(
45
+ () => [...versions].sort((a, b) => b.versionNumber - a.versionNumber),
46
+ [versions]
47
+ );
48
+
49
+ if (versions.length === 0) {
50
+ return (
51
+ <div className={cn('text-center py-12', className)}>
52
+ <Hash className="h-12 w-12 mx-auto mb-3 text-muted-foreground" />
53
+ <h3 className="text-lg font-semibold mb-2">No Versions Yet</h3>
54
+ <p className="text-muted-foreground max-w-sm mx-auto">
55
+ No versions published yet. Use the canvas toolbar to publish a
56
+ version.
57
+ </p>
58
+ </div>
59
+ );
60
+ }
61
+
62
+ const formatTime = formatTimestamp ?? ((t: string) => t);
63
+
64
+ return (
65
+ <ol className={cn('relative space-y-6', className)}>
66
+ {sorted.map((version, index) => {
67
+ const label = version.versionNote
68
+ ? `v${version.versionNumber} — ${version.versionNote}`
69
+ : `v${version.versionNumber}`;
70
+
71
+ const nodeCount =
72
+ version.workflowData &&
73
+ Array.isArray(
74
+ (version.workflowData as Record<string, unknown>).nodes
75
+ )
76
+ ? (
77
+ (version.workflowData as Record<string, unknown>)
78
+ .nodes as unknown[]
79
+ ).length
80
+ : null;
81
+
82
+ const isLast = index === sorted.length - 1;
83
+
84
+ return (
85
+ <li key={version.uuid} className="relative pl-8">
86
+ {/* Timeline rail + dot */}
87
+ {!isLast && (
88
+ <span
89
+ className="absolute left-[7px] top-5 bottom-[-1.5rem] w-px bg-border"
90
+ aria-hidden="true"
91
+ />
92
+ )}
93
+ <span
94
+ className={cn(
95
+ 'absolute left-0 top-1 h-3.5 w-3.5 rounded-full border-2',
96
+ version.isPublished
97
+ ? 'border-green-500 bg-green-500'
98
+ : 'border-muted-foreground bg-background'
99
+ )}
100
+ aria-hidden="true"
101
+ />
102
+
103
+ <div className="flex items-center justify-between gap-2">
104
+ <span className="font-medium text-sm">{label}</span>
105
+ <span className="text-xs text-muted-foreground">
106
+ {formatTime(version.timestamp)}
107
+ </span>
108
+ </div>
109
+
110
+ <div className="mt-2 space-y-2 text-sm">
111
+ {version.isPublished && (
112
+ <div>
113
+ <Badge
114
+ variant="outline"
115
+ className="border-green-200 bg-green-50 text-green-700 dark:border-green-800 dark:bg-green-950/30 dark:text-green-400"
116
+ >
117
+ Published
118
+ </Badge>
119
+ </div>
120
+ )}
121
+ {version.createdBy && (
122
+ <div className="flex items-center gap-2 text-muted-foreground">
123
+ <User className="h-3.5 w-3.5 shrink-0" />
124
+ <span>
125
+ {version.createdBy.firstName
126
+ ? `${version.createdBy.firstName} ${version.createdBy.lastName ?? ''}`.trim()
127
+ : version.createdBy.email}
128
+ </span>
129
+ </div>
130
+ )}
131
+ {version.versionNote && (
132
+ <div className="flex items-start gap-2 text-muted-foreground">
133
+ <StickyNote className="h-3.5 w-3.5 shrink-0 mt-0.5" />
134
+ <span>{version.versionNote}</span>
135
+ </div>
136
+ )}
137
+ {nodeCount !== null && (
138
+ <div className="flex items-center gap-2 text-muted-foreground">
139
+ <Boxes className="h-3.5 w-3.5 shrink-0" />
140
+ <span>
141
+ {nodeCount} node{nodeCount !== 1 ? 's' : ''}
142
+ </span>
143
+ </div>
144
+ )}
145
+ </div>
146
+ </li>
147
+ );
148
+ })}
149
+ </ol>
150
+ );
151
+ }
@@ -76,3 +76,36 @@ export { useNodeStatusOverlay } from './hooks/useNodeStatusOverlay';
76
76
 
77
77
  // Category icon resolver (lucide)
78
78
  export { getCategoryIcon } from './node-icons';
79
+
80
+ // Page composers — zero-coupling workflow UI (empty-state guidance + version history)
81
+ export { WorkflowEmptyState, useWorkflowEmptyState } from './WorkflowEmptyState';
82
+ export type { WorkflowEmptyStateProps } from './WorkflowEmptyState';
83
+ export { WorkflowVersionHistory } from './WorkflowVersionHistory';
84
+ export type {
85
+ WorkflowVersion,
86
+ WorkflowVersionHistoryProps,
87
+ } from './WorkflowVersionHistory';
88
+
89
+ // Page composers — workflow settings, stats, list, and template gallery
90
+ export { WorkflowSettingsCard } from './WorkflowSettingsCard';
91
+ export type { WorkflowSettingsCardProps } from './WorkflowSettingsCard';
92
+ export { WorkflowStatsOverview } from './WorkflowStatsOverview';
93
+ export type {
94
+ WorkflowStats,
95
+ WorkflowStatsOverviewProps,
96
+ } from './WorkflowStatsOverview';
97
+ export { WorkflowListComposer } from './WorkflowListComposer';
98
+ export type {
99
+ WorkflowListItem,
100
+ WorkflowCreateInput,
101
+ WorkflowListComposerProps,
102
+ } from './WorkflowListComposer';
103
+ export {
104
+ WorkflowTemplateGallery,
105
+ WORKFLOW_TEMPLATES,
106
+ } from './WorkflowTemplateGallery';
107
+ export type {
108
+ WorkflowTemplate,
109
+ WorkflowTemplateDefinition,
110
+ WorkflowTemplateGalleryProps,
111
+ } from './WorkflowTemplateGallery';