@dilipod/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.
- package/dist/components/flowchart-diagram.d.ts +8 -0
- package/dist/components/flowchart-diagram.d.ts.map +1 -0
- package/dist/components/impact-metrics-form.d.ts.map +1 -1
- package/dist/components/scenarios-manager.d.ts.map +1 -1
- package/dist/components/worker-spec.d.ts +35 -0
- package/dist/components/worker-spec.d.ts.map +1 -0
- package/dist/components/workflow-viewer.d.ts +1 -1
- package/dist/components/workflow-viewer.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +444 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +444 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/flowchart-diagram.tsx +319 -0
- package/src/components/impact-metrics-form.tsx +17 -6
- package/src/components/scenarios-manager.tsx +3 -0
- package/src/components/worker-spec.tsx +389 -0
- package/src/components/workflow-viewer.tsx +1 -1
- package/src/index.ts +8 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { useState } from 'react'
|
|
5
|
+
import {
|
|
6
|
+
Target,
|
|
7
|
+
Crosshair,
|
|
8
|
+
ListNumbers,
|
|
9
|
+
TreeStructure,
|
|
10
|
+
Lightning,
|
|
11
|
+
Wrench,
|
|
12
|
+
Plugs,
|
|
13
|
+
ShieldCheck,
|
|
14
|
+
CaretDown,
|
|
15
|
+
CaretRight,
|
|
16
|
+
Clock,
|
|
17
|
+
TrendUp,
|
|
18
|
+
CurrencyEur,
|
|
19
|
+
Sparkle,
|
|
20
|
+
Lightbulb,
|
|
21
|
+
Robot,
|
|
22
|
+
} from '@phosphor-icons/react'
|
|
23
|
+
import { FlowchartDiagram } from './flowchart-diagram'
|
|
24
|
+
import { Badge } from './badge'
|
|
25
|
+
|
|
26
|
+
// ============================================
|
|
27
|
+
// Types
|
|
28
|
+
// ============================================
|
|
29
|
+
|
|
30
|
+
export interface WorkerSpecDocumentation {
|
|
31
|
+
scope: string | null
|
|
32
|
+
goal: string | null
|
|
33
|
+
steps: Array<{
|
|
34
|
+
step: number
|
|
35
|
+
title: string
|
|
36
|
+
description: string
|
|
37
|
+
tools_used?: string[]
|
|
38
|
+
}> | null
|
|
39
|
+
diagram: string | null
|
|
40
|
+
expected_impact: {
|
|
41
|
+
time_saved_per_occurrence_minutes: number
|
|
42
|
+
frequency: string
|
|
43
|
+
yearly_hours_saved: number
|
|
44
|
+
yearly_cost_savings_euros: number
|
|
45
|
+
qualitative_benefits: string[]
|
|
46
|
+
} | null
|
|
47
|
+
technical_requirements: string[] | null
|
|
48
|
+
integration_points: string[] | null
|
|
49
|
+
edge_cases_handled: Array<{
|
|
50
|
+
scenario: string
|
|
51
|
+
handling: string
|
|
52
|
+
}> | null
|
|
53
|
+
version: number
|
|
54
|
+
model_used: string | null
|
|
55
|
+
updated_at: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface WorkerSpecProps {
|
|
59
|
+
/** The Knowledge Builder final documentation */
|
|
60
|
+
documentation: WorkerSpecDocumentation | null
|
|
61
|
+
/** Optional className for the container */
|
|
62
|
+
className?: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ============================================
|
|
66
|
+
// Frequency labels for impact display
|
|
67
|
+
// ============================================
|
|
68
|
+
|
|
69
|
+
const frequencyLabels: Record<string, string> = {
|
|
70
|
+
multiple_daily: 'occurrence',
|
|
71
|
+
daily: 'day',
|
|
72
|
+
weekly: 'week',
|
|
73
|
+
monthly: 'month',
|
|
74
|
+
quarterly: 'quarter',
|
|
75
|
+
yearly: 'year',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ============================================
|
|
79
|
+
// Section Header Component
|
|
80
|
+
// ============================================
|
|
81
|
+
|
|
82
|
+
function SectionHeader({
|
|
83
|
+
icon,
|
|
84
|
+
title,
|
|
85
|
+
count,
|
|
86
|
+
expanded,
|
|
87
|
+
onToggle,
|
|
88
|
+
iconColor = 'text-[var(--cyan)]',
|
|
89
|
+
}: {
|
|
90
|
+
icon: React.ReactNode
|
|
91
|
+
title: string
|
|
92
|
+
count?: number
|
|
93
|
+
expanded: boolean
|
|
94
|
+
onToggle: () => void
|
|
95
|
+
iconColor?: string
|
|
96
|
+
}) {
|
|
97
|
+
return (
|
|
98
|
+
<button
|
|
99
|
+
onClick={onToggle}
|
|
100
|
+
className="flex items-center gap-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide hover:text-[var(--black)] transition-colors w-full"
|
|
101
|
+
>
|
|
102
|
+
{expanded ? <CaretDown size={12} /> : <CaretRight size={12} />}
|
|
103
|
+
<span className={iconColor}>{icon}</span>
|
|
104
|
+
{title}
|
|
105
|
+
{count !== undefined && (
|
|
106
|
+
<span className="text-muted-foreground font-normal">({count})</span>
|
|
107
|
+
)}
|
|
108
|
+
</button>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ============================================
|
|
113
|
+
// Main Component
|
|
114
|
+
// ============================================
|
|
115
|
+
|
|
116
|
+
export function WorkerSpec({ documentation, className }: WorkerSpecProps) {
|
|
117
|
+
const [expandedSections, setExpandedSections] = useState<Set<string>>(
|
|
118
|
+
new Set(['goal', 'scope', 'steps', 'diagram', 'impact', 'requirements', 'edge_cases'])
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
const toggleSection = (section: string) => {
|
|
122
|
+
setExpandedSections(prev => {
|
|
123
|
+
const next = new Set(prev)
|
|
124
|
+
if (next.has(section)) {
|
|
125
|
+
next.delete(section)
|
|
126
|
+
} else {
|
|
127
|
+
next.add(section)
|
|
128
|
+
}
|
|
129
|
+
return next
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Empty state
|
|
134
|
+
if (!documentation) {
|
|
135
|
+
return (
|
|
136
|
+
<div className={className}>
|
|
137
|
+
<div className="flex items-center gap-3 p-6 rounded-sm border border-dashed border-gray-300 bg-gray-50/50">
|
|
138
|
+
<div className="w-10 h-10 rounded-sm bg-gray-100 flex items-center justify-center">
|
|
139
|
+
<Robot size={20} className="text-gray-400" />
|
|
140
|
+
</div>
|
|
141
|
+
<div>
|
|
142
|
+
<h3 className="font-semibold text-[var(--black)]">Worker Spec Pending</h3>
|
|
143
|
+
<p className="text-sm text-muted-foreground">
|
|
144
|
+
The final specification will be generated automatically after the documentation is approved.
|
|
145
|
+
</p>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const freqLabel = documentation.expected_impact?.frequency
|
|
153
|
+
? frequencyLabels[documentation.expected_impact.frequency] || documentation.expected_impact.frequency
|
|
154
|
+
: 'occurrence'
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<div className={className}>
|
|
158
|
+
<div className="space-y-5">
|
|
159
|
+
{/* Goal */}
|
|
160
|
+
{documentation.goal && (
|
|
161
|
+
<div>
|
|
162
|
+
<SectionHeader
|
|
163
|
+
icon={<Target size={12} weight="fill" />}
|
|
164
|
+
title="Goal"
|
|
165
|
+
expanded={expandedSections.has('goal')}
|
|
166
|
+
onToggle={() => toggleSection('goal')}
|
|
167
|
+
/>
|
|
168
|
+
{expandedSections.has('goal') && (
|
|
169
|
+
<p className="text-sm text-muted-foreground leading-relaxed pl-5 mt-2">
|
|
170
|
+
{documentation.goal}
|
|
171
|
+
</p>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
)}
|
|
175
|
+
|
|
176
|
+
{/* Scope */}
|
|
177
|
+
{documentation.scope && (
|
|
178
|
+
<div>
|
|
179
|
+
<SectionHeader
|
|
180
|
+
icon={<Crosshair size={12} weight="fill" />}
|
|
181
|
+
title="Scope"
|
|
182
|
+
expanded={expandedSections.has('scope')}
|
|
183
|
+
onToggle={() => toggleSection('scope')}
|
|
184
|
+
/>
|
|
185
|
+
{expandedSections.has('scope') && (
|
|
186
|
+
<p className="text-sm text-muted-foreground leading-relaxed pl-5 mt-2">
|
|
187
|
+
{documentation.scope}
|
|
188
|
+
</p>
|
|
189
|
+
)}
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
{/* Detailed Steps */}
|
|
194
|
+
{documentation.steps && documentation.steps.length > 0 && (
|
|
195
|
+
<div>
|
|
196
|
+
<SectionHeader
|
|
197
|
+
icon={<ListNumbers size={12} weight="fill" />}
|
|
198
|
+
title="Steps"
|
|
199
|
+
count={documentation.steps.length}
|
|
200
|
+
expanded={expandedSections.has('steps')}
|
|
201
|
+
onToggle={() => toggleSection('steps')}
|
|
202
|
+
/>
|
|
203
|
+
{expandedSections.has('steps') && (
|
|
204
|
+
<div className="space-y-3 pl-5 mt-2">
|
|
205
|
+
{documentation.steps.map((step, i) => (
|
|
206
|
+
<div key={i} className="flex items-start gap-3">
|
|
207
|
+
<span className="w-6 h-6 rounded-sm bg-[var(--cyan)]/10 flex items-center justify-center text-xs font-bold text-[var(--cyan)] shrink-0 mt-0.5">
|
|
208
|
+
{step.step || i + 1}
|
|
209
|
+
</span>
|
|
210
|
+
<div className="flex-1 min-w-0">
|
|
211
|
+
<p className="text-sm font-medium text-[var(--black)]">{step.title}</p>
|
|
212
|
+
<p className="text-sm text-muted-foreground mt-0.5">{step.description}</p>
|
|
213
|
+
{step.tools_used && step.tools_used.length > 0 && (
|
|
214
|
+
<div className="flex flex-wrap gap-1 mt-1.5">
|
|
215
|
+
{step.tools_used.map((tool, j) => (
|
|
216
|
+
<span key={j} className="inline-flex items-center gap-1 px-2 py-0.5 rounded-sm bg-gray-100 text-[10px] font-medium text-gray-600">
|
|
217
|
+
<Wrench size={10} />
|
|
218
|
+
{tool}
|
|
219
|
+
</span>
|
|
220
|
+
))}
|
|
221
|
+
</div>
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
))}
|
|
226
|
+
</div>
|
|
227
|
+
)}
|
|
228
|
+
</div>
|
|
229
|
+
)}
|
|
230
|
+
|
|
231
|
+
{/* Workflow Diagram */}
|
|
232
|
+
{documentation.diagram && (
|
|
233
|
+
<div>
|
|
234
|
+
<SectionHeader
|
|
235
|
+
icon={<TreeStructure size={12} weight="fill" />}
|
|
236
|
+
title="Workflow Diagram"
|
|
237
|
+
expanded={expandedSections.has('diagram')}
|
|
238
|
+
onToggle={() => toggleSection('diagram')}
|
|
239
|
+
iconColor="text-purple-500"
|
|
240
|
+
/>
|
|
241
|
+
{expandedSections.has('diagram') && (
|
|
242
|
+
<div className="pl-5 mt-2">
|
|
243
|
+
<div className="bg-white border border-gray-100 rounded-sm p-4 overflow-x-auto">
|
|
244
|
+
<FlowchartDiagram mermaid={documentation.diagram} />
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
)}
|
|
248
|
+
</div>
|
|
249
|
+
)}
|
|
250
|
+
|
|
251
|
+
{/* Expected Impact */}
|
|
252
|
+
{documentation.expected_impact && (
|
|
253
|
+
<div>
|
|
254
|
+
<SectionHeader
|
|
255
|
+
icon={<Lightning size={12} weight="fill" />}
|
|
256
|
+
title="Expected Impact"
|
|
257
|
+
expanded={expandedSections.has('impact')}
|
|
258
|
+
onToggle={() => toggleSection('impact')}
|
|
259
|
+
iconColor="text-purple-500"
|
|
260
|
+
/>
|
|
261
|
+
{expandedSections.has('impact') && (
|
|
262
|
+
<div className="pl-5 mt-2">
|
|
263
|
+
<div className="bg-emerald-50/50 border border-emerald-100 rounded-sm p-4">
|
|
264
|
+
<div className="grid grid-cols-3 gap-3 mb-3">
|
|
265
|
+
<div className="bg-white rounded-sm p-3 border border-emerald-100 text-center">
|
|
266
|
+
<Clock size={18} className="text-emerald-600 mx-auto mb-1" />
|
|
267
|
+
<p className="text-lg font-bold text-[var(--black)]">
|
|
268
|
+
{documentation.expected_impact.time_saved_per_occurrence_minutes} min
|
|
269
|
+
</p>
|
|
270
|
+
<p className="text-[10px] text-muted-foreground">saved per {freqLabel}</p>
|
|
271
|
+
</div>
|
|
272
|
+
<div className="bg-white rounded-sm p-3 border border-emerald-100 text-center">
|
|
273
|
+
<TrendUp size={18} className="text-emerald-600 mx-auto mb-1" />
|
|
274
|
+
<p className="text-lg font-bold text-[var(--black)]">
|
|
275
|
+
{documentation.expected_impact.yearly_hours_saved}h
|
|
276
|
+
</p>
|
|
277
|
+
<p className="text-[10px] text-muted-foreground">saved per year</p>
|
|
278
|
+
</div>
|
|
279
|
+
<div className="bg-white rounded-sm p-3 border border-emerald-100 text-center">
|
|
280
|
+
<CurrencyEur size={18} className="text-emerald-600 mx-auto mb-1" />
|
|
281
|
+
<p className="text-lg font-bold text-[var(--black)]">
|
|
282
|
+
€{documentation.expected_impact.yearly_cost_savings_euros.toLocaleString()}
|
|
283
|
+
</p>
|
|
284
|
+
<p className="text-[10px] text-muted-foreground">estimated yearly savings</p>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
{documentation.expected_impact.qualitative_benefits && documentation.expected_impact.qualitative_benefits.length > 0 && (
|
|
288
|
+
<div className="space-y-1">
|
|
289
|
+
{documentation.expected_impact.qualitative_benefits.map((benefit, i) => (
|
|
290
|
+
<div key={i} className="flex items-start gap-2 text-sm text-emerald-700">
|
|
291
|
+
<Sparkle size={14} className="text-emerald-500 shrink-0 mt-0.5" weight="fill" />
|
|
292
|
+
{benefit}
|
|
293
|
+
</div>
|
|
294
|
+
))}
|
|
295
|
+
</div>
|
|
296
|
+
)}
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
)}
|
|
300
|
+
</div>
|
|
301
|
+
)}
|
|
302
|
+
|
|
303
|
+
{/* Technical Requirements & Integration Points */}
|
|
304
|
+
{((documentation.technical_requirements && documentation.technical_requirements.length > 0) ||
|
|
305
|
+
(documentation.integration_points && documentation.integration_points.length > 0)) && (
|
|
306
|
+
<div>
|
|
307
|
+
<SectionHeader
|
|
308
|
+
icon={<Plugs size={12} weight="fill" />}
|
|
309
|
+
title="Requirements & Integrations"
|
|
310
|
+
expanded={expandedSections.has('requirements')}
|
|
311
|
+
onToggle={() => toggleSection('requirements')}
|
|
312
|
+
/>
|
|
313
|
+
{expandedSections.has('requirements') && (
|
|
314
|
+
<div className="grid md:grid-cols-2 gap-4 pl-5 mt-2">
|
|
315
|
+
{documentation.technical_requirements && documentation.technical_requirements.length > 0 && (
|
|
316
|
+
<div>
|
|
317
|
+
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2">
|
|
318
|
+
Technical Requirements
|
|
319
|
+
</p>
|
|
320
|
+
<ul className="space-y-1.5">
|
|
321
|
+
{documentation.technical_requirements.map((req, i) => (
|
|
322
|
+
<li key={i} className="flex items-start gap-2 text-sm text-muted-foreground">
|
|
323
|
+
<Wrench size={12} className="text-gray-400 shrink-0 mt-1" />
|
|
324
|
+
{req}
|
|
325
|
+
</li>
|
|
326
|
+
))}
|
|
327
|
+
</ul>
|
|
328
|
+
</div>
|
|
329
|
+
)}
|
|
330
|
+
{documentation.integration_points && documentation.integration_points.length > 0 && (
|
|
331
|
+
<div>
|
|
332
|
+
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2">
|
|
333
|
+
Integration Points
|
|
334
|
+
</p>
|
|
335
|
+
<ul className="space-y-1.5">
|
|
336
|
+
{documentation.integration_points.map((point, i) => (
|
|
337
|
+
<li key={i} className="flex items-start gap-2 text-sm text-muted-foreground">
|
|
338
|
+
<Plugs size={12} className="text-gray-400 shrink-0 mt-1" />
|
|
339
|
+
{point}
|
|
340
|
+
</li>
|
|
341
|
+
))}
|
|
342
|
+
</ul>
|
|
343
|
+
</div>
|
|
344
|
+
)}
|
|
345
|
+
</div>
|
|
346
|
+
)}
|
|
347
|
+
</div>
|
|
348
|
+
)}
|
|
349
|
+
|
|
350
|
+
{/* Edge Cases Handled */}
|
|
351
|
+
{documentation.edge_cases_handled && documentation.edge_cases_handled.length > 0 && (
|
|
352
|
+
<div>
|
|
353
|
+
<SectionHeader
|
|
354
|
+
icon={<ShieldCheck size={12} weight="fill" />}
|
|
355
|
+
title="Edge Cases Handled"
|
|
356
|
+
count={documentation.edge_cases_handled.length}
|
|
357
|
+
expanded={expandedSections.has('edge_cases')}
|
|
358
|
+
onToggle={() => toggleSection('edge_cases')}
|
|
359
|
+
iconColor="text-amber-500"
|
|
360
|
+
/>
|
|
361
|
+
{expandedSections.has('edge_cases') && (
|
|
362
|
+
<div className="space-y-2 pl-5 mt-2">
|
|
363
|
+
{documentation.edge_cases_handled.map((ec, i) => (
|
|
364
|
+
<div key={i} className="text-sm p-3 bg-gray-50 rounded-sm border border-gray-100">
|
|
365
|
+
<p className="font-medium text-[var(--black)]">{ec.scenario}</p>
|
|
366
|
+
<p className="text-muted-foreground mt-1">→ {ec.handling}</p>
|
|
367
|
+
</div>
|
|
368
|
+
))}
|
|
369
|
+
</div>
|
|
370
|
+
)}
|
|
371
|
+
</div>
|
|
372
|
+
)}
|
|
373
|
+
|
|
374
|
+
{/* Version footer */}
|
|
375
|
+
<div className="pt-3 border-t border-gray-100 flex items-center gap-2 text-xs text-muted-foreground">
|
|
376
|
+
<Badge variant="outline" size="sm">v{documentation.version}</Badge>
|
|
377
|
+
{documentation.model_used && (
|
|
378
|
+
<>
|
|
379
|
+
<span>•</span>
|
|
380
|
+
<span>{documentation.model_used}</span>
|
|
381
|
+
</>
|
|
382
|
+
)}
|
|
383
|
+
<span>•</span>
|
|
384
|
+
<span>Updated {new Date(documentation.updated_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}</span>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
)
|
|
389
|
+
}
|
|
@@ -97,7 +97,7 @@ export interface SimWorkflow {
|
|
|
97
97
|
}>
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export type WorkflowTemplate = 'blank' | 'request_analyzer' | '
|
|
100
|
+
export type WorkflowTemplate = 'blank' | 'request_analyzer' | 'knowledge_builder' | 'execution_monitor' | 'usage_reporter' | 'custom'
|
|
101
101
|
|
|
102
102
|
export interface WorkflowViewerProps {
|
|
103
103
|
/** The workflow definition to display */
|
package/src/index.ts
CHANGED
|
@@ -293,6 +293,14 @@ export type {
|
|
|
293
293
|
WorkflowTemplate
|
|
294
294
|
} from './components/workflow-viewer'
|
|
295
295
|
|
|
296
|
+
// Worker Spec Components
|
|
297
|
+
export { WorkerSpec } from './components/worker-spec'
|
|
298
|
+
export type { WorkerSpecProps, WorkerSpecDocumentation } from './components/worker-spec'
|
|
299
|
+
|
|
300
|
+
// Flowchart Diagram Components
|
|
301
|
+
export { FlowchartDiagram } from './components/flowchart-diagram'
|
|
302
|
+
export type { FlowchartDiagramProps } from './components/flowchart-diagram'
|
|
303
|
+
|
|
296
304
|
// Utilities
|
|
297
305
|
export { cn } from './lib/utils'
|
|
298
306
|
|