@growthub/cli 0.13.6 → 0.13.7
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/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/metadata-graph/route.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceActivationPanel.jsx +172 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/NangoConnectionPanel.jsx +37 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +170 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +44 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +537 -39
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +8 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-activation.js +534 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-store.js +82 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +3 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/seeded-configs/project-management.config.json +4 -4
- package/package.json +1 -1
|
@@ -152,6 +152,7 @@ async function GET(request) {
|
|
|
152
152
|
runs: metadataStore.runs,
|
|
153
153
|
outputArtifacts: metadataStore.outputArtifacts,
|
|
154
154
|
workerKits: metadataStore.workerKits,
|
|
155
|
+
provenance: metadataStore.provenance,
|
|
155
156
|
pipelineHealth: metadataStore.pipelineHealth
|
|
156
157
|
},
|
|
157
158
|
graph: {
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* WorkspaceActivationPanel — customer activation checklist.
|
|
5
|
+
*
|
|
6
|
+
* Renders the derived activation state from
|
|
7
|
+
* `lib/workspace-activation.js` as a goal-first checklist with deep links
|
|
8
|
+
* into the existing surfaces. The panel is read-only; every step routes
|
|
9
|
+
* through routes the workspace already owns.
|
|
10
|
+
*
|
|
11
|
+
* Props:
|
|
12
|
+
* workspaceConfig — parsed growthub.config.json (governed)
|
|
13
|
+
* workspaceSourceRecords — parsed growthub.source-records.json (sidecar)
|
|
14
|
+
* metadataGraph — optional metadata graph envelope
|
|
15
|
+
* onOpenHelper — optional helper-thread CTA handler
|
|
16
|
+
* compact — render the rail-friendly compact variant
|
|
17
|
+
*
|
|
18
|
+
* Invariants:
|
|
19
|
+
* - No fetch. No mutation. No secret reading.
|
|
20
|
+
* - Reads only safe data (booleans, status strings, deep-link routes).
|
|
21
|
+
* - Falls back to a sensible default state if config is missing.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import Link from "next/link";
|
|
25
|
+
import {
|
|
26
|
+
ArrowRight,
|
|
27
|
+
Check,
|
|
28
|
+
CircleDot,
|
|
29
|
+
HelpCircle,
|
|
30
|
+
Lock,
|
|
31
|
+
Sparkles,
|
|
32
|
+
} from "lucide-react";
|
|
33
|
+
import { deriveWorkspaceActivationState } from "@/lib/workspace-activation";
|
|
34
|
+
|
|
35
|
+
function StatusIcon({ status }) {
|
|
36
|
+
if (status === "complete") return <Check size={14} aria-hidden="true" />;
|
|
37
|
+
if (status === "blocked") return <Lock size={14} aria-hidden="true" />;
|
|
38
|
+
if (status === "optional") return <Sparkles size={14} aria-hidden="true" />;
|
|
39
|
+
return <CircleDot size={14} aria-hidden="true" />;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function StatusLabel({ status }) {
|
|
43
|
+
if (status === "complete") return "Done";
|
|
44
|
+
if (status === "blocked") return "Blocked";
|
|
45
|
+
if (status === "optional") return "Optional";
|
|
46
|
+
return "Next";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function WorkspaceActivationPanel({
|
|
50
|
+
workspaceConfig,
|
|
51
|
+
workspaceSourceRecords,
|
|
52
|
+
metadataGraph,
|
|
53
|
+
onOpenHelper,
|
|
54
|
+
compact = false,
|
|
55
|
+
}) {
|
|
56
|
+
const state = deriveWorkspaceActivationState({
|
|
57
|
+
workspaceConfig,
|
|
58
|
+
workspaceSourceRecords,
|
|
59
|
+
metadataGraph,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const stepsToRender = compact
|
|
63
|
+
? state.steps.filter((step) => step.status !== "optional")
|
|
64
|
+
: state.steps;
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<section
|
|
68
|
+
className={
|
|
69
|
+
"workspace-activation-panel"
|
|
70
|
+
+ (compact ? " is-compact" : "")
|
|
71
|
+
+ (state.complete ? " is-complete" : "")
|
|
72
|
+
}
|
|
73
|
+
aria-label="Workspace activation"
|
|
74
|
+
data-template={state.template}
|
|
75
|
+
>
|
|
76
|
+
<header className="workspace-activation-head">
|
|
77
|
+
<div className="workspace-activation-head-text">
|
|
78
|
+
<p className="workspace-activation-eyebrow">{state.templateName}</p>
|
|
79
|
+
<h2 className="workspace-activation-headline">{state.headline}</h2>
|
|
80
|
+
{state.subheadline ? (
|
|
81
|
+
<p className="workspace-activation-subheadline">{state.subheadline}</p>
|
|
82
|
+
) : null}
|
|
83
|
+
</div>
|
|
84
|
+
<div
|
|
85
|
+
className="workspace-activation-progress"
|
|
86
|
+
aria-label={`${state.completedCount} of ${state.totalCount} setup steps complete`}
|
|
87
|
+
>
|
|
88
|
+
<span className="workspace-activation-progress-value">
|
|
89
|
+
{state.completedCount}/{state.totalCount}
|
|
90
|
+
</span>
|
|
91
|
+
<span className="workspace-activation-progress-bar" aria-hidden="true">
|
|
92
|
+
<span
|
|
93
|
+
className="workspace-activation-progress-fill"
|
|
94
|
+
style={{
|
|
95
|
+
width: state.totalCount > 0
|
|
96
|
+
? `${Math.min(100, Math.round((state.completedCount / state.totalCount) * 100))}%`
|
|
97
|
+
: "0%",
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
</span>
|
|
101
|
+
</div>
|
|
102
|
+
</header>
|
|
103
|
+
|
|
104
|
+
<ol className="workspace-activation-steps" role="list">
|
|
105
|
+
{stepsToRender.map((step) => {
|
|
106
|
+
const isNext = state.nextStepId === step.id;
|
|
107
|
+
return (
|
|
108
|
+
<li
|
|
109
|
+
key={step.id}
|
|
110
|
+
className={
|
|
111
|
+
"workspace-activation-step"
|
|
112
|
+
+ ` is-${step.status}`
|
|
113
|
+
+ (isNext ? " is-next" : "")
|
|
114
|
+
}
|
|
115
|
+
>
|
|
116
|
+
<span className="workspace-activation-step-status" aria-hidden="true">
|
|
117
|
+
<StatusIcon status={step.status} />
|
|
118
|
+
</span>
|
|
119
|
+
<div className="workspace-activation-step-body">
|
|
120
|
+
<div className="workspace-activation-step-titlebar">
|
|
121
|
+
<h3 className="workspace-activation-step-title">{step.label}</h3>
|
|
122
|
+
<span className={`workspace-activation-step-badge is-${step.status}`}>
|
|
123
|
+
<StatusLabel status={step.status} />
|
|
124
|
+
</span>
|
|
125
|
+
</div>
|
|
126
|
+
<p className="workspace-activation-step-description">{step.description}</p>
|
|
127
|
+
{step.hint ? (
|
|
128
|
+
<p className="workspace-activation-step-hint">
|
|
129
|
+
<HelpCircle size={12} aria-hidden="true" />
|
|
130
|
+
<span>{step.hint}</span>
|
|
131
|
+
</p>
|
|
132
|
+
) : null}
|
|
133
|
+
{step.href ? (
|
|
134
|
+
<Link
|
|
135
|
+
href={step.href}
|
|
136
|
+
className={
|
|
137
|
+
"workspace-activation-step-cta"
|
|
138
|
+
+ (isNext ? " is-primary" : "")
|
|
139
|
+
}
|
|
140
|
+
>
|
|
141
|
+
<span>{step.cta || (step.status === "complete" ? "Review" : "Open")}</span>
|
|
142
|
+
<ArrowRight size={12} aria-hidden="true" />
|
|
143
|
+
</Link>
|
|
144
|
+
) : null}
|
|
145
|
+
</div>
|
|
146
|
+
</li>
|
|
147
|
+
);
|
|
148
|
+
})}
|
|
149
|
+
</ol>
|
|
150
|
+
|
|
151
|
+
{onOpenHelper ? (
|
|
152
|
+
<div className="workspace-activation-helper-cta">
|
|
153
|
+
<button
|
|
154
|
+
type="button"
|
|
155
|
+
className="workspace-activation-helper-btn"
|
|
156
|
+
onClick={() => onOpenHelper({
|
|
157
|
+
template: state.template,
|
|
158
|
+
nextStepId: state.nextStepId,
|
|
159
|
+
})}
|
|
160
|
+
>
|
|
161
|
+
<Sparkles size={13} aria-hidden="true" />
|
|
162
|
+
<span>
|
|
163
|
+
{state.complete
|
|
164
|
+
? "Ask helper to customize this workspace"
|
|
165
|
+
: `Ask helper to finish ${state.templateName}`}
|
|
166
|
+
</span>
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
) : null}
|
|
170
|
+
</section>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { ArrowRight, CheckCircle, ExternalLink, Loader2, RefreshCw, ShieldCheck, XCircle } from "lucide-react";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* NangoConnectionPanel — interactive sidecar for an api-registry row whose
|
|
@@ -114,7 +115,7 @@ function StatusBadge({ status, label }) {
|
|
|
114
115
|
);
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
export function NangoConnectionPanel({ row, disabled, onUpdateRow }) {
|
|
118
|
+
export function NangoConnectionPanel({ row, disabled, onUpdateRow, templateContext }) {
|
|
118
119
|
const initialProviderConfigKey = useMemo(() => deriveProviderConfigKey(row), [row]);
|
|
119
120
|
const initialConnectionId = useMemo(() => deriveDefaultConnectionId(row), [row]);
|
|
120
121
|
const initialStatus = useMemo(() => deriveInitialStatus(row), [row]);
|
|
@@ -491,6 +492,40 @@ export function NangoConnectionPanel({ row, disabled, onUpdateRow }) {
|
|
|
491
492
|
</button>
|
|
492
493
|
) : null}
|
|
493
494
|
</div>
|
|
495
|
+
|
|
496
|
+
{/*
|
|
497
|
+
* Template-aware affordances. When this row was scaffolded as part
|
|
498
|
+
* of a workspace template (project-management today), surface a
|
|
499
|
+
* "next step" hint linking back to the activation checklist or the
|
|
500
|
+
* seeded workflow. Other rows render no template context at all.
|
|
501
|
+
*/}
|
|
502
|
+
{templateContext && (templateContext.nextHref || templateContext.backHref) ? (
|
|
503
|
+
<div
|
|
504
|
+
className={
|
|
505
|
+
"workspace-template-context-banner"
|
|
506
|
+
+ ((statusKind === "connected" || persistedStatus === "connected") ? "" : " is-warn")
|
|
507
|
+
}
|
|
508
|
+
role="note"
|
|
509
|
+
>
|
|
510
|
+
<span>
|
|
511
|
+
{(statusKind === "connected" || persistedStatus === "connected")
|
|
512
|
+
? (templateContext.nextLabel || "Next: run the seeded workflow.")
|
|
513
|
+
: (templateContext.pendingLabel || "Finish OAuth above, then continue setup.")}
|
|
514
|
+
</span>
|
|
515
|
+
{templateContext.backHref ? (
|
|
516
|
+
<Link href={templateContext.backHref} className="workspace-template-context-link">
|
|
517
|
+
<span>Back to setup checklist</span>
|
|
518
|
+
<ArrowRight size={12} aria-hidden="true" />
|
|
519
|
+
</Link>
|
|
520
|
+
) : null}
|
|
521
|
+
{templateContext.nextHref ? (
|
|
522
|
+
<Link href={templateContext.nextHref} className="workspace-template-context-link">
|
|
523
|
+
<span>{templateContext.nextCta || "Open workflow"}</span>
|
|
524
|
+
<ArrowRight size={12} aria-hidden="true" />
|
|
525
|
+
</Link>
|
|
526
|
+
) : null}
|
|
527
|
+
</div>
|
|
528
|
+
) : null}
|
|
494
529
|
</section>
|
|
495
530
|
);
|
|
496
531
|
}
|
package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css
CHANGED
|
@@ -559,7 +559,10 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
559
559
|
padding: 16px;
|
|
560
560
|
display: flex;
|
|
561
561
|
flex-direction: column;
|
|
562
|
-
overflow:
|
|
562
|
+
overflow-y: auto;
|
|
563
|
+
overflow-x: hidden;
|
|
564
|
+
scrollbar-gutter: stable;
|
|
565
|
+
overscroll-behavior: contain;
|
|
563
566
|
}
|
|
564
567
|
.workspace-toolbar {
|
|
565
568
|
min-height: 48px;
|
|
@@ -639,6 +642,54 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
639
642
|
.workspace-tabs > button svg {
|
|
640
643
|
flex: 0 0 auto;
|
|
641
644
|
}
|
|
645
|
+
.workspace-toolbar-actions > .workspace-finish-setup-control {
|
|
646
|
+
gap: 0;
|
|
647
|
+
padding: 0;
|
|
648
|
+
overflow: hidden;
|
|
649
|
+
}
|
|
650
|
+
.workspace-finish-setup-trigger,
|
|
651
|
+
.workspace-finish-setup-dismiss {
|
|
652
|
+
min-height: 28px;
|
|
653
|
+
border: 0;
|
|
654
|
+
background: transparent;
|
|
655
|
+
color: inherit;
|
|
656
|
+
display: inline-flex;
|
|
657
|
+
align-items: center;
|
|
658
|
+
justify-content: center;
|
|
659
|
+
gap: 6px;
|
|
660
|
+
padding: 0 10px;
|
|
661
|
+
cursor: pointer;
|
|
662
|
+
}
|
|
663
|
+
.workspace-finish-setup-trigger:hover,
|
|
664
|
+
.workspace-finish-setup-dismiss:hover {
|
|
665
|
+
background: #fafafa;
|
|
666
|
+
}
|
|
667
|
+
.workspace-finish-setup-control.is-complete {
|
|
668
|
+
border-color: #bbf7d0;
|
|
669
|
+
color: #047857;
|
|
670
|
+
background: #f0fdf4;
|
|
671
|
+
}
|
|
672
|
+
.workspace-finish-setup-control.is-complete .workspace-finish-setup-trigger:hover,
|
|
673
|
+
.workspace-finish-setup-control.is-complete .workspace-finish-setup-dismiss:hover {
|
|
674
|
+
background: #dcfce7;
|
|
675
|
+
}
|
|
676
|
+
.workspace-finish-setup-dismiss {
|
|
677
|
+
width: 30px;
|
|
678
|
+
padding: 0;
|
|
679
|
+
border-left: 1px solid #bbf7d0;
|
|
680
|
+
}
|
|
681
|
+
.workspace-finish-setup-dismiss-x {
|
|
682
|
+
display: none;
|
|
683
|
+
}
|
|
684
|
+
.workspace-finish-setup-dismiss:hover {
|
|
685
|
+
color: #b91c1c;
|
|
686
|
+
}
|
|
687
|
+
.workspace-finish-setup-dismiss:hover .workspace-finish-setup-dismiss-check {
|
|
688
|
+
display: none;
|
|
689
|
+
}
|
|
690
|
+
.workspace-finish-setup-dismiss:hover .workspace-finish-setup-dismiss-x {
|
|
691
|
+
display: block;
|
|
692
|
+
}
|
|
642
693
|
.workspace-table,
|
|
643
694
|
.workspace-canvas {
|
|
644
695
|
border: 1px solid #e7e7e7;
|
|
@@ -4120,6 +4171,68 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
4120
4171
|
.workspace-chart-type-tabs button.active em {
|
|
4121
4172
|
color: #075985;
|
|
4122
4173
|
}
|
|
4174
|
+
.workspace-table-view-tabs {
|
|
4175
|
+
grid-template-columns: repeat(4, 1fr);
|
|
4176
|
+
}
|
|
4177
|
+
.workspace-table-transform-preview {
|
|
4178
|
+
display: grid;
|
|
4179
|
+
gap: 8px;
|
|
4180
|
+
min-height: 88px;
|
|
4181
|
+
margin-top: 10px;
|
|
4182
|
+
color: #4b5563;
|
|
4183
|
+
font-size: 11px;
|
|
4184
|
+
}
|
|
4185
|
+
.workspace-table-transform-preview.is-board,
|
|
4186
|
+
.workspace-table-transform-preview.is-calendar {
|
|
4187
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
4188
|
+
}
|
|
4189
|
+
.workspace-table-transform-preview.is-calendar {
|
|
4190
|
+
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
4191
|
+
}
|
|
4192
|
+
.workspace-table-transform-preview section {
|
|
4193
|
+
min-width: 0;
|
|
4194
|
+
border: 1px solid #eeeeee;
|
|
4195
|
+
border-radius: 5px;
|
|
4196
|
+
background: #fafafa;
|
|
4197
|
+
padding: 6px;
|
|
4198
|
+
}
|
|
4199
|
+
.workspace-table-transform-preview strong,
|
|
4200
|
+
.workspace-table-transform-preview span,
|
|
4201
|
+
.workspace-table-transform-preview em {
|
|
4202
|
+
display: block;
|
|
4203
|
+
min-width: 0;
|
|
4204
|
+
overflow: hidden;
|
|
4205
|
+
text-overflow: ellipsis;
|
|
4206
|
+
white-space: nowrap;
|
|
4207
|
+
}
|
|
4208
|
+
.workspace-table-transform-preview strong {
|
|
4209
|
+
color: #111827;
|
|
4210
|
+
font-size: 11px;
|
|
4211
|
+
}
|
|
4212
|
+
.workspace-table-transform-preview span {
|
|
4213
|
+
margin-top: 5px;
|
|
4214
|
+
border-radius: 4px;
|
|
4215
|
+
background: #fff;
|
|
4216
|
+
padding: 5px 6px;
|
|
4217
|
+
}
|
|
4218
|
+
.workspace-table-transform-preview div {
|
|
4219
|
+
display: grid;
|
|
4220
|
+
grid-template-columns: minmax(64px, 1fr) 2fr minmax(32px, auto);
|
|
4221
|
+
align-items: center;
|
|
4222
|
+
gap: 8px;
|
|
4223
|
+
}
|
|
4224
|
+
.workspace-table-transform-preview i {
|
|
4225
|
+
display: block;
|
|
4226
|
+
width: var(--width, 42%);
|
|
4227
|
+
height: 9px;
|
|
4228
|
+
margin-left: var(--offset, 0);
|
|
4229
|
+
border-radius: 999px;
|
|
4230
|
+
background: #93c5fd;
|
|
4231
|
+
}
|
|
4232
|
+
.workspace-table-transform-preview em {
|
|
4233
|
+
color: #9ca3af;
|
|
4234
|
+
font-style: normal;
|
|
4235
|
+
}
|
|
4123
4236
|
.workspace-axis-range {
|
|
4124
4237
|
display: grid;
|
|
4125
4238
|
grid-template-columns: 1fr 1fr;
|
|
@@ -8501,3 +8614,59 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
8501
8614
|
.dm-swarm-phase { border: 1px solid #edf0f3; border-radius: 4px; padding: 6px 8px; font-size: 11px; }
|
|
8502
8615
|
.dm-swarm-phase summary { cursor: pointer; color: #6b7280; font-weight: 500; }
|
|
8503
8616
|
.dm-swarm-phase pre { margin: 6px 0 0; font-size: 11px; white-space: pre-wrap; color: #111827; max-height: 240px; overflow: auto; }
|
|
8617
|
+
|
|
8618
|
+
/* Customer Activation Layer V1 — workspace activation panel */
|
|
8619
|
+
.workspace-activation-panel { border: 1px solid #e5e7eb; border-radius: 10px; background: #ffffff; padding: 18px 20px; margin: 0 0 20px; display: flex; flex-direction: column; gap: 16px; }
|
|
8620
|
+
.workspace-activation-panel.is-complete { background: linear-gradient(180deg, #f0fdf4 0%, #ffffff 80%); border-color: #bbf7d0; }
|
|
8621
|
+
.workspace-activation-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
|
|
8622
|
+
.workspace-activation-head-text { display: flex; flex-direction: column; gap: 4px; flex: 1 1 320px; min-width: 0; }
|
|
8623
|
+
.workspace-activation-eyebrow { margin: 0; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: #6b7280; font-weight: 600; }
|
|
8624
|
+
.workspace-activation-headline { margin: 0; font-size: 18px; font-weight: 600; color: #111827; line-height: 1.3; }
|
|
8625
|
+
.workspace-activation-subheadline { margin: 0; font-size: 13px; color: #4b5563; }
|
|
8626
|
+
.workspace-activation-progress { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; min-width: 120px; }
|
|
8627
|
+
.workspace-activation-progress-value { font-size: 11px; font-weight: 600; color: #475569; }
|
|
8628
|
+
.workspace-activation-progress-bar { display: block; width: 120px; height: 6px; background: #f1f5f9; border-radius: 999px; overflow: hidden; }
|
|
8629
|
+
.workspace-activation-progress-fill { display: block; height: 100%; background: #3b82f6; transition: width 200ms ease; }
|
|
8630
|
+
.workspace-activation-panel.is-complete .workspace-activation-progress-fill { background: #16a34a; }
|
|
8631
|
+
.workspace-activation-steps { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
|
|
8632
|
+
.workspace-activation-step { display: flex; align-items: flex-start; gap: 12px; padding: 12px 14px; border: 1px solid #edf0f3; border-radius: 8px; background: #fbfcfd; transition: border-color 120ms ease, background 120ms ease; }
|
|
8633
|
+
.workspace-activation-step.is-next { border-color: #3b82f6; background: #eff6ff; }
|
|
8634
|
+
.workspace-activation-step.is-complete { background: #f0fdf4; border-color: #bbf7d0; }
|
|
8635
|
+
.workspace-activation-step.is-blocked { background: #fffbeb; border-color: #fde68a; }
|
|
8636
|
+
.workspace-activation-step.is-optional { opacity: 0.85; }
|
|
8637
|
+
.workspace-activation-step-status { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 999px; background: #ffffff; border: 1px solid #cbd5f5; color: #3b82f6; flex-shrink: 0; }
|
|
8638
|
+
.workspace-activation-step.is-complete .workspace-activation-step-status { background: #16a34a; border-color: #16a34a; color: #ffffff; }
|
|
8639
|
+
.workspace-activation-step.is-blocked .workspace-activation-step-status { background: #fef3c7; border-color: #f59e0b; color: #b45309; }
|
|
8640
|
+
.workspace-activation-step.is-optional .workspace-activation-step-status { background: #f5f3ff; border-color: #c4b5fd; color: #7c3aed; }
|
|
8641
|
+
.workspace-activation-step-body { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
|
|
8642
|
+
.workspace-activation-step-titlebar { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
|
|
8643
|
+
.workspace-activation-step-title { margin: 0; font-size: 13px; font-weight: 600; color: #111827; }
|
|
8644
|
+
.workspace-activation-step-badge { font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; padding: 1px 6px; border-radius: 999px; background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe; }
|
|
8645
|
+
.workspace-activation-step-badge.is-complete { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
|
|
8646
|
+
.workspace-activation-step-badge.is-blocked { background: #fef3c7; color: #b45309; border-color: #fde68a; }
|
|
8647
|
+
.workspace-activation-step-badge.is-optional { background: #f5f3ff; color: #6d28d9; border-color: #ddd6fe; }
|
|
8648
|
+
.workspace-activation-step-description { margin: 0; font-size: 12px; color: #475569; line-height: 1.5; }
|
|
8649
|
+
.workspace-activation-step-hint { display: inline-flex; align-items: flex-start; gap: 6px; margin: 0; font-size: 11px; color: #6b7280; line-height: 1.45; }
|
|
8650
|
+
.workspace-activation-step-hint > svg { margin-top: 2px; flex-shrink: 0; }
|
|
8651
|
+
.workspace-activation-step-cta { display: inline-flex; align-items: center; gap: 4px; align-self: flex-start; font-size: 12px; color: #1d4ed8; text-decoration: none; padding: 4px 0; }
|
|
8652
|
+
.workspace-activation-step-cta:hover { text-decoration: underline; }
|
|
8653
|
+
.workspace-activation-step-cta.is-primary { background: #3b82f6; color: #ffffff; border-radius: 6px; padding: 4px 10px; }
|
|
8654
|
+
.workspace-activation-step-cta.is-primary:hover { background: #2563eb; text-decoration: none; }
|
|
8655
|
+
.workspace-activation-helper-cta { display: flex; justify-content: flex-end; }
|
|
8656
|
+
.workspace-activation-helper-btn { display: inline-flex; align-items: center; gap: 6px; background: transparent; border: 1px dashed #c7d2fe; color: #4338ca; font-size: 12px; padding: 6px 10px; border-radius: 6px; cursor: pointer; }
|
|
8657
|
+
.workspace-activation-helper-btn:hover { background: #eef2ff; }
|
|
8658
|
+
|
|
8659
|
+
/* Compact rail variant — slim activation chip in WorkspaceRail Home */
|
|
8660
|
+
.workspace-activation-panel.is-compact { padding: 12px 14px; margin: 0 0 12px; gap: 10px; border-radius: 8px; }
|
|
8661
|
+
.workspace-activation-panel.is-compact .workspace-activation-head { gap: 8px; }
|
|
8662
|
+
.workspace-activation-panel.is-compact .workspace-activation-headline { font-size: 13px; }
|
|
8663
|
+
.workspace-activation-panel.is-compact .workspace-activation-subheadline { font-size: 11px; }
|
|
8664
|
+
.workspace-activation-panel.is-compact .workspace-activation-step { padding: 8px 10px; gap: 8px; }
|
|
8665
|
+
.workspace-activation-panel.is-compact .workspace-activation-step-title { font-size: 12px; }
|
|
8666
|
+
.workspace-activation-panel.is-compact .workspace-activation-step-description { font-size: 11px; }
|
|
8667
|
+
.workspace-activation-panel.is-compact .workspace-activation-progress-bar { width: 80px; }
|
|
8668
|
+
|
|
8669
|
+
/* Template-aware context banner — workflow + nango affordance */
|
|
8670
|
+
.workspace-template-context-banner { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 6px; background: #eff6ff; border: 1px solid #bfdbfe; color: #1e40af; font-size: 12px; margin: 0 0 12px; }
|
|
8671
|
+
.workspace-template-context-banner.is-warn { background: #fffbeb; border-color: #fde68a; color: #92400e; }
|
|
8672
|
+
.workspace-template-context-banner .workspace-template-context-link { color: inherit; text-decoration: underline; font-weight: 600; margin-left: auto; }
|
|
@@ -51,6 +51,7 @@ import { AgentSwarmPanel } from "../data-model/components/AgentSwarmPanel.jsx";
|
|
|
51
51
|
import { RunSetupPanel } from "./RunSetupPanel.jsx";
|
|
52
52
|
import { describeRunInputMetadataItems, discoverRunInputSchema } from "@/lib/orchestration-run-inputs";
|
|
53
53
|
import { selectWorkflowNodeInputSchema } from "@/lib/workspace-metadata-selectors";
|
|
54
|
+
import { deriveProvenance, hasConnectionId } from "@/lib/workspace-activation";
|
|
54
55
|
|
|
55
56
|
// Workspace Metadata Graph V1 — read-only dependency metadata for workflow
|
|
56
57
|
// sidecars. The runtime path (sandbox-run, publish, draft/live) is
|
|
@@ -387,6 +388,33 @@ export default function WorkflowSurface() {
|
|
|
387
388
|
[workspaceConfig, sandboxRow]
|
|
388
389
|
);
|
|
389
390
|
|
|
391
|
+
// Template-aware activation banner. When the active workflow belongs to
|
|
392
|
+
// a seeded template (project-management today) and its provider row
|
|
393
|
+
// doesn't have a connectionId yet, surface a back-link to the API
|
|
394
|
+
// Registry / Nango panel so the user can finish setup without hunting
|
|
395
|
+
// through Data Model surfaces.
|
|
396
|
+
const templateBanner = useMemo(() => {
|
|
397
|
+
if (!workspaceConfig) return null;
|
|
398
|
+
const provenance = deriveProvenance(workspaceConfig);
|
|
399
|
+
if (provenance.template !== "project-management") return null;
|
|
400
|
+
if (!registryRow) return null;
|
|
401
|
+
const ready = hasConnectionId(registryRow);
|
|
402
|
+
const apiRegistryObjectId = String(
|
|
403
|
+
(Array.isArray(workspaceConfig?.dataModel?.objects)
|
|
404
|
+
? workspaceConfig.dataModel.objects.find((o) => o?.objectType === "api-registry")?.id
|
|
405
|
+
: "") || ""
|
|
406
|
+
);
|
|
407
|
+
const apiRegistryRowId = String(registryRow.integrationId || "").trim();
|
|
408
|
+
const backHref = apiRegistryObjectId && apiRegistryRowId
|
|
409
|
+
? `/data-model?object=${encodeURIComponent(apiRegistryObjectId)}&row=${encodeURIComponent(apiRegistryRowId)}`
|
|
410
|
+
: "/data-model";
|
|
411
|
+
return {
|
|
412
|
+
ready,
|
|
413
|
+
backHref,
|
|
414
|
+
providerConfigKey: String(registryRow.providerConfigKey || registryRow.integrationId || "").trim(),
|
|
415
|
+
};
|
|
416
|
+
}, [workspaceConfig, registryRow]);
|
|
417
|
+
|
|
390
418
|
useEffect(() => {
|
|
391
419
|
setSidecarMode(runId ? "trace" : "graph");
|
|
392
420
|
}, [runId]);
|
|
@@ -876,6 +904,22 @@ export default function WorkflowSurface() {
|
|
|
876
904
|
</div>
|
|
877
905
|
</header>
|
|
878
906
|
|
|
907
|
+
{templateBanner ? (
|
|
908
|
+
<div
|
|
909
|
+
className={"workspace-template-context-banner" + (templateBanner.ready ? "" : " is-warn")}
|
|
910
|
+
role="note"
|
|
911
|
+
>
|
|
912
|
+
<span>
|
|
913
|
+
{templateBanner.ready
|
|
914
|
+
? `Provider connected via Nango${templateBanner.providerConfigKey ? ` (${templateBanner.providerConfigKey})` : ""}. Ready to run.`
|
|
915
|
+
: "Connect your provider through Nango before running this workflow."}
|
|
916
|
+
</span>
|
|
917
|
+
<Link href={templateBanner.backHref} className="workspace-template-context-link">
|
|
918
|
+
<span>{templateBanner.ready ? "Manage connection" : "Open Nango panel"}</span>
|
|
919
|
+
</Link>
|
|
920
|
+
</div>
|
|
921
|
+
) : null}
|
|
922
|
+
|
|
879
923
|
{loading ? (
|
|
880
924
|
<p className="dm-workflow-empty">Loading workflow…</p>
|
|
881
925
|
) : error ? (
|