@growthub/cli 0.13.9 → 0.14.0
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/env-status/route.js +31 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/helper/apply/route.js +130 -5
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceActivationPanel.jsx +17 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceHelperSetupModal.jsx +5 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryCreationCockpit.jsx +200 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +396 -5
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/HelperSidecar.jsx +75 -55
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ReferencePicker.jsx +2 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +100 -6
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +176 -5
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/resolver-loader.js +2 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/api-registry-creation-flow.js +317 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/api-response-profile.js +207 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/creation-error-recovery.js +103 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/env-status.js +100 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +63 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-serverless-flow.js +215 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/server-resolver-write.js +67 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/serverless-upgrade.js +89 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-activation.js +11 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +8 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper.js +7 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-resolver-proposal.js +200 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package.json +1 -1
- package/package.json +1 -1
|
@@ -69,6 +69,7 @@ function ToolCallCard({ proposal, content, onOpenArtifact }) {
|
|
|
69
69
|
rationale: proposal?.rationale,
|
|
70
70
|
confidence: proposal?.confidence,
|
|
71
71
|
};
|
|
72
|
+
const showJson = meta.payload != null || meta.affectedField || meta.rationale;
|
|
72
73
|
return (
|
|
73
74
|
<div className="dm-helper-toolcall" data-toolcall-type={proposal?.type}>
|
|
74
75
|
<button
|
|
@@ -89,9 +90,11 @@ function ToolCallCard({ proposal, content, onOpenArtifact }) {
|
|
|
89
90
|
{open && (
|
|
90
91
|
<div className="dm-helper-toolcall-body">
|
|
91
92
|
{content && <div className="dm-helper-toolcall-content">{content}</div>}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
{showJson && (
|
|
94
|
+
<pre className="dm-helper-toolcall-json">
|
|
95
|
+
{JSON.stringify(meta, null, 2)}
|
|
96
|
+
</pre>
|
|
97
|
+
)}
|
|
95
98
|
</div>
|
|
96
99
|
)}
|
|
97
100
|
{canNavigate && (
|
|
@@ -108,6 +111,55 @@ function ToolCallCard({ proposal, content, onOpenArtifact }) {
|
|
|
108
111
|
);
|
|
109
112
|
}
|
|
110
113
|
|
|
114
|
+
function formatRunDuration(ms) {
|
|
115
|
+
const value = Number(ms);
|
|
116
|
+
if (!Number.isFinite(value) || value < 0) return "";
|
|
117
|
+
const totalSeconds = Math.max(0, Math.round(value / 1000));
|
|
118
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
119
|
+
const seconds = totalSeconds % 60;
|
|
120
|
+
if (minutes <= 0) return `${seconds}s`;
|
|
121
|
+
return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function ProposalReviewCard({ proposal, checked, disabled, onCheckedChange, onKeyDown }) {
|
|
125
|
+
const [open, setOpen] = useState(false);
|
|
126
|
+
const summary = summarizePayload(proposal);
|
|
127
|
+
return (
|
|
128
|
+
<div className="dm-helper-toolcall" data-proposal-item="" tabIndex={0} onKeyDown={onKeyDown}>
|
|
129
|
+
<div className="dm-helper-toolcall-row dm-helper-proposal-card-row">
|
|
130
|
+
<input
|
|
131
|
+
type="checkbox"
|
|
132
|
+
checked={!!checked}
|
|
133
|
+
onChange={(e) => onCheckedChange(e.target.checked)}
|
|
134
|
+
disabled={disabled}
|
|
135
|
+
data-proposal-accept=""
|
|
136
|
+
aria-label={`Select ${proposal.type}`}
|
|
137
|
+
/>
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
className="dm-helper-proposal-card-toggle"
|
|
141
|
+
onClick={() => setOpen((v) => !v)}
|
|
142
|
+
aria-expanded={open}
|
|
143
|
+
>
|
|
144
|
+
<span className="dm-helper-toolcall-title">{proposal.type}</span>
|
|
145
|
+
<span className="dm-helper-proposal-field">→ {proposal.affectedField}</span>
|
|
146
|
+
<ChevronDown
|
|
147
|
+
size={14}
|
|
148
|
+
className={`dm-helper-toolcall-chevron${open ? " is-open" : ""}`}
|
|
149
|
+
aria-hidden="true"
|
|
150
|
+
/>
|
|
151
|
+
</button>
|
|
152
|
+
</div>
|
|
153
|
+
{open && (
|
|
154
|
+
<div className="dm-helper-toolcall-body">
|
|
155
|
+
{summary && <p className="dm-helper-proposal-payload" data-proposal-payload="">{summary}</p>}
|
|
156
|
+
{proposal.rationale && <p className="dm-helper-proposal-rationale">{proposal.rationale}</p>}
|
|
157
|
+
</div>
|
|
158
|
+
)}
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
111
163
|
// Pair a system apply-receipt message with the actual proposal payload
|
|
112
164
|
// it confirms. The applyResult (rehydrated from row.lastApplied at thread
|
|
113
165
|
// load time) carries the typed payloads keyed in order — we walk the
|
|
@@ -747,6 +799,11 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
|
|
|
747
799
|
const acceptedCount = Object.values(accepted).filter(Boolean).length;
|
|
748
800
|
const skippedCount = applyResult?.skipped?.length || 0;
|
|
749
801
|
const hasProposals = result && (result.proposals || []).length > 0;
|
|
802
|
+
const visibleWarnings = (result?.warnings || []).filter((warning) => {
|
|
803
|
+
const text = String(warning || "");
|
|
804
|
+
return !/transcript does not include the actual registry row id or lastResponse payload/i.test(text)
|
|
805
|
+
&& !/No credentials or env values should be stored/i.test(text);
|
|
806
|
+
});
|
|
750
807
|
|
|
751
808
|
// Thread is "active" the moment the user has sent at least one message,
|
|
752
809
|
// OR we have rehydrated a prior thread row. Pills only show on the
|
|
@@ -916,18 +973,9 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
|
|
|
916
973
|
{/* Proposals */}
|
|
917
974
|
{result && (
|
|
918
975
|
<div className="dm-helper-result">
|
|
919
|
-
|
|
920
|
-
<
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
{(result.warnings || []).length > 0 && (
|
|
924
|
-
<div className="dm-helper-warnings">
|
|
925
|
-
{result.warnings.map((w, i) => (
|
|
926
|
-
<div key={i} className="dm-helper-warning">
|
|
927
|
-
<AlertCircle size={12} />
|
|
928
|
-
<span>{w}</span>
|
|
929
|
-
</div>
|
|
930
|
-
))}
|
|
976
|
+
{!threadActive && result.summary && (
|
|
977
|
+
<div className="dm-helper-summary">
|
|
978
|
+
<span>{result.summary}</span>
|
|
931
979
|
</div>
|
|
932
980
|
)}
|
|
933
981
|
|
|
@@ -943,42 +991,17 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
|
|
|
943
991
|
aria-label="Proposals"
|
|
944
992
|
>
|
|
945
993
|
{result.proposals.map((proposal, i) => {
|
|
946
|
-
const summary = summarizePayload(proposal);
|
|
947
|
-
const conf = typeof proposal.confidence === "number" ? Math.round(proposal.confidence * 100) : null;
|
|
948
994
|
return (
|
|
949
|
-
<
|
|
995
|
+
<ProposalReviewCard
|
|
950
996
|
key={i}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
997
|
+
proposal={proposal}
|
|
998
|
+
checked={accepted[i]}
|
|
999
|
+
disabled={applying}
|
|
1000
|
+
onCheckedChange={(checked) =>
|
|
1001
|
+
setAccepted((prev) => ({ ...prev, [i]: checked }))
|
|
1002
|
+
}
|
|
954
1003
|
onKeyDown={(e) => handleProposalKeyDown(e, i)}
|
|
955
|
-
|
|
956
|
-
<input
|
|
957
|
-
type="checkbox"
|
|
958
|
-
checked={!!accepted[i]}
|
|
959
|
-
onChange={(e) =>
|
|
960
|
-
setAccepted((prev) => ({ ...prev, [i]: e.target.checked }))
|
|
961
|
-
}
|
|
962
|
-
disabled={applying}
|
|
963
|
-
data-proposal-accept=""
|
|
964
|
-
tabIndex={-1}
|
|
965
|
-
/>
|
|
966
|
-
<div className="dm-helper-proposal-body">
|
|
967
|
-
<div className="dm-helper-proposal-row">
|
|
968
|
-
<span className="dm-helper-proposal-type">{proposal.type}</span>
|
|
969
|
-
<span className="dm-helper-proposal-field">→ {proposal.affectedField}</span>
|
|
970
|
-
{conf !== null && (
|
|
971
|
-
<span className="dm-helper-proposal-confidence" data-proposal-confidence={conf}>
|
|
972
|
-
{conf}%
|
|
973
|
-
</span>
|
|
974
|
-
)}
|
|
975
|
-
</div>
|
|
976
|
-
{summary && (
|
|
977
|
-
<p className="dm-helper-proposal-payload" data-proposal-payload="">{summary}</p>
|
|
978
|
-
)}
|
|
979
|
-
<p className="dm-helper-proposal-rationale">{proposal.rationale}</p>
|
|
980
|
-
</div>
|
|
981
|
-
</label>
|
|
1004
|
+
/>
|
|
982
1005
|
);
|
|
983
1006
|
})}
|
|
984
1007
|
</div>
|
|
@@ -1055,13 +1078,10 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
|
|
|
1055
1078
|
)}
|
|
1056
1079
|
|
|
1057
1080
|
{result.receipts && (
|
|
1058
|
-
<
|
|
1059
|
-
|
|
1060
|
-
{
|
|
1061
|
-
|
|
1062
|
-
: "n/a"}{" "}
|
|
1063
|
-
· {result.receipts.latencyMs}ms
|
|
1064
|
-
</p>
|
|
1081
|
+
<div className="dm-helper-run-meta" data-helper-receipt="">
|
|
1082
|
+
<span>{result.receipts.model || "run"}</span>
|
|
1083
|
+
<span>{formatRunDuration(result.receipts.latencyMs)}</span>
|
|
1084
|
+
</div>
|
|
1065
1085
|
)}
|
|
1066
1086
|
</div>
|
|
1067
1087
|
)}
|
|
@@ -202,9 +202,9 @@ export function ReferencePicker({
|
|
|
202
202
|
<div className="dm-reference-picker">
|
|
203
203
|
{error && <p className="dm-field-error" style={{ fontSize: 11 }}>{error}</p>}
|
|
204
204
|
{showRepair && (
|
|
205
|
-
<p className="dm-
|
|
205
|
+
<p className="dm-reference-picker-warning">
|
|
206
206
|
<AlertTriangle size={12} aria-hidden />
|
|
207
|
-
<span>
|
|
207
|
+
<span>Missing reference. Pick a row or test the API Registry.</span>
|
|
208
208
|
</p>
|
|
209
209
|
)}
|
|
210
210
|
<SearchableSelect
|
package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css
CHANGED
|
@@ -5030,7 +5030,7 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
5030
5030
|
.dm-db-status.warn { border-color: #fde68a; background: #fffbeb; color: #92400e; }
|
|
5031
5031
|
.dm-db-status.warn span { background: #f59e0b; }
|
|
5032
5032
|
.dm-record-backdrop { position: fixed; inset: 0; z-index: 80; background: rgba(15,23,42,.12); }
|
|
5033
|
-
.dm-record-drawer { position: fixed; top: 0; right: 0; bottom: 0; z-index: 81; display: flex; flex-direction: column; width: min(440px, 100vw); background: #fff; border-left: 1px solid #dfe3e8; box-shadow: -10px 0 34px rgba(15,23,42,.16); }
|
|
5033
|
+
.dm-record-drawer { position: fixed; top: 0; right: 0; bottom: 0; z-index: 81; display: flex; flex-direction: column; min-height: 0; width: min(440px, 100vw); background: #fff; border-left: 1px solid #dfe3e8; box-shadow: -10px 0 34px rgba(15,23,42,.16); overflow: hidden; }
|
|
5034
5034
|
.dm-record-drawer-wide { width: min(780px, 100vw); }
|
|
5035
5035
|
.dm-api-action-card {
|
|
5036
5036
|
display: grid;
|
|
@@ -5070,6 +5070,59 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
5070
5070
|
.dm-api-action-card-body h3 { margin: 0; font-size: 14px; font-weight: 650; color: #111827; }
|
|
5071
5071
|
.dm-api-action-card-body p { margin: 0; font-size: 12px; line-height: 1.45; color: #4b5563; }
|
|
5072
5072
|
.dm-api-action-card-cta { flex-shrink: 0; align-self: center; }
|
|
5073
|
+
|
|
5074
|
+
/* Governed creation cockpit — vertical journey inside the api-registry drawer.
|
|
5075
|
+
Overrides the action-card 3-col grid and reuses the workspace's own status
|
|
5076
|
+
chip (.dm-db-status) + dm-btn-* buttons. No new colors, no new primitive. */
|
|
5077
|
+
.dm-cockpit { display: block; grid-template-columns: none; transition: box-shadow .14s, background .14s; }
|
|
5078
|
+
.dm-cockpit.is-collapsed { padding-bottom: 12px; }
|
|
5079
|
+
.dm-cockpit-head { width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; border: 0; background: transparent; padding: 0; text-align: left; cursor: pointer; }
|
|
5080
|
+
.dm-cockpit-head:hover .dm-api-action-card-body h3 { color: #000; }
|
|
5081
|
+
.dm-cockpit-head:focus-visible { outline: 2px solid #bfdbfe; outline-offset: 4px; border-radius: 6px; }
|
|
5082
|
+
.dm-cockpit-count { flex-shrink: 0; font-size: 11px; font-weight: 700; color: #94a3b8; font-variant-numeric: tabular-nums; padding-top: 2px; }
|
|
5083
|
+
.dm-cockpit-steps { list-style: none; margin: 10px 0 0; padding: 0; }
|
|
5084
|
+
.dm-cockpit-step { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: start; padding: 10px 0; border-top: 1px solid #edf0f3; }
|
|
5085
|
+
.dm-cockpit-step:first-child { border-top: 0; }
|
|
5086
|
+
.dm-cockpit-step-chip { flex-shrink: 0; align-self: start; margin-top: 1px; min-width: 64px; justify-content: center; }
|
|
5087
|
+
.dm-cockpit-step-body { min-width: 0; display: grid; gap: 2px; }
|
|
5088
|
+
.dm-cockpit-step-label { margin: 0; font-size: 13px; font-weight: 600; color: #111827; }
|
|
5089
|
+
.dm-cockpit-step-desc { margin: 0; font-size: 12px; line-height: 1.45; color: #64748b; }
|
|
5090
|
+
.dm-cockpit-step-hint { margin: 0; font-size: 11px; line-height: 1.4; color: #94a3b8; }
|
|
5091
|
+
.dm-cockpit-step button { flex-shrink: 0; align-self: center; }
|
|
5092
|
+
.dm-cockpit-step-muted .dm-cockpit-step-label,
|
|
5093
|
+
.dm-cockpit-step-muted .dm-cockpit-step-desc { color: #94a3b8; }
|
|
5094
|
+
.dm-cockpit-step-next { background: #f8fafc; margin: 0 -14px; padding-left: 14px; padding-right: 14px; border-radius: 6px; }
|
|
5095
|
+
.dm-cockpit-shape { margin-top: 12px; padding-top: 12px; border-top: 1px solid #edf0f3; display: grid; gap: 6px; }
|
|
5096
|
+
.dm-cockpit-shape-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
5097
|
+
.dm-cockpit-shape-head .dm-api-action-card-eyebrow { margin: 0; }
|
|
5098
|
+
.dm-cockpit-fields { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
|
|
5099
|
+
.dm-cockpit-field { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: #475569; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 2px 8px; }
|
|
5100
|
+
.dm-cockpit-field b { font-weight: 700; color: #94a3b8; text-transform: uppercase; font-size: 10px; letter-spacing: .03em; }
|
|
5101
|
+
.dm-cockpit-receipts { margin-top: 12px; padding-top: 12px; border-top: 1px solid #edf0f3; }
|
|
5102
|
+
.dm-cockpit-receipts ul { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 6px; }
|
|
5103
|
+
.dm-cockpit-receipt { display: grid; grid-template-columns: auto 1fr; gap: 8px; align-items: start; }
|
|
5104
|
+
.dm-cockpit-receipt-chip { align-self: start; }
|
|
5105
|
+
.dm-cockpit-receipt-text { font-size: 12px; color: #64748b; line-height: 1.4; }
|
|
5106
|
+
|
|
5107
|
+
/* Serverless upgrade — toolbar button, one-time nudge, and cockpit panel. */
|
|
5108
|
+
.dm-workflow-upgrade-btn { position: relative; }
|
|
5109
|
+
.dm-workflow-upgrade-btn.is-serverless { color: #166534; }
|
|
5110
|
+
.dm-workflow-upgrade-btn.is-pulse { color: #111827; }
|
|
5111
|
+
.dm-workflow-upgrade-btn[data-tooltip]:hover::after {
|
|
5112
|
+
content: attr(data-tooltip); position: absolute; top: 100%; right: 0; margin-top: 6px;
|
|
5113
|
+
white-space: nowrap; background: #111827; color: #fff; font-size: 11px; font-weight: 500;
|
|
5114
|
+
padding: 5px 8px; border-radius: 6px; z-index: 40; box-shadow: 0 4px 12px rgba(15,23,42,.18);
|
|
5115
|
+
}
|
|
5116
|
+
.dm-workflow-upgrade-nudge { align-items: center; justify-content: space-between; gap: 16px; padding: 10px 16px; }
|
|
5117
|
+
.dm-workflow-upgrade-nudge > div:first-child { min-width: 0; padding-right: 10px; }
|
|
5118
|
+
.dm-workflow-upgrade-nudge strong,
|
|
5119
|
+
.dm-workflow-upgrade-nudge span { line-height: 1.35; }
|
|
5120
|
+
.dm-workflow-upgrade-nudge-actions { display: inline-flex; align-items: center; gap: 8px; }
|
|
5121
|
+
.dm-workflow-upgrade-panel { width: auto; margin: 12px 8px 16px; border: 1px solid #e5e7eb; border-radius: 8px; background: #fff; box-shadow: 0 2px 8px rgba(15,23,42,.06); }
|
|
5122
|
+
.dm-workflow-upgrade-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px 0; }
|
|
5123
|
+
.dm-workflow-upgrade-panel-head .dm-api-action-card-eyebrow { margin: 0; }
|
|
5124
|
+
.dm-workflow-upgrade-panel .dm-api-action-card { margin: 8px; box-shadow: none; }
|
|
5125
|
+
|
|
5073
5126
|
.dm-api-review-banner {
|
|
5074
5127
|
display: grid;
|
|
5075
5128
|
grid-template-columns: auto 1fr auto;
|
|
@@ -5223,6 +5276,7 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
5223
5276
|
display: flex;
|
|
5224
5277
|
align-items: center;
|
|
5225
5278
|
gap: 6px;
|
|
5279
|
+
padding-left: 16px;
|
|
5226
5280
|
min-width: max-content;
|
|
5227
5281
|
flex: 1 0 auto;
|
|
5228
5282
|
color: #8b8b91;
|
|
@@ -5276,6 +5330,7 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
5276
5330
|
display: flex;
|
|
5277
5331
|
align-items: center;
|
|
5278
5332
|
gap: 6px;
|
|
5333
|
+
padding-right: 16px;
|
|
5279
5334
|
flex: 0 1 auto;
|
|
5280
5335
|
min-width: 0;
|
|
5281
5336
|
max-width: 58vw;
|
|
@@ -6025,6 +6080,7 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
6025
6080
|
.dm-drawer-hidden-list { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
6026
6081
|
.dm-record-drawer-head p { margin: 0 0 3px; color: #94a3b8; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; }
|
|
6027
6082
|
.dm-record-drawer-head h2 { margin: 0; color: #111827; font-size: 16px; font-weight: 650; }
|
|
6083
|
+
.dm-record-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; scrollbar-gutter: stable; padding: 0 0 28px; }
|
|
6028
6084
|
.dm-record-testbar { display: flex; align-items: center; gap: 8px; padding: 10px 18px; border-bottom: 1px solid #edf0f3; background: #fbfdff; }
|
|
6029
6085
|
.dm-record-testbar > span:last-child { min-width: 0; color: #64748b; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
6030
6086
|
.dm-record-testbar[data-panel="sandbox-agent-auth"] {
|
|
@@ -6114,7 +6170,7 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
6114
6170
|
white-space: pre-wrap;
|
|
6115
6171
|
word-break: break-word;
|
|
6116
6172
|
}
|
|
6117
|
-
.dm-record-fields { display: grid; gap: 8px; padding: 14px 16px
|
|
6173
|
+
.dm-record-fields { display: grid; align-content: start; gap: 8px; min-height: 0; padding: 14px 16px 0; }
|
|
6118
6174
|
.dm-record-field { display: grid; gap: 5px; }
|
|
6119
6175
|
.dm-record-field span { color: #475569; font-size: 11px; font-weight: 650; }
|
|
6120
6176
|
.dm-record-field input,
|
|
@@ -6137,7 +6193,7 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
6137
6193
|
.dm-radio-row input[type="radio"], .dm-check-row input[type="checkbox"] { width: 14px; height: 14px; margin: 1px 0 0; padding: 0; box-shadow: none; accent-color: #111827; }
|
|
6138
6194
|
.dm-radio-row span, .dm-check-row span { color: #1f2937; font-size: 12px; font-weight: 500; }
|
|
6139
6195
|
.dm-check-row { cursor: pointer; }
|
|
6140
|
-
.dm-select { position: relative; width: 100%; min-width:
|
|
6196
|
+
.dm-select { position: relative; width: 100%; min-width: 0; font-size: 11px; }
|
|
6141
6197
|
.dm-select-trigger { width: 100%; min-height: 32px; display: flex; align-items: center; justify-content: space-between; gap: 8px; border: 1px solid #cbd5e1; border-radius: 7px; background: #fff; color: #111827; box-shadow: 0 1px 2px rgba(15,23,42,.05); font: inherit; font-size: 11px; padding: 6px 10px; text-align: left; cursor: pointer; transition: border-color .12s, box-shadow .12s, background .12s; }
|
|
6142
6198
|
.dm-select-trigger:hover:not(:disabled) { border-color: #94a3b8; box-shadow: 0 2px 8px rgba(15,23,42,.08); }
|
|
6143
6199
|
.dm-select.open .dm-select-trigger { border-color: #64748b; box-shadow: 0 0 0 3px rgba(100,116,139,.12), 0 2px 8px rgba(15,23,42,.08); }
|
|
@@ -6162,8 +6218,12 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
6162
6218
|
.dm-select-pager button { height: 26px; border: 1px solid #e2e8f0; border-radius: 6px; background: #fff; color: #334155; font: inherit; font-size: 12px; padding: 0 8px; cursor: pointer; }
|
|
6163
6219
|
.dm-select-pager button:disabled { opacity: .45; cursor: not-allowed; }
|
|
6164
6220
|
.dm-select-pager span { color: #64748b; font-size: 12px; font-weight: 650; }
|
|
6165
|
-
.dm-
|
|
6166
|
-
.dm-
|
|
6221
|
+
.dm-reference-picker { display: grid; gap: 6px; width: min(240px, 100%); min-width: 0; }
|
|
6222
|
+
.dm-reference-picker-warning { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; margin: 0; padding: 5px 7px; border: 1px solid #fde68a; border-radius: 6px; background: #fffbeb; color: #92400e; font-size: 11px; line-height: 1.25; }
|
|
6223
|
+
.dm-reference-picker-warning svg { flex: 0 0 auto; }
|
|
6224
|
+
.dm-reference-picker-warning span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
6225
|
+
.dm-db-grid td:has(.dm-select) { overflow: visible; padding-top: 5px; padding-bottom: 5px; vertical-align: top; }
|
|
6226
|
+
.dm-db-grid td .dm-select { min-width: 0; }
|
|
6167
6227
|
.dm-json-field { position: relative; }
|
|
6168
6228
|
.dm-json-field > span { padding-right: 34px; }
|
|
6169
6229
|
.dm-json-expand { position: absolute; top: 0; right: 0; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 24px; border: 1px solid #e2e8f0; border-radius: 6px; background: #fff; color: #64748b; box-shadow: 0 1px 2px rgba(15,23,42,.05); opacity: 0; cursor: pointer; transition: opacity .12s, border-color .12s, color .12s, box-shadow .12s; }
|
|
@@ -6607,6 +6667,40 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
|
|
|
6607
6667
|
background: #f5f5f5;
|
|
6608
6668
|
border-color: #9ca3af;
|
|
6609
6669
|
}
|
|
6670
|
+
.dm-helper-run-meta {
|
|
6671
|
+
display: flex;
|
|
6672
|
+
align-items: center;
|
|
6673
|
+
justify-content: space-between;
|
|
6674
|
+
gap: 12px;
|
|
6675
|
+
padding-top: 8px;
|
|
6676
|
+
border-top: 1px solid #e5e7eb;
|
|
6677
|
+
color: #6b7280;
|
|
6678
|
+
font-size: 12px;
|
|
6679
|
+
line-height: 1.3;
|
|
6680
|
+
}
|
|
6681
|
+
.dm-helper-proposal-card-row {
|
|
6682
|
+
grid-template-columns: 18px 1fr;
|
|
6683
|
+
}
|
|
6684
|
+
.dm-helper-proposal-card-row input[type=checkbox] {
|
|
6685
|
+
width: 14px;
|
|
6686
|
+
height: 14px;
|
|
6687
|
+
margin: 0;
|
|
6688
|
+
accent-color: #111827;
|
|
6689
|
+
}
|
|
6690
|
+
.dm-helper-proposal-card-toggle {
|
|
6691
|
+
display: grid;
|
|
6692
|
+
grid-template-columns: minmax(0, max-content) minmax(0, 1fr) auto;
|
|
6693
|
+
align-items: center;
|
|
6694
|
+
gap: 6px;
|
|
6695
|
+
width: 100%;
|
|
6696
|
+
padding: 0;
|
|
6697
|
+
border: 0;
|
|
6698
|
+
background: transparent;
|
|
6699
|
+
color: inherit;
|
|
6700
|
+
font: inherit;
|
|
6701
|
+
text-align: left;
|
|
6702
|
+
cursor: pointer;
|
|
6703
|
+
}
|
|
6610
6704
|
|
|
6611
6705
|
.dm-helper-typing {
|
|
6612
6706
|
display: inline-flex;
|
|
@@ -8960,7 +9054,7 @@ body.workspace-rail-collapsed .workspace-builder.workspace-lens-page,
|
|
|
8960
9054
|
.workspace-lens-helper-callout-btn { flex-shrink: 0; font-size: 12px; font-weight: 600; color: #111827; background: #ffffff; border: 1px solid #d1d5db; border-radius: 6px; padding: 7px 12px; cursor: pointer; }
|
|
8961
9055
|
.workspace-lens-helper-callout-btn:hover:not(:disabled) { background: #f3f4f6; }
|
|
8962
9056
|
.workspace-lens-helper-callout-btn:disabled { opacity: 0.6; cursor: default; }
|
|
8963
|
-
.workspace-helper-setup-modal-backdrop { position: fixed; inset: 0; z-index:
|
|
9057
|
+
.workspace-helper-setup-modal-backdrop { position: fixed; inset: 0; z-index: 5100; display: flex; align-items: center; justify-content: center; padding: 24px; background: rgba(17, 24, 39, 0.42); backdrop-filter: blur(3px); }
|
|
8964
9058
|
.workspace-helper-setup-modal { position: relative; width: min(620px, 100%); max-height: min(720px, calc(100vh - 48px)); overflow: auto; background: #ffffff; border: 1px solid #d1d5db; border-radius: 8px; box-shadow: 0 24px 70px rgba(17, 24, 39, 0.28); padding: 18px; }
|
|
8965
9059
|
.workspace-helper-setup-modal-close { position: absolute; top: 12px; right: 12px; width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid #e5e7eb; border-radius: 6px; background: #fff; color: #6b7280; cursor: pointer; }
|
|
8966
9060
|
.workspace-helper-setup-modal-close:hover { background: #f9fafb; color: #111827; }
|
|
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
6
6
|
import {
|
|
7
|
+
ArrowUpCircle,
|
|
7
8
|
Bot,
|
|
8
9
|
ChevronDown,
|
|
9
10
|
ChevronUp,
|
|
@@ -51,7 +52,31 @@ import { AgentSwarmPanel } from "../data-model/components/AgentSwarmPanel.jsx";
|
|
|
51
52
|
import { RunSetupPanel } from "./RunSetupPanel.jsx";
|
|
52
53
|
import { describeRunInputMetadataItems, discoverRunInputSchema } from "@/lib/orchestration-run-inputs";
|
|
53
54
|
import { selectWorkflowNodeInputSchema } from "@/lib/workspace-metadata-selectors";
|
|
54
|
-
import { deriveProvenance, hasConnectionId } from "@/lib/workspace-activation";
|
|
55
|
+
import { deriveProvenance, hasConnectionId, readUiCacheFlag } from "@/lib/workspace-activation";
|
|
56
|
+
import { ApiRegistryCreationCockpit } from "../data-model/components/ApiRegistryCreationCockpit.jsx";
|
|
57
|
+
import { deriveSandboxServerlessState } from "@/lib/sandbox-serverless-flow";
|
|
58
|
+
import { deriveServerlessUpgradeState, SERVERLESS_UPGRADE_DISMISS_FLAG } from "@/lib/serverless-upgrade";
|
|
59
|
+
|
|
60
|
+
// Set a flag on the governed workspace-ui-cache "activation" row (pure helper,
|
|
61
|
+
// same transform the rail/lens one-time dismisses use).
|
|
62
|
+
function withUiCacheFlag(workspaceConfig, flag, value) {
|
|
63
|
+
const dm = workspaceConfig?.dataModel && typeof workspaceConfig.dataModel === "object" ? workspaceConfig.dataModel : {};
|
|
64
|
+
const objects = Array.isArray(dm.objects) ? dm.objects : [];
|
|
65
|
+
const existing = objects.find((o) => o?.id === "workspace-ui-cache");
|
|
66
|
+
const baseRow = (existing?.rows || []).find((r) => r?.id === "activation") || { id: "activation" };
|
|
67
|
+
const nextRow = { ...baseRow, [flag]: value };
|
|
68
|
+
const nextCache = existing
|
|
69
|
+
? { ...existing, rows: [nextRow, ...(existing.rows || []).filter((r) => r?.id !== "activation")] }
|
|
70
|
+
: {
|
|
71
|
+
id: "workspace-ui-cache", label: "Workspace UI Cache", source: "Workspace UI Cache",
|
|
72
|
+
objectType: "custom", columns: ["id", flag], rows: [nextRow],
|
|
73
|
+
binding: { mode: "manual", source: "Workspace UI Cache" },
|
|
74
|
+
};
|
|
75
|
+
const nextObjects = existing
|
|
76
|
+
? objects.map((o) => (o?.id === "workspace-ui-cache" ? nextCache : o))
|
|
77
|
+
: [...objects, nextCache];
|
|
78
|
+
return { ...workspaceConfig, dataModel: { ...dm, objects: nextObjects } };
|
|
79
|
+
}
|
|
55
80
|
|
|
56
81
|
// Workspace Metadata Graph V1 — read-only dependency metadata for workflow
|
|
57
82
|
// sidecars. The runtime path (sandbox-run, publish, draft/live) is
|
|
@@ -63,20 +88,33 @@ const WORKFLOW_METADATA_SELECTORS = Object.freeze({
|
|
|
63
88
|
});
|
|
64
89
|
|
|
65
90
|
function resolveRegistryRowForSandbox(workspaceConfig, sandboxRow) {
|
|
91
|
+
return resolveRegistryRefForSandbox(workspaceConfig, sandboxRow)?.row || null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function resolveRegistryRefForSandbox(workspaceConfig, sandboxRow) {
|
|
66
95
|
const graph = parseOrchestrationGraph(sandboxRow?.orchestrationConfig || sandboxRow?.orchestrationGraph);
|
|
67
96
|
const apiNode = graph?.nodes?.find((n) => n?.type === "api-registry-call");
|
|
68
97
|
const registryId = String(
|
|
69
98
|
apiNode?.config?.registryId || apiNode?.config?.integrationId || sandboxRow?.schedulerRegistryId || ""
|
|
70
99
|
).trim();
|
|
71
|
-
if (!
|
|
100
|
+
if (!workspaceConfig) return null;
|
|
72
101
|
const objects = Array.isArray(workspaceConfig?.dataModel?.objects) ? workspaceConfig.dataModel.objects : [];
|
|
102
|
+
let firstRegistryRow = null;
|
|
103
|
+
let firstRegistryObject = null;
|
|
73
104
|
for (const objectItem of objects) {
|
|
74
105
|
if (objectItem?.objectType !== "api-registry") continue;
|
|
75
106
|
const rows = Array.isArray(objectItem.rows) ? objectItem.rows : [];
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
107
|
+
const firstRow = rows.find((r) => String(r?.integrationId || "").trim());
|
|
108
|
+
if (!firstRegistryRow && firstRow) {
|
|
109
|
+
firstRegistryRow = firstRow;
|
|
110
|
+
firstRegistryObject = objectItem;
|
|
111
|
+
}
|
|
112
|
+
if (registryId) {
|
|
113
|
+
const match = rows.find((r) => String(r?.integrationId || "").trim() === registryId);
|
|
114
|
+
if (match) return { object: objectItem, row: match };
|
|
115
|
+
}
|
|
78
116
|
}
|
|
79
|
-
return null;
|
|
117
|
+
return firstRegistryRow ? { object: firstRegistryObject, row: firstRegistryRow } : null;
|
|
80
118
|
}
|
|
81
119
|
|
|
82
120
|
function patchSandboxRowInConfig(workspaceConfig, objectId, rowIndex, fields) {
|
|
@@ -349,6 +387,23 @@ export default function WorkflowSurface() {
|
|
|
349
387
|
const [orchestrationGraph, setOrchestrationGraph] = useState(null);
|
|
350
388
|
const [dirty, setDirty] = useState(false);
|
|
351
389
|
const [runSetupOpen, setRunSetupOpen] = useState(false);
|
|
390
|
+
const [upgradeOpen, setUpgradeOpen] = useState(false);
|
|
391
|
+
const [serverlessSignals, setServerlessSignals] = useState({ configuredEnvRefs: [], persistenceAdapters: [] });
|
|
392
|
+
|
|
393
|
+
useEffect(() => {
|
|
394
|
+
let cancelled = false;
|
|
395
|
+
fetch("/api/workspace/env-status", { cache: "no-store" })
|
|
396
|
+
.then((res) => (res.ok ? res.json() : {}))
|
|
397
|
+
.then((payload) => {
|
|
398
|
+
if (cancelled) return;
|
|
399
|
+
setServerlessSignals({
|
|
400
|
+
configuredEnvRefs: Array.isArray(payload.configuredEnvRefs) ? payload.configuredEnvRefs : [],
|
|
401
|
+
persistenceAdapters: Array.isArray(payload.persistenceAdapters) ? payload.persistenceAdapters : [],
|
|
402
|
+
});
|
|
403
|
+
})
|
|
404
|
+
.catch(() => {});
|
|
405
|
+
return () => { cancelled = true; };
|
|
406
|
+
}, [objectId, rowId]);
|
|
352
407
|
|
|
353
408
|
const load = useCallback(async () => {
|
|
354
409
|
setLoading(true);
|
|
@@ -807,6 +862,73 @@ export default function WorkflowSurface() {
|
|
|
807
862
|
const showSaveDraft = dirty && !graphUnset;
|
|
808
863
|
const workflowModeLabel = isDraftMode ? "draft" : lifecycle || "live";
|
|
809
864
|
|
|
865
|
+
// Serverless upgrade — same derivation + cockpit as the sandbox/API lanes.
|
|
866
|
+
const upgradeState = deriveServerlessUpgradeState(workspaceConfig || {}, {
|
|
867
|
+
dismissed: readUiCacheFlag(workspaceConfig || {}, SERVERLESS_UPGRADE_DISMISS_FLAG),
|
|
868
|
+
});
|
|
869
|
+
const serverlessState = sandboxRow
|
|
870
|
+
? deriveSandboxServerlessState({
|
|
871
|
+
sandboxRow,
|
|
872
|
+
workspaceConfig: workspaceConfig || {},
|
|
873
|
+
configuredEnvRefs: serverlessSignals.configuredEnvRefs,
|
|
874
|
+
persistenceAdapters: serverlessSignals.persistenceAdapters,
|
|
875
|
+
})
|
|
876
|
+
: null;
|
|
877
|
+
const isServerlessWorkflow = Boolean(serverlessState?.isServerless);
|
|
878
|
+
|
|
879
|
+
async function patchSandboxAndPersist(fields) {
|
|
880
|
+
if (resolved.rowIndex < 0 || !objectId || !workspaceConfig) return;
|
|
881
|
+
try {
|
|
882
|
+
const next = patchSandboxRowInConfig(workspaceConfig, objectId, resolved.rowIndex, fields);
|
|
883
|
+
await persistWorkspace(next);
|
|
884
|
+
setSaveMessage(fields.runLocality === "serverless"
|
|
885
|
+
? "Upgraded to serverless. Link a scheduler and configure persistence to close the loop."
|
|
886
|
+
: fields.runLocality === "local"
|
|
887
|
+
? "Reverted to local execution."
|
|
888
|
+
: "Saved.");
|
|
889
|
+
} catch (err) {
|
|
890
|
+
setSaveMessage(err.message || "Failed to save");
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
async function handleUpgradeAction(action) {
|
|
895
|
+
if (!action) return;
|
|
896
|
+
if (action.id === "toggle-locality") {
|
|
897
|
+
if (isServerlessWorkflow) {
|
|
898
|
+
await patchSandboxAndPersist({ runLocality: "local" });
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
const registryRow = resolveRegistryRowForSandbox(workspaceConfig, sandboxRow);
|
|
902
|
+
const adapterId = String(sandboxRow?.adapter || "").trim();
|
|
903
|
+
await patchSandboxAndPersist({
|
|
904
|
+
runLocality: "serverless",
|
|
905
|
+
schedulerRegistryId: String(registryRow?.integrationId || "").trim(),
|
|
906
|
+
adapter: ["local-agent-host", "local-intelligence"].includes(adapterId) ? "local-process" : adapterId,
|
|
907
|
+
});
|
|
908
|
+
} else if (action.id === "open-settings") {
|
|
909
|
+
router.push(action.href || "/settings");
|
|
910
|
+
} else if (action.id === "link-scheduler") {
|
|
911
|
+
const registryRef = resolveRegistryRefForSandbox(workspaceConfig, sandboxRow);
|
|
912
|
+
if (registryRef?.object?.id && registryRef?.row?.integrationId) {
|
|
913
|
+
router.push(`/data-model?object=${encodeURIComponent(registryRef.object.id)}&row=${encodeURIComponent(registryRef.row.integrationId)}`);
|
|
914
|
+
} else {
|
|
915
|
+
router.push(`/data-model?object=${encodeURIComponent(objectId)}&row=${encodeURIComponent(rowId)}`);
|
|
916
|
+
}
|
|
917
|
+
} else if (action.id === "edit-adapter") {
|
|
918
|
+
// Full scheduler/adapter config lives on the sandbox object's drawer.
|
|
919
|
+
router.push(`/data-model?object=${encodeURIComponent(objectId)}&row=${encodeURIComponent(rowId)}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
async function dismissUpgradeOnboarding() {
|
|
924
|
+
if (!workspaceConfig) return;
|
|
925
|
+
try {
|
|
926
|
+
await persistWorkspace(withUiCacheFlag(workspaceConfig, SERVERLESS_UPGRADE_DISMISS_FLAG, true));
|
|
927
|
+
} catch {
|
|
928
|
+
/* non-fatal */
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
810
932
|
return (
|
|
811
933
|
<main className="workspace-builder dm-workflow-page">
|
|
812
934
|
<WorkspaceRail
|
|
@@ -854,6 +976,18 @@ export default function WorkflowSurface() {
|
|
|
854
976
|
>
|
|
855
977
|
<ChevronUp size={14} />
|
|
856
978
|
</button>
|
|
979
|
+
{sandboxRow && (
|
|
980
|
+
<button
|
|
981
|
+
type="button"
|
|
982
|
+
className={"dm-workflow-icon-btn dm-workflow-upgrade-btn" + (isServerlessWorkflow ? " is-serverless" : (upgradeState.showOnboarding ? " is-pulse" : ""))}
|
|
983
|
+
aria-label={isServerlessWorkflow ? "Serverless workflow — review persistence & scheduling" : "Upgrade to serverless environment to ensure persistence"}
|
|
984
|
+
data-tooltip={isServerlessWorkflow ? "Serverless — review persistence & scheduling" : "Upgrade to serverless environment to ensure persistence"}
|
|
985
|
+
aria-pressed={upgradeOpen}
|
|
986
|
+
onClick={() => setUpgradeOpen((open) => !open)}
|
|
987
|
+
>
|
|
988
|
+
<ArrowUpCircle size={14} />
|
|
989
|
+
</button>
|
|
990
|
+
)}
|
|
857
991
|
{showDiscardDraft && (
|
|
858
992
|
<button
|
|
859
993
|
type="button"
|
|
@@ -920,6 +1054,43 @@ export default function WorkflowSurface() {
|
|
|
920
1054
|
</div>
|
|
921
1055
|
) : null}
|
|
922
1056
|
|
|
1057
|
+
{/* One-time serverless upgrade onboarding — shows only when the operator
|
|
1058
|
+
has workflows but none are serverless, and hasn't dismissed it. */}
|
|
1059
|
+
{sandboxRow && !upgradeOpen && upgradeState.showOnboarding ? (
|
|
1060
|
+
<div className="workspace-template-context-banner dm-workflow-upgrade-nudge" role="note">
|
|
1061
|
+
<div>
|
|
1062
|
+
<strong>{upgradeState.headline}</strong>
|
|
1063
|
+
<span style={{ display: "block", marginTop: 2 }}>{upgradeState.subheadline}</span>
|
|
1064
|
+
</div>
|
|
1065
|
+
<div className="dm-workflow-upgrade-nudge-actions">
|
|
1066
|
+
<button type="button" className="dm-btn-primary-sm" onClick={() => setUpgradeOpen(true)}>
|
|
1067
|
+
<ArrowUpCircle size={13} /> Upgrade this workflow
|
|
1068
|
+
</button>
|
|
1069
|
+
<button type="button" className="dm-btn-ghost" onClick={dismissUpgradeOnboarding}>Not now</button>
|
|
1070
|
+
</div>
|
|
1071
|
+
</div>
|
|
1072
|
+
) : null}
|
|
1073
|
+
|
|
1074
|
+
{/* Serverless cockpit — same derivation + cockpit interface as the API
|
|
1075
|
+
Registry and sandbox lanes. Toggles patch the sandbox row; deep config
|
|
1076
|
+
(scheduler/adapter) routes to the object's Data Model drawer. */}
|
|
1077
|
+
{sandboxRow && upgradeOpen && serverlessState ? (
|
|
1078
|
+
<div className="dm-workflow-upgrade-panel">
|
|
1079
|
+
<div className="dm-workflow-upgrade-panel-head">
|
|
1080
|
+
<span className="dm-api-action-card-eyebrow">Persistence & scheduling</span>
|
|
1081
|
+
<button type="button" className="dm-workflow-icon-btn" aria-label="Close upgrade panel" onClick={() => { setUpgradeOpen(false); dismissUpgradeOnboarding(); }}>
|
|
1082
|
+
<X size={14} />
|
|
1083
|
+
</button>
|
|
1084
|
+
</div>
|
|
1085
|
+
<ApiRegistryCreationCockpit
|
|
1086
|
+
state={serverlessState}
|
|
1087
|
+
onAction={handleUpgradeAction}
|
|
1088
|
+
disabled={saving || publishing || running}
|
|
1089
|
+
eyebrow={isServerlessWorkflow ? "Serverless workflow" : "Upgrade to serverless"}
|
|
1090
|
+
/>
|
|
1091
|
+
</div>
|
|
1092
|
+
) : null}
|
|
1093
|
+
|
|
923
1094
|
{loading ? (
|
|
924
1095
|
<p className="dm-workflow-empty">Loading workflow…</p>
|
|
925
1096
|
) : error ? (
|
|
@@ -28,11 +28,9 @@ import path from "node:path";
|
|
|
28
28
|
import { pathToFileURL } from "node:url";
|
|
29
29
|
|
|
30
30
|
const staticLoaded = new Set();
|
|
31
|
-
|
|
31
|
+
const nativeImport = new Function("specifier", "return import(specifier)");
|
|
32
32
|
|
|
33
33
|
async function loadStaticResolversOnce() {
|
|
34
|
-
if (staticLoadDone) return;
|
|
35
|
-
staticLoadDone = true;
|
|
36
34
|
const resolversDir = path.resolve(/*turbopackIgnore: true*/ process.cwd(), "lib/adapters/integrations/resolvers");
|
|
37
35
|
try {
|
|
38
36
|
const entries = await fs.readdir(resolversDir);
|
|
@@ -42,7 +40,7 @@ async function loadStaticResolversOnce() {
|
|
|
42
40
|
if (staticLoaded.has(file)) return;
|
|
43
41
|
try {
|
|
44
42
|
const absolutePath = path.join(resolversDir, file);
|
|
45
|
-
await
|
|
43
|
+
await nativeImport(pathToFileURL(absolutePath).href);
|
|
46
44
|
staticLoaded.add(file);
|
|
47
45
|
} catch {
|
|
48
46
|
// Malformed resolver — skip silently; operator needs to fix the file
|