@burdenoff/fluidgrids-fe-sdk 2026.1029.6 → 2026.1029.8
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/ExecutionDetailPage-H6R3ZIXN.js +22 -0
- package/dist/{WorkflowsList-VA2HRYFG.js → ExecutionsListPage-TLD2E442.js} +9 -9
- package/dist/{WorkflowBuilder-PORH3H6P.js → WorkflowBuilder-XVHY7XWJ.js} +12 -12
- package/dist/{ExecutionsListPage-SCPWUXUL.js → WorkflowsList-3GXXXURR.js} +9 -8
- package/dist/{chunk-MNY2UNQH.js → chunk-2NG5VZWI.js} +1 -1
- package/dist/{chunk-CY6KX4RG.js → chunk-6AMNEX2Y.js} +6 -1
- package/dist/{chunk-LPGQTSI2.js → chunk-6CKDGT2N.js} +3 -3
- package/dist/{chunk-U6KI4AKI.js → chunk-6TMLIQHB.js} +199 -1
- package/dist/{chunk-LTVAUZ3M.js → chunk-G3KZOX52.js} +3 -3
- package/dist/{chunk-7PP6CRXS.js → chunk-GQTEHWWY.js} +26 -8
- package/dist/{chunk-LB62TAF7.js → chunk-H4AZBUWM.js} +1 -1
- package/dist/{chunk-57RS7DXZ.js → chunk-HWEKWYXQ.js} +117 -8
- package/dist/{chunk-7B2GRTUL.js → chunk-LJGC7RAL.js} +164 -101
- package/dist/{chunk-4TGUNOQQ.js → chunk-NAYPOEYM.js} +391 -112
- package/dist/{chunk-BWAUFSHC.js → chunk-NNPXN4DI.js} +5 -5
- package/dist/{chunk-QZM6EDGK.js → chunk-NUBPALBK.js} +1 -1
- package/dist/{chunk-YSUSSIWU.js → chunk-R7VHURPQ.js} +1 -1
- package/dist/{chunk-7SSZUX6E.js → chunk-S4JYBJ4X.js} +2 -2
- package/dist/{chunk-WTGBHE3J.js → chunk-T22LICGX.js} +118 -96
- package/dist/{chunk-63ZMEHZ4.js → chunk-TJ6RUV4R.js} +937 -26
- package/dist/{chunk-H364USFF.js → chunk-UIDJT3YK.js} +1 -1
- package/dist/{chunk-4XAPSIHY.js → chunk-UWNCFMHV.js} +183 -26
- package/dist/{chunk-MDPBO52Q.js → chunk-V5PA5KGV.js} +2 -2
- package/dist/{chunk-MQI7NH4Z.js → chunk-VEZ7G2FE.js} +145 -8
- package/dist/{chunk-YHTRCQ5M.js → chunk-WEXO3KAY.js} +4 -4
- package/dist/{chunk-7LFAWWVF.js → chunk-WTP343PG.js} +2 -2
- package/dist/{chunk-Z6EWB5ZG.js → chunk-X2J4ZXKD.js} +1492 -98
- package/dist/{chunk-6XZCYLAQ.js → chunk-XJBCRDWZ.js} +3 -3
- package/dist/{chunk-AVMI3XLM.js → chunk-XMKYZP6Q.js} +282 -18
- package/dist/{chunk-5GD6OXYW.js → chunk-Z6I6A47T.js} +1 -1
- package/dist/{config-T7BQ7AO2.js → config-VM7FTHMZ.js} +1 -1
- package/dist/executions.js +13 -13
- package/dist/history.js +5 -5
- package/dist/index.d.ts +2588 -26
- package/dist/index.js +36 -36
- package/dist/nodes.js +2 -2
- package/dist/observability.js +7 -7
- package/dist/settings.js +7 -7
- package/dist/templates.js +11 -11
- package/dist/{workflow-builder-CZFczcE7.d.ts → workflow-builder-BMGVSwpy.d.ts} +7 -0
- package/dist/workflow-builder.d.ts +1 -1
- package/dist/workflow-builder.js +13 -13
- package/dist/workflows-list.js +9 -9
- package/package.json +1 -1
- package/dist/ExecutionDetailPage-M6JAWY4Q.js +0 -21
|
@@ -2,18 +2,18 @@ import { deepClone, applyTemplateInputs } from './chunk-GEMNVFPK.js';
|
|
|
2
2
|
import { Input } from './chunk-IEVSFCFS.js';
|
|
3
3
|
import { Dialog as Dialog$1, DialogContent as DialogContent$1, DialogHeader as DialogHeader$1, DialogTitle as DialogTitle$1, DialogDescription as DialogDescription$1, DialogFooter } from './chunk-YXMFRQYV.js';
|
|
4
4
|
import { Badge as Badge$1, Button } from './chunk-BQXVT32O.js';
|
|
5
|
-
import { QuotaExhaustedDialog, useWorkflowCodeExport, orderedExportFiles, fileBaseName, downloadWorkflowCodeExport, isLosslessReport, sortFidelityItems, isLossyFidelityItem, lineOfNode } from './chunk-
|
|
6
|
-
import { EntityTagPicker, useWorkflowProposal, WorkflowProposalCard, useRunHistory, RunHistoryView, SignalRunDialog } from './chunk-
|
|
5
|
+
import { QuotaExhaustedDialog, useWorkflowCodeExport, orderedExportFiles, fileBaseName, downloadWorkflowCodeExport, isLosslessReport, sortFidelityItems, isLossyFidelityItem, lineOfNode } from './chunk-S4JYBJ4X.js';
|
|
6
|
+
import { EntityTagPicker, useWorkflowProposal, WorkflowProposalCard, useRunHistory, RunHistoryView, SignalRunDialog } from './chunk-T22LICGX.js';
|
|
7
7
|
import { AiCreditBalanceSlot } from './chunk-Y53CVZVV.js';
|
|
8
|
-
import { useRestoreWorkflowVersion, useWorkflowVersions, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-
|
|
9
|
-
import { isAgentNodeType, AgentDefinitionSelectField } from './chunk-
|
|
8
|
+
import { useRestoreWorkflowVersion, useWorkflowVersions, useActivateWorkflow, useDeleteWorkflow, useLazyWorkflowDefinition, useDeactivateWorkflow } from './chunk-G3KZOX52.js';
|
|
9
|
+
import { isAgentNodeType, AgentDefinitionSelectField } from './chunk-NUBPALBK.js';
|
|
10
10
|
import { FluidGridsDocsLink } from './chunk-4VJ3MDOV.js';
|
|
11
|
-
import { NODE_CONFIGS, createConfiguredNode, resolveOutputHandles, resolveInputHandles, isNodeConfigsInitialized, useFlowStore, getNodeDetail, useSaveStatusStore, isNodeTypeHiddenFromPalette, liveInternalOperations, resolveNodeOperation, readDisplayOptions, parseParameterValue, canAutosave, STICKY_NOTE_TYPE, isNodeTrigger, resolveUiSpec, RUNS_QUOTA_NAME, throwIfResultError, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, useDurableFunctionNodesEnabled, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useIsValidConnection, refetchStoreNodes, AVAILABLE_NODES, useInsertNode, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, CODE_WORKFLOW_NODE_TYPE, SdkPermissionButton,
|
|
11
|
+
import { leaseCallQueue, NODE_CONFIGS, createConfiguredNode, resolveOutputHandles, resolveInputHandles, isNodeConfigsInitialized, useFlowStore, getNodeDetail, useSaveStatusStore, isNodeTypeHiddenFromPalette, liveInternalOperations, resolveNodeOperation, readDisplayOptions, parseParameterValue, canAutosave, STICKY_NOTE_TYPE, isNodeTrigger, resolveUiSpec, RUNS_QUOTA_NAME, throwIfResultError, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, useEditLeaseStore, useEditLeaseLocked, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, useDurableFunctionNodesEnabled, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, useIsValidConnection, BuilderReadOnlyProvider, refetchStoreNodes, AVAILABLE_NODES, EDIT_SESSION_ID, useFluidGridsPermission, FLUIDGRIDS_PERMISSIONS, useInsertNode, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, CODE_WORKFLOW_NODE_TYPE, SdkPermissionButton, bannerOf, useSaveWorkflow, useBuilderReadOnly, fieldsFromValue, filterPaletteNodes, useFluidGridsAnalytics, sessionBeforeReload, forgetSessionForReload, releasesOnClose, editStateOf, workflowFingerprint, isLocked, buildStickyNode, useNodeRegistryRevision, fieldsFromIO, readCodeWorkflowState, useCodeWorkflowInterface, clearCodeWorkflowDefinitionCache, isParamVisible, ConnectionSelector, structuredParameterType, nodeAccent, NodeTypeIcon, NODES_METADATA, shouldReleaseForIdle, tickAction, rememberSessionForReload, useDurableParityEnabled, useConnections, ConnectionFormDialog, useFluidGridsFlag, FLUIDGRIDS_FLAGS, saveIndicatorOf, inAppLeaveTarget, declaredOutputFields, subscribeWorkflowSaved, pathToExpression, diagnosticsByPath, interfaceHandlers, declaredSignals, ExpressionEditor, toCodeMirrorDiagnostics, formatParameterValue, leaveNeedsConfirmation, phaseAfterAcquire, buildOperationSeed, describeOperationError, rememberOwnStatusChange, snapshotForSave, childRunIdOf, defaultSourcePath, projectLanguage, changedSourceFiles, isEditableSourcePath, sourceLanguageOf, interfaceFields, isImageIcon, NODES, synchronizeOperationUpdate, NodePropertyPanel, loadDefinitionJson, openRunQuotaUpgradePrompt, isTriggerOperation, canRenderOperationPanel, runPreparationOf, resolveOperationName, savesInPlace, AUTOSAVE_RETRY_DELAYS_MS, AUTOSAVE_DEBOUNCE_MS, rememberRevision, phaseAfterTakeOver } from './chunk-NAYPOEYM.js';
|
|
12
12
|
import { cn } from './chunk-JL7CASN5.js';
|
|
13
13
|
import { getGlobalStoreClient } from './chunk-PXIFUMLA.js';
|
|
14
|
-
import { getFluidGridsConfig } from './chunk-
|
|
14
|
+
import { getFluidGridsConfig } from './chunk-6AMNEX2Y.js';
|
|
15
15
|
import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, InstallWorkflowNodeDocument, InstallPurchasedNodeDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument, GetNodeInstallableVersionsDocument, OrganizationPrivateNodesDocument, InstallOrganizationPrivateNodeDocument, UninstallOrganizationPrivateNodeDocument } from './chunk-JUUYPCFY.js';
|
|
16
|
-
import { WorkspaceRunsQuotaDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, useRunFromNodeEligibilityQuery, EventRegistrationsDocument, WorkflowGenerationTemplatesDocument, WorkflowEnvironmentsDocument, WorkflowPromotionRequestsDocument, DeployWorkflowVersionToDevDocument, RequestWorkflowPromotionDocument, ApproveWorkflowPromotionDocument, RejectWorkflowPromotionDocument, CancelWorkflowPromotionDocument, UpdateWorkflowEnvironmentPolicyDocument, WorkflowGitRepositoryDocument, WorkflowGitPushesDocument, WorkflowGitCommitsDocument, LinkWorkflowGitRepositoryDocument, UnlinkWorkflowGitRepositoryDocument, PushWorkflowToGitDocument, WorkflowGitDiffDocument, RestoreWorkflowFromGitDocument, WorkflowAuthoringDocument, NodeStatesDocument, PreviewScheduleDocument, WorkflowCodeSourceDocument, WorkflowEditLeaseStatusDocument, BuildWorkflowCodeDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument } from './chunk-
|
|
16
|
+
import { WorkspaceRunsQuotaDocument, ReleaseWorkflowEditLeaseDocument, NodeSchemaIntrospectionDocument, useWorkflowPinnedDataQuery, usePinNodeDataMutation, useUnpinNodeDataMutation, useRunFromNodeEligibilityQuery, EventRegistrationsDocument, AcquireWorkflowEditLeaseDocument, WorkflowGenerationTemplatesDocument, WorkflowEnvironmentsDocument, WorkflowPromotionRequestsDocument, DeployWorkflowVersionToDevDocument, RequestWorkflowPromotionDocument, ApproveWorkflowPromotionDocument, RejectWorkflowPromotionDocument, CancelWorkflowPromotionDocument, UpdateWorkflowEnvironmentPolicyDocument, WorkflowGitRepositoryDocument, WorkflowGitPushesDocument, WorkflowGitCommitsDocument, LinkWorkflowGitRepositoryDocument, UnlinkWorkflowGitRepositoryDocument, PushWorkflowToGitDocument, WorkflowGitDiffDocument, RestoreWorkflowFromGitDocument, WorkflowAuthoringDocument, NodeStatesDocument, PreviewScheduleDocument, WorkflowEditLeaseDocument, WorkflowVersioningDocument, WorkflowVersionDrainageDocument, ActivateWorkflowVersionCheckedDocument, WorkflowDefinitionDocument, WorkflowCodeSourceDocument, WorkflowEditLeaseStatusDocument, BuildWorkflowCodeDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument, SetWorkflowRolloutDocument, DeleteWorkflowRolloutDocument, TakeOverWorkflowEditLeaseDocument } from './chunk-GQTEHWWY.js';
|
|
17
17
|
import { useTr } from './chunk-UULVIT25.js';
|
|
18
18
|
import { getFluidGridsClient, waitForFluidGridsClient, getFluidGridsClientSafe } from './chunk-NTWG3CJX.js';
|
|
19
19
|
import { __export } from './chunk-62GWEYJ5.js';
|
|
@@ -29,7 +29,8 @@ import { useEventBus } from '@burdenoff/fe-libs/shared/events';
|
|
|
29
29
|
import { useQuery, useMutation } from '@apollo/client/react';
|
|
30
30
|
import { gql as gql$1 } from '@apollo/client/core';
|
|
31
31
|
import 'jszip';
|
|
32
|
-
import { Sparkles, Star, Download, Eye, Maximize2, Undo2, Redo2, LayoutGrid, Keyboard, Plus, Trash2, GitBranch, Loader2, AlertCircle, Search, RefreshCw, History, GitCompareArrows, Play, RotateCcw, Layers, Upload, Rocket, ArrowRight, Check, X, Link2, Unlink, GitCompare, ExternalLink, GitCommitHorizontal, CircleHelp, CheckCircle2, Package, Info, Copy, BadgeCheck, DollarSign, Type, Code, Hash, List, Braces, Workflow, PlusCircle, ChevronDown, ChevronRight, AlertTriangle } from 'lucide-react';
|
|
32
|
+
import { Sparkles, Star, Download, Eye, Maximize2, Undo2, Redo2, LayoutGrid, Keyboard, Plus, Trash2, GitBranch, Loader2, AlertCircle, Search, RefreshCw, History, GitCompareArrows, Play, RotateCcw, Layers, Upload, Rocket, ArrowRight, Check, X, Link2, Unlink, GitCompare, ExternalLink, GitCommitHorizontal, CircleHelp, CheckCircle2, Package, SlidersHorizontal, Info, Copy, BadgeCheck, DollarSign, Type, Code, Hash, List, Braces, Workflow, PlusCircle, ChevronDown, ChevronRight, AlertTriangle } from 'lucide-react';
|
|
33
|
+
import { create } from 'zustand';
|
|
33
34
|
import { Icon } from '@iconify/react';
|
|
34
35
|
import { toast } from 'sonner';
|
|
35
36
|
import { useShallow, shallow } from 'zustand/shallow';
|
|
@@ -43,7 +44,6 @@ import { ThemeProvider as ThemeProvider$1 } from '@burdenoff/fe-libs/shared/prov
|
|
|
43
44
|
import '@xyflow/react/dist/style.css';
|
|
44
45
|
import { edgeColor, nodeCategoryColor } from '@burdenoff/fe-libs/shared/utils';
|
|
45
46
|
import { buildSchema, GraphQLObjectType, GraphQLInputObjectType, GraphQLEnumType, GraphQLInterfaceType, GraphQLUnionType, GraphQLNonNull, GraphQLList } from 'graphql';
|
|
46
|
-
import { create } from 'zustand';
|
|
47
47
|
import { nanoid as nanoid$1 } from 'nanoid/non-secure';
|
|
48
48
|
import { defineAgentTool, AgentToolError, useAgentTools } from '@burdenoff/fe-libs/shared/agent-tools';
|
|
49
49
|
import CodeMirror, { EditorView } from '@uiw/react-codemirror';
|
|
@@ -21676,6 +21676,266 @@ function FluidGridsGlyph() {
|
|
|
21676
21676
|
}
|
|
21677
21677
|
);
|
|
21678
21678
|
}
|
|
21679
|
+
var useWorkflowReloadStore = create()((set2) => ({
|
|
21680
|
+
nonce: 0,
|
|
21681
|
+
request: () => set2((state) => ({ nonce: state.nonce + 1 }))
|
|
21682
|
+
}));
|
|
21683
|
+
function requestWorkflowReload() {
|
|
21684
|
+
useWorkflowReloadStore.getState().request();
|
|
21685
|
+
}
|
|
21686
|
+
var TICK_MS = 5e3;
|
|
21687
|
+
var UNAVAILABLE = {
|
|
21688
|
+
available: false,
|
|
21689
|
+
held: false,
|
|
21690
|
+
heldBySelf: false
|
|
21691
|
+
};
|
|
21692
|
+
var leaseCalls = leaseCallQueue();
|
|
21693
|
+
function sessionStore() {
|
|
21694
|
+
try {
|
|
21695
|
+
return typeof window === "undefined" ? void 0 : window.sessionStorage;
|
|
21696
|
+
} catch {
|
|
21697
|
+
return void 0;
|
|
21698
|
+
}
|
|
21699
|
+
}
|
|
21700
|
+
function openWorkflow() {
|
|
21701
|
+
const { workflow } = useFlowStore.getState();
|
|
21702
|
+
const workflowKey = workflow.workflowKey || workflow.id;
|
|
21703
|
+
if (!workflow.dbId || !workflowKey) return null;
|
|
21704
|
+
return { workflowKey, version: workflow.version ?? "" };
|
|
21705
|
+
}
|
|
21706
|
+
function snapshotOpen() {
|
|
21707
|
+
const open2 = openWorkflow();
|
|
21708
|
+
if (!open2) return null;
|
|
21709
|
+
return { ...open2, generation: useFlowStore.getState().loadGeneration };
|
|
21710
|
+
}
|
|
21711
|
+
function stillOpen(snapshot) {
|
|
21712
|
+
const now = openWorkflow();
|
|
21713
|
+
return now?.workflowKey === snapshot.workflowKey && now.version === snapshot.version && useFlowStore.getState().loadGeneration === snapshot.generation && useEditLeaseStore.getState().workflowKey === snapshot.workflowKey;
|
|
21714
|
+
}
|
|
21715
|
+
function discardStaleAnswer(snapshot, answer) {
|
|
21716
|
+
if (!answer.heldBySelf) return;
|
|
21717
|
+
if (useEditLeaseStore.getState().workflowKey === snapshot.workflowKey) return;
|
|
21718
|
+
void releaseLease(snapshot.workflowKey);
|
|
21719
|
+
}
|
|
21720
|
+
function acquireLease(workflowKey, version2, resumeSessionId) {
|
|
21721
|
+
return leaseCalls.run(workflowKey, async () => {
|
|
21722
|
+
try {
|
|
21723
|
+
const { data } = throwIfResultError(
|
|
21724
|
+
await getFluidGridsClient().mutate({
|
|
21725
|
+
mutation: AcquireWorkflowEditLeaseDocument,
|
|
21726
|
+
variables: {
|
|
21727
|
+
input: {
|
|
21728
|
+
workflowKey,
|
|
21729
|
+
sessionId: EDIT_SESSION_ID,
|
|
21730
|
+
version: version2 || null,
|
|
21731
|
+
resumeSessionId
|
|
21732
|
+
}
|
|
21733
|
+
}
|
|
21734
|
+
})
|
|
21735
|
+
);
|
|
21736
|
+
return data?.acquireWorkflowEditLease ?? UNAVAILABLE;
|
|
21737
|
+
} catch {
|
|
21738
|
+
return UNAVAILABLE;
|
|
21739
|
+
}
|
|
21740
|
+
});
|
|
21741
|
+
}
|
|
21742
|
+
async function peekLease(workflowKey) {
|
|
21743
|
+
try {
|
|
21744
|
+
const { data } = throwIfResultError(
|
|
21745
|
+
await getFluidGridsClient().query({
|
|
21746
|
+
query: WorkflowEditLeaseDocument,
|
|
21747
|
+
variables: { workflowKey, sessionId: EDIT_SESSION_ID },
|
|
21748
|
+
fetchPolicy: "network-only"
|
|
21749
|
+
})
|
|
21750
|
+
);
|
|
21751
|
+
return data?.workflowEditLease ?? UNAVAILABLE;
|
|
21752
|
+
} catch {
|
|
21753
|
+
return UNAVAILABLE;
|
|
21754
|
+
}
|
|
21755
|
+
}
|
|
21756
|
+
function sendRelease(workflowKey, keepalive) {
|
|
21757
|
+
return getFluidGridsClient().mutate({
|
|
21758
|
+
mutation: ReleaseWorkflowEditLeaseDocument,
|
|
21759
|
+
variables: { workflowKey, sessionId: EDIT_SESSION_ID },
|
|
21760
|
+
...keepalive ? { context: { fetchOptions: { keepalive: true } } } : {}
|
|
21761
|
+
}).then(() => void 0).catch(() => void 0);
|
|
21762
|
+
}
|
|
21763
|
+
function releaseLease(workflowKey) {
|
|
21764
|
+
return leaseCalls.run(workflowKey, () => sendRelease(workflowKey, false));
|
|
21765
|
+
}
|
|
21766
|
+
function recordAcquired(answer) {
|
|
21767
|
+
const lease = useEditLeaseStore.getState();
|
|
21768
|
+
lease.actions.record(phaseAfterAcquire(lease.phase, answer), answer);
|
|
21769
|
+
}
|
|
21770
|
+
async function takeOverEditLease() {
|
|
21771
|
+
const open2 = snapshotOpen();
|
|
21772
|
+
if (!open2) return;
|
|
21773
|
+
const answer = await leaseCalls.run(open2.workflowKey, async () => {
|
|
21774
|
+
try {
|
|
21775
|
+
const { data } = throwIfResultError(
|
|
21776
|
+
await getFluidGridsClient().mutate({
|
|
21777
|
+
mutation: TakeOverWorkflowEditLeaseDocument,
|
|
21778
|
+
variables: {
|
|
21779
|
+
input: {
|
|
21780
|
+
workflowKey: open2.workflowKey,
|
|
21781
|
+
sessionId: EDIT_SESSION_ID,
|
|
21782
|
+
version: open2.version || null
|
|
21783
|
+
}
|
|
21784
|
+
}
|
|
21785
|
+
})
|
|
21786
|
+
);
|
|
21787
|
+
return data?.takeOverWorkflowEditLease ?? UNAVAILABLE;
|
|
21788
|
+
} catch {
|
|
21789
|
+
return UNAVAILABLE;
|
|
21790
|
+
}
|
|
21791
|
+
});
|
|
21792
|
+
if (!stillOpen(open2)) {
|
|
21793
|
+
discardStaleAnswer(open2, answer);
|
|
21794
|
+
return;
|
|
21795
|
+
}
|
|
21796
|
+
const next = phaseAfterTakeOver(answer);
|
|
21797
|
+
useEditLeaseStore.getState().actions.record(next, answer);
|
|
21798
|
+
if (next === "reloading") requestWorkflowReload();
|
|
21799
|
+
}
|
|
21800
|
+
async function resumeEditLease() {
|
|
21801
|
+
const open2 = snapshotOpen();
|
|
21802
|
+
if (!open2) return;
|
|
21803
|
+
const answer = await acquireLease(open2.workflowKey, open2.version, null);
|
|
21804
|
+
if (!stillOpen(open2)) {
|
|
21805
|
+
discardStaleAnswer(open2, answer);
|
|
21806
|
+
return;
|
|
21807
|
+
}
|
|
21808
|
+
recordAcquired(answer);
|
|
21809
|
+
}
|
|
21810
|
+
function releaseLeaseKeptForReload() {
|
|
21811
|
+
const lease = useEditLeaseStore.getState();
|
|
21812
|
+
const workflowKey = lease.workflowKey;
|
|
21813
|
+
if (lease.phase !== "reloading" || !workflowKey) return;
|
|
21814
|
+
void releaseLease(workflowKey);
|
|
21815
|
+
lease.actions.reset();
|
|
21816
|
+
}
|
|
21817
|
+
function reloadLatestVersion() {
|
|
21818
|
+
const lease = useEditLeaseStore.getState();
|
|
21819
|
+
if (lease.phase === "holding") lease.actions.record("reloading");
|
|
21820
|
+
requestWorkflowReload();
|
|
21821
|
+
}
|
|
21822
|
+
function useEditLease(enabled) {
|
|
21823
|
+
const workflowKey = useFlowStore(
|
|
21824
|
+
(s) => s.workflow.dbId ? s.workflow.workflowKey || s.workflow.id : ""
|
|
21825
|
+
);
|
|
21826
|
+
useEffect(() => {
|
|
21827
|
+
const lease = useEditLeaseStore.getState();
|
|
21828
|
+
if (!enabled || !workflowKey) {
|
|
21829
|
+
lease.actions.reset();
|
|
21830
|
+
return;
|
|
21831
|
+
}
|
|
21832
|
+
lease.actions.begin(workflowKey);
|
|
21833
|
+
let disposed = false;
|
|
21834
|
+
let inFlight = false;
|
|
21835
|
+
let lastRenewAt = 0;
|
|
21836
|
+
let lastPeekAt = 0;
|
|
21837
|
+
let lastInputAt = Date.now();
|
|
21838
|
+
const visible = () => typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
21839
|
+
const phase = () => useEditLeaseStore.getState().phase;
|
|
21840
|
+
const version2 = () => useFlowStore.getState().workflow.version ?? "";
|
|
21841
|
+
const renew = async (resumeSessionId = null) => {
|
|
21842
|
+
if (inFlight) return;
|
|
21843
|
+
inFlight = true;
|
|
21844
|
+
lastRenewAt = Date.now();
|
|
21845
|
+
try {
|
|
21846
|
+
const answer = await acquireLease(
|
|
21847
|
+
workflowKey,
|
|
21848
|
+
version2(),
|
|
21849
|
+
resumeSessionId
|
|
21850
|
+
);
|
|
21851
|
+
if (!disposed && phase() !== "idle") recordAcquired(answer);
|
|
21852
|
+
} finally {
|
|
21853
|
+
inFlight = false;
|
|
21854
|
+
}
|
|
21855
|
+
};
|
|
21856
|
+
const peek = async () => {
|
|
21857
|
+
if (inFlight) return;
|
|
21858
|
+
inFlight = true;
|
|
21859
|
+
lastPeekAt = Date.now();
|
|
21860
|
+
try {
|
|
21861
|
+
const answer = await peekLease(workflowKey);
|
|
21862
|
+
if (disposed || !answer.available) return;
|
|
21863
|
+
const current = useEditLeaseStore.getState();
|
|
21864
|
+
current.actions.record(current.phase, answer);
|
|
21865
|
+
} finally {
|
|
21866
|
+
inFlight = false;
|
|
21867
|
+
}
|
|
21868
|
+
};
|
|
21869
|
+
const tick = () => {
|
|
21870
|
+
if (disposed) return;
|
|
21871
|
+
const now = Date.now();
|
|
21872
|
+
if (shouldReleaseForIdle(phase(), lastInputAt, now)) {
|
|
21873
|
+
useEditLeaseStore.getState().actions.record("idle");
|
|
21874
|
+
void releaseLease(workflowKey);
|
|
21875
|
+
return;
|
|
21876
|
+
}
|
|
21877
|
+
const action = tickAction(
|
|
21878
|
+
phase(),
|
|
21879
|
+
{ lastRenewAt, lastPeekAt, visible: visible() },
|
|
21880
|
+
now
|
|
21881
|
+
);
|
|
21882
|
+
if (action === "renew") void renew();
|
|
21883
|
+
else if (action === "peek") void peek();
|
|
21884
|
+
};
|
|
21885
|
+
const resume = sessionBeforeReload(sessionStore(), workflowKey);
|
|
21886
|
+
forgetSessionForReload(sessionStore(), workflowKey);
|
|
21887
|
+
void renew(resume);
|
|
21888
|
+
const timer = setInterval(tick, TICK_MS);
|
|
21889
|
+
let reloadSeen = false;
|
|
21890
|
+
const unsubscribeFlow = useFlowStore.subscribe((state, previous) => {
|
|
21891
|
+
if (state.loadGeneration !== previous.loadGeneration) reloadSeen = true;
|
|
21892
|
+
if (reloadSeen && state.workflow.dbId && phase() === "reloading") {
|
|
21893
|
+
reloadSeen = false;
|
|
21894
|
+
void renew();
|
|
21895
|
+
}
|
|
21896
|
+
});
|
|
21897
|
+
const onVisible = () => {
|
|
21898
|
+
if (!visible()) return;
|
|
21899
|
+
lastRenewAt = 0;
|
|
21900
|
+
lastPeekAt = 0;
|
|
21901
|
+
tick();
|
|
21902
|
+
};
|
|
21903
|
+
const onInput = () => {
|
|
21904
|
+
lastInputAt = Date.now();
|
|
21905
|
+
};
|
|
21906
|
+
const onPageHide = () => {
|
|
21907
|
+
if (phase() !== "holding") return;
|
|
21908
|
+
rememberSessionForReload(sessionStore(), workflowKey, EDIT_SESSION_ID);
|
|
21909
|
+
void sendRelease(workflowKey, true);
|
|
21910
|
+
};
|
|
21911
|
+
const onPageShow = (event) => {
|
|
21912
|
+
if (event.persisted) void renew(EDIT_SESSION_ID);
|
|
21913
|
+
};
|
|
21914
|
+
const inputEvents = ["pointerdown", "keydown", "wheel"];
|
|
21915
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
21916
|
+
window.addEventListener("online", onVisible);
|
|
21917
|
+
window.addEventListener("pagehide", onPageHide);
|
|
21918
|
+
window.addEventListener("pageshow", onPageShow);
|
|
21919
|
+
for (const name of inputEvents) {
|
|
21920
|
+
window.addEventListener(name, onInput, { capture: true, passive: true });
|
|
21921
|
+
}
|
|
21922
|
+
return () => {
|
|
21923
|
+
disposed = true;
|
|
21924
|
+
clearInterval(timer);
|
|
21925
|
+
unsubscribeFlow();
|
|
21926
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
21927
|
+
window.removeEventListener("online", onVisible);
|
|
21928
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
21929
|
+
window.removeEventListener("pageshow", onPageShow);
|
|
21930
|
+
for (const name of inputEvents) {
|
|
21931
|
+
window.removeEventListener(name, onInput, { capture: true });
|
|
21932
|
+
}
|
|
21933
|
+
const current = useEditLeaseStore.getState();
|
|
21934
|
+
if (releasesOnClose(current.phase)) void releaseLease(workflowKey);
|
|
21935
|
+
if (current.phase !== "reloading") current.actions.reset();
|
|
21936
|
+
};
|
|
21937
|
+
}, [enabled, workflowKey]);
|
|
21938
|
+
}
|
|
21679
21939
|
function findEdges(node2, connectedEdges) {
|
|
21680
21940
|
const outgoingEdges = connectedEdges.filter(
|
|
21681
21941
|
(edge) => edge.source === node2.id
|
|
@@ -21752,6 +22012,9 @@ function useFlowValidator(onValidate) {
|
|
|
21752
22012
|
}
|
|
21753
22013
|
|
|
21754
22014
|
// src/builder/lib/save-guards.ts
|
|
22015
|
+
function editingLeaseLocked() {
|
|
22016
|
+
return isLocked(useEditLeaseStore.getState().phase);
|
|
22017
|
+
}
|
|
21755
22018
|
function autosaveAllowedFor(workflow) {
|
|
21756
22019
|
return useSaveStatusStore.getState().autosaveEnabled && canAutosave(workflow);
|
|
21757
22020
|
}
|
|
@@ -21768,7 +22031,7 @@ function editStateFor(state) {
|
|
|
21768
22031
|
}
|
|
21769
22032
|
function departingSave(state) {
|
|
21770
22033
|
const status = useSaveStatusStore.getState();
|
|
21771
|
-
if (status.autosavePaused) return null;
|
|
22034
|
+
if (status.autosavePaused || editingLeaseLocked()) return null;
|
|
21772
22035
|
if (editStateFor(state) !== "dirty") return null;
|
|
21773
22036
|
if (!autosaveAllowedFor(state.workflow)) return null;
|
|
21774
22037
|
const { nodes, edges } = state.workflow;
|
|
@@ -21784,7 +22047,9 @@ function unsavedState() {
|
|
|
21784
22047
|
return {
|
|
21785
22048
|
// Checked fresh: the dirty flag trails the last edit by a moment.
|
|
21786
22049
|
dirty: status.dirty || editStateFor(flow) === "dirty",
|
|
21787
|
-
|
|
22050
|
+
// A paused autosave (a refused save), or a page someone else is editing
|
|
22051
|
+
// from, does not save on the way out either.
|
|
22052
|
+
autosaveAllowed: autosaveAllowedFor(flow.workflow) && !status.autosavePaused && !editingLeaseLocked(),
|
|
21788
22053
|
incomplete: status.incomplete || !isFlowComplete(flow.workflow.nodes, flow.workflow.edges),
|
|
21789
22054
|
failed: status.failure !== null
|
|
21790
22055
|
};
|
|
@@ -21814,6 +22079,10 @@ function watchLeavingLosesChanges(onChange, delayMs) {
|
|
|
21814
22079
|
if (timer) clearTimeout(timer);
|
|
21815
22080
|
timer = setTimeout(settle2, delayMs);
|
|
21816
22081
|
};
|
|
22082
|
+
const settleNow = () => {
|
|
22083
|
+
if (timer) clearTimeout(timer);
|
|
22084
|
+
settle2();
|
|
22085
|
+
};
|
|
21817
22086
|
settle2();
|
|
21818
22087
|
const unsubscribeFlow = useFlowStore.subscribe((state, previous) => {
|
|
21819
22088
|
if (!touchesSavedFields(state, previous)) return;
|
|
@@ -21821,9 +22090,13 @@ function watchLeavingLosesChanges(onChange, delayMs) {
|
|
|
21821
22090
|
settleLater();
|
|
21822
22091
|
});
|
|
21823
22092
|
const unsubscribeStatus = useSaveStatusStore.subscribe(settleLater);
|
|
22093
|
+
const unsubscribeLease = useEditLeaseStore.subscribe((state, previous) => {
|
|
22094
|
+
if (isLocked(state.phase) !== isLocked(previous.phase)) settleNow();
|
|
22095
|
+
});
|
|
21824
22096
|
return () => {
|
|
21825
22097
|
unsubscribeFlow();
|
|
21826
22098
|
unsubscribeStatus();
|
|
22099
|
+
unsubscribeLease();
|
|
21827
22100
|
if (timer) clearTimeout(timer);
|
|
21828
22101
|
};
|
|
21829
22102
|
}
|
|
@@ -25200,7 +25473,7 @@ function DesktopSidebarFragment({
|
|
|
25200
25473
|
if (nodesToInstall.length > 0) {
|
|
25201
25474
|
const { getGlobalStoreClient: getStore } = await import('./global-client-KLOVTVPP.js');
|
|
25202
25475
|
const { InstallWorkflowNodeDocument: InstallWorkflowNodeDocument2 } = await import('./global-operations-D2USVOPM.js');
|
|
25203
|
-
const { getFluidGridsConfig: getFluidGridsConfig3 } = await import('./config-
|
|
25476
|
+
const { getFluidGridsConfig: getFluidGridsConfig3 } = await import('./config-VM7FTHMZ.js');
|
|
25204
25477
|
const storeClient = getStore();
|
|
25205
25478
|
const cfg = getFluidGridsConfig3();
|
|
25206
25479
|
for (let i = 0; i < nodesToInstall.length; i++) {
|
|
@@ -25261,7 +25534,7 @@ function DesktopSidebarFragment({
|
|
|
25261
25534
|
);
|
|
25262
25535
|
}
|
|
25263
25536
|
const { getFluidGridsClient: getFluidGridsClient2 } = await import('./client-T7BHWM2H.js');
|
|
25264
|
-
const { getFluidGridsConfig: getFluidGridsConfig2 } = await import('./config-
|
|
25537
|
+
const { getFluidGridsConfig: getFluidGridsConfig2 } = await import('./config-VM7FTHMZ.js');
|
|
25265
25538
|
const { gql: gql10 } = await import('@apollo/client/core');
|
|
25266
25539
|
const IMPORT_MUTATION = gql10`
|
|
25267
25540
|
mutation ImportWorkflowTemplate(
|
|
@@ -26743,8 +27016,8 @@ var reducer = (state, action) => {
|
|
|
26743
27016
|
if (toastId) {
|
|
26744
27017
|
addToRemoveQueue(toastId);
|
|
26745
27018
|
} else {
|
|
26746
|
-
state.toasts.forEach((
|
|
26747
|
-
addToRemoveQueue(
|
|
27019
|
+
state.toasts.forEach((toast18) => {
|
|
27020
|
+
addToRemoveQueue(toast18.id);
|
|
26748
27021
|
});
|
|
26749
27022
|
}
|
|
26750
27023
|
return {
|
|
@@ -28120,7 +28393,7 @@ function VisualMapperContent({
|
|
|
28120
28393
|
mapping,
|
|
28121
28394
|
onMappingChange
|
|
28122
28395
|
}) {
|
|
28123
|
-
const { toast:
|
|
28396
|
+
const { toast: toast18 } = useToast();
|
|
28124
28397
|
const tr = useTr();
|
|
28125
28398
|
const reactFlowWrapper = useRef(null);
|
|
28126
28399
|
const [selectedSourceNode, setSelectedSourceNode] = useState(null);
|
|
@@ -28140,7 +28413,7 @@ function VisualMapperContent({
|
|
|
28140
28413
|
targetOperation
|
|
28141
28414
|
);
|
|
28142
28415
|
if (generatedNodes.length === 0) {
|
|
28143
|
-
|
|
28416
|
+
toast18({
|
|
28144
28417
|
title: tr(
|
|
28145
28418
|
"fluidgrids.builder.visualMapper.noFieldsFoundTitle",
|
|
28146
28419
|
"No fields found"
|
|
@@ -28166,7 +28439,7 @@ function VisualMapperContent({
|
|
|
28166
28439
|
targetNode,
|
|
28167
28440
|
targetOperation,
|
|
28168
28441
|
setNodes,
|
|
28169
|
-
|
|
28442
|
+
toast18,
|
|
28170
28443
|
tr
|
|
28171
28444
|
]);
|
|
28172
28445
|
useEffect(() => {
|
|
@@ -28273,7 +28546,7 @@ function VisualMapperContent({
|
|
|
28273
28546
|
}
|
|
28274
28547
|
onMappingChange(updatedMapping);
|
|
28275
28548
|
if (isCompatible) {
|
|
28276
|
-
|
|
28549
|
+
toast18({
|
|
28277
28550
|
title: tr(
|
|
28278
28551
|
"fluidgrids.builder.visualMapper.mappingCreatedTitle",
|
|
28279
28552
|
"Mapping created"
|
|
@@ -28281,7 +28554,7 @@ function VisualMapperContent({
|
|
|
28281
28554
|
description: `Mapped ${sourcePath} (${sourceType}) to ${targetPath} (${targetType})`
|
|
28282
28555
|
});
|
|
28283
28556
|
} else {
|
|
28284
|
-
|
|
28557
|
+
toast18({
|
|
28285
28558
|
title: tr(
|
|
28286
28559
|
"fluidgrids.builder.visualMapper.typeMismatchTitle",
|
|
28287
28560
|
"Type mismatch warning"
|
|
@@ -28291,7 +28564,7 @@ function VisualMapperContent({
|
|
|
28291
28564
|
});
|
|
28292
28565
|
}
|
|
28293
28566
|
} else {
|
|
28294
|
-
|
|
28567
|
+
toast18({
|
|
28295
28568
|
title: tr(
|
|
28296
28569
|
"fluidgrids.builder.visualMapper.invalidMappingTitle",
|
|
28297
28570
|
"Invalid mapping"
|
|
@@ -28304,7 +28577,7 @@ function VisualMapperContent({
|
|
|
28304
28577
|
});
|
|
28305
28578
|
}
|
|
28306
28579
|
},
|
|
28307
|
-
[nodes, mapping, onMappingChange,
|
|
28580
|
+
[nodes, mapping, onMappingChange, toast18, tr, setEdges]
|
|
28308
28581
|
);
|
|
28309
28582
|
const onEdgeDelete = useCallback(
|
|
28310
28583
|
(edge) => {
|
|
@@ -28361,7 +28634,7 @@ function VisualMapperContent({
|
|
|
28361
28634
|
const handleSaveMappingDialog = (expression, targetFieldName) => {
|
|
28362
28635
|
const targetPath = targetFieldName || selectedTargetNode?.data?.path;
|
|
28363
28636
|
if (!targetPath) {
|
|
28364
|
-
|
|
28637
|
+
toast18({
|
|
28365
28638
|
title: tr(
|
|
28366
28639
|
"fluidgrids.builder.visualMapper.noTargetFieldTitle",
|
|
28367
28640
|
"No target field specified"
|
|
@@ -28393,7 +28666,7 @@ function VisualMapperContent({
|
|
|
28393
28666
|
}
|
|
28394
28667
|
onMappingChange(updatedMapping);
|
|
28395
28668
|
const mappingType = detectMappingType(expression);
|
|
28396
|
-
|
|
28669
|
+
toast18({
|
|
28397
28670
|
title: `${mappingType.charAt(0).toUpperCase() + mappingType.slice(1)} mapping created`,
|
|
28398
28671
|
description: `${tr("fluidgrids.builder.visualMapper.appliedMappingTo", "Applied mapping to")} ${targetPath}`
|
|
28399
28672
|
});
|
|
@@ -28692,7 +28965,7 @@ function MappingEditor({
|
|
|
28692
28965
|
setEdges,
|
|
28693
28966
|
edgeId
|
|
28694
28967
|
}) {
|
|
28695
|
-
const { toast:
|
|
28968
|
+
const { toast: toast18 } = useToast();
|
|
28696
28969
|
const tr = useTr();
|
|
28697
28970
|
const [mappingJson, setMappingJson] = useState({});
|
|
28698
28971
|
const [jsonDataString, setJsonDataString] = useState(
|
|
@@ -28816,7 +29089,7 @@ function MappingEditor({
|
|
|
28816
29089
|
const handleSaveMapping = () => {
|
|
28817
29090
|
try {
|
|
28818
29091
|
checkJsonValidity();
|
|
28819
|
-
|
|
29092
|
+
toast18({
|
|
28820
29093
|
title: tr(
|
|
28821
29094
|
"fluidgrids.builder.mappingEditor.mappingSavedTitle",
|
|
28822
29095
|
"Mapping saved"
|
|
@@ -28827,7 +29100,7 @@ function MappingEditor({
|
|
|
28827
29100
|
)
|
|
28828
29101
|
});
|
|
28829
29102
|
} catch (error62) {
|
|
28830
|
-
|
|
29103
|
+
toast18({
|
|
28831
29104
|
title: tr(
|
|
28832
29105
|
"fluidgrids.builder.mappingEditor.errorSavingTitle",
|
|
28833
29106
|
"Error saving mapping"
|
|
@@ -28846,7 +29119,7 @@ function MappingEditor({
|
|
|
28846
29119
|
const parsedData = checkJsonValidity();
|
|
28847
29120
|
const result = await applyMapping(parsedData, sampleInput);
|
|
28848
29121
|
setPreviewOutput(result);
|
|
28849
|
-
|
|
29122
|
+
toast18({
|
|
28850
29123
|
title: tr(
|
|
28851
29124
|
"fluidgrids.builder.mappingEditor.mappingTestedTitle",
|
|
28852
29125
|
"Mapping tested"
|
|
@@ -28858,7 +29131,7 @@ function MappingEditor({
|
|
|
28858
29131
|
});
|
|
28859
29132
|
} catch (error62) {
|
|
28860
29133
|
console.error("Test mapping error:", error62);
|
|
28861
|
-
|
|
29134
|
+
toast18({
|
|
28862
29135
|
title: tr(
|
|
28863
29136
|
"fluidgrids.builder.mappingEditor.mappingTestFailedTitle",
|
|
28864
29137
|
"Mapping test failed"
|
|
@@ -31501,6 +31774,7 @@ function CustomDeletableEdge(props) {
|
|
|
31501
31774
|
markerEnd
|
|
31502
31775
|
} = props;
|
|
31503
31776
|
const { setEdges, getEdges, getNode } = useReactFlow();
|
|
31777
|
+
const readOnly = useBuilderReadOnly();
|
|
31504
31778
|
const tr = useTr();
|
|
31505
31779
|
const nodeStatuses = useFlowStore(
|
|
31506
31780
|
useShallow((s) => s.execution.nodeStatuses)
|
|
@@ -31522,6 +31796,7 @@ function CustomDeletableEdge(props) {
|
|
|
31522
31796
|
targetPosition
|
|
31523
31797
|
});
|
|
31524
31798
|
useEffect(() => {
|
|
31799
|
+
if (readOnly) return;
|
|
31525
31800
|
const edges = getEdges();
|
|
31526
31801
|
const currentEdge = edges?.find((e) => e.id === id);
|
|
31527
31802
|
if (currentEdge && !currentEdge.conditions) {
|
|
@@ -31534,10 +31809,13 @@ function CustomDeletableEdge(props) {
|
|
|
31534
31809
|
});
|
|
31535
31810
|
});
|
|
31536
31811
|
}
|
|
31537
|
-
}, [id, setEdges, getEdges]);
|
|
31538
|
-
const [
|
|
31539
|
-
const [
|
|
31540
|
-
const [
|
|
31812
|
+
}, [id, setEdges, getEdges, readOnly]);
|
|
31813
|
+
const [mapperRequested, setShowModal] = useState(false);
|
|
31814
|
+
const [conditionRequested, setConditionShowModal] = useState(false);
|
|
31815
|
+
const [hovered, setIsHovered] = useState(false);
|
|
31816
|
+
const showModal = mapperRequested && !readOnly;
|
|
31817
|
+
const showConditionModal = conditionRequested && !readOnly;
|
|
31818
|
+
const isHovered = hovered && !readOnly;
|
|
31541
31819
|
const [sourceSchema, setSourceSchema] = useState(null);
|
|
31542
31820
|
const [targetSchema, setTargetSchema] = useState(null);
|
|
31543
31821
|
const [isLoadingSchemas, setIsLoadingSchemas] = useState(false);
|
|
@@ -33122,7 +33400,8 @@ function ControlBtn({
|
|
|
33122
33400
|
function CanvasControls() {
|
|
33123
33401
|
const tr = useTr();
|
|
33124
33402
|
const searchParams = new URLSearchParams(window.location.search);
|
|
33125
|
-
const
|
|
33403
|
+
const leaseLocked = useEditLeaseLocked();
|
|
33404
|
+
const isReadOnly = searchParams.get("readonly") === "true" || leaseLocked;
|
|
33126
33405
|
const [showMinimap, setShowMinimap] = useState(false);
|
|
33127
33406
|
const [edgesHidden, setEdgesHidden] = useState(false);
|
|
33128
33407
|
const [shortcutsHelpOpen, setShortcutsHelpOpen] = useState(false);
|
|
@@ -34569,6 +34848,24 @@ function nodeSubtitle(node2) {
|
|
|
34569
34848
|
const data = asRecord(node2?.data);
|
|
34570
34849
|
return typeof data?.operation_name === "string" ? data.operation_name : void 0;
|
|
34571
34850
|
}
|
|
34851
|
+
function leaveUnchanged() {
|
|
34852
|
+
}
|
|
34853
|
+
function readOnlyNodeConfig(api) {
|
|
34854
|
+
return {
|
|
34855
|
+
...api,
|
|
34856
|
+
writeFixed: leaveUnchanged,
|
|
34857
|
+
writeMapping: leaveUnchanged,
|
|
34858
|
+
handleConnectionsChange: leaveUnchanged,
|
|
34859
|
+
toggleMode: leaveUnchanged,
|
|
34860
|
+
// A field dropped on a read-only form is refused, not opened as a link.
|
|
34861
|
+
handleDropOnParam: () => (e) => e.preventDefault(),
|
|
34862
|
+
writeErrorConfig: leaveUnchanged,
|
|
34863
|
+
writeNotes: leaveUnchanged,
|
|
34864
|
+
writeExecutionSettings: leaveUnchanged,
|
|
34865
|
+
writeNodeDataField: leaveUnchanged,
|
|
34866
|
+
readOnly: true
|
|
34867
|
+
};
|
|
34868
|
+
}
|
|
34572
34869
|
function runOnOf(executionSettings) {
|
|
34573
34870
|
const runOn = asRecord(executionSettings?.runOn);
|
|
34574
34871
|
return runOn?.kind === "runner" && typeof runOn.runnerId === "string" ? { kind: "runner", runnerId: runOn.runnerId } : null;
|
|
@@ -34577,6 +34874,7 @@ function useNodeConfig(target, options) {
|
|
|
34577
34874
|
const nodes = useFlowStore((s) => s.workflow.nodes);
|
|
34578
34875
|
const edges = useFlowStore((s) => s.workflow.edges);
|
|
34579
34876
|
const workflowKey = useFlowStore((s) => s.workflow.workflowKey);
|
|
34877
|
+
const readOnly = useBuilderReadOnly();
|
|
34580
34878
|
const executionLogs = useFlowStore((s) => s.execution.logs);
|
|
34581
34879
|
const currentRunId = useFlowStore((s) => s.execution.currentRunId);
|
|
34582
34880
|
const nodeId2 = target?.nodeId;
|
|
@@ -34841,7 +35139,7 @@ function useNodeConfig(target, options) {
|
|
|
34841
35139
|
setModeByField((m) => ({ ...m, [field]: "expression" }));
|
|
34842
35140
|
}
|
|
34843
35141
|
};
|
|
34844
|
-
|
|
35142
|
+
const api = {
|
|
34845
35143
|
node: node2,
|
|
34846
35144
|
nodes,
|
|
34847
35145
|
incoming,
|
|
@@ -34882,8 +35180,10 @@ function useNodeConfig(target, options) {
|
|
|
34882
35180
|
executeOnce,
|
|
34883
35181
|
runOn,
|
|
34884
35182
|
writeExecutionSettings,
|
|
34885
|
-
writeNodeDataField
|
|
35183
|
+
writeNodeDataField,
|
|
35184
|
+
readOnly: false
|
|
34886
35185
|
};
|
|
35186
|
+
return readOnly ? readOnlyNodeConfig(api) : api;
|
|
34887
35187
|
}
|
|
34888
35188
|
|
|
34889
35189
|
// src/builder/agentTools.ts
|
|
@@ -35993,7 +36293,7 @@ function CodeEditorField({
|
|
|
35993
36293
|
placeholder,
|
|
35994
36294
|
label,
|
|
35995
36295
|
onChange,
|
|
35996
|
-
readOnly = false,
|
|
36296
|
+
readOnly: readOnlyProp = false,
|
|
35997
36297
|
diagnostics,
|
|
35998
36298
|
minHeight = "180px",
|
|
35999
36299
|
maxHeight = "420px",
|
|
@@ -36002,6 +36302,8 @@ function CodeEditorField({
|
|
|
36002
36302
|
}) {
|
|
36003
36303
|
const dark = useIsDarkTheme();
|
|
36004
36304
|
const withLint = diagnostics !== void 0;
|
|
36305
|
+
const builderReadOnly = useBuilderReadOnly();
|
|
36306
|
+
const readOnly = readOnlyProp || builderReadOnly;
|
|
36005
36307
|
const extensions = useMemo(
|
|
36006
36308
|
() => [
|
|
36007
36309
|
languageExtension(language),
|
|
@@ -36298,11 +36600,6 @@ function useWebhookTestListener(target, onReceived) {
|
|
|
36298
36600
|
}, [workflowKey, version2, triggerNodeId, stopOpenListener]);
|
|
36299
36601
|
return { listener, busy, error: error62, listen, stop };
|
|
36300
36602
|
}
|
|
36301
|
-
var BuilderReadOnlyContext = createContext(false);
|
|
36302
|
-
var BuilderReadOnlyProvider = BuilderReadOnlyContext.Provider;
|
|
36303
|
-
function useBuilderReadOnly() {
|
|
36304
|
-
return useContext(BuilderReadOnlyContext);
|
|
36305
|
-
}
|
|
36306
36603
|
var SECTION_LABEL2 = "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground";
|
|
36307
36604
|
function isSafeHttpUrl(value) {
|
|
36308
36605
|
try {
|
|
@@ -39717,6 +40014,21 @@ function Field({
|
|
|
39717
40014
|
children
|
|
39718
40015
|
] });
|
|
39719
40016
|
}
|
|
40017
|
+
function ReadOnlyFieldset({
|
|
40018
|
+
className,
|
|
40019
|
+
children
|
|
40020
|
+
}) {
|
|
40021
|
+
const readOnly = useBuilderReadOnly();
|
|
40022
|
+
return /* @__PURE__ */ jsx(
|
|
40023
|
+
"fieldset",
|
|
40024
|
+
{
|
|
40025
|
+
disabled: readOnly,
|
|
40026
|
+
"data-readonly": readOnly ? "true" : void 0,
|
|
40027
|
+
className: cn$1("m-0 min-w-0 border-0 p-0", className),
|
|
40028
|
+
children
|
|
40029
|
+
}
|
|
40030
|
+
);
|
|
40031
|
+
}
|
|
39720
40032
|
function useMediaQuery(query) {
|
|
39721
40033
|
const [matches, setMatches] = React4.useState(false);
|
|
39722
40034
|
React4.useEffect(() => {
|
|
@@ -40910,7 +41222,7 @@ function NodeDetailView() {
|
|
|
40910
41222
|
const [pinNodeData, { loading: pinning }] = usePinNodeDataMutation();
|
|
40911
41223
|
const [unpinNodeData, { loading: unpinning }] = useUnpinNodeDataMutation();
|
|
40912
41224
|
const togglePin = async () => {
|
|
40913
|
-
if (!workflowDbId || !ndv?.nodeId) return;
|
|
41225
|
+
if (!workflowDbId || !ndv?.nodeId || config2.readOnly) return;
|
|
40914
41226
|
try {
|
|
40915
41227
|
if (isPinned) {
|
|
40916
41228
|
await unpinNodeData({
|
|
@@ -41282,21 +41594,21 @@ function NodeDetailView() {
|
|
|
41282
41594
|
{
|
|
41283
41595
|
className: "min-h-0 flex-1 space-y-4 overflow-auto p-4",
|
|
41284
41596
|
"data-testid": "ndv-params",
|
|
41285
|
-
children: /* @__PURE__ */ jsx(
|
|
41597
|
+
children: /* @__PURE__ */ jsx(ReadOnlyFieldset, { className: "space-y-4", children: /* @__PURE__ */ jsx(
|
|
41286
41598
|
NodeParamsForm,
|
|
41287
41599
|
{
|
|
41288
41600
|
config: config2,
|
|
41289
41601
|
nodeType: node2?.type,
|
|
41290
41602
|
testIdPrefix: "ndv"
|
|
41291
41603
|
}
|
|
41292
|
-
)
|
|
41604
|
+
) })
|
|
41293
41605
|
}
|
|
41294
41606
|
) : /* @__PURE__ */ jsx(
|
|
41295
41607
|
"div",
|
|
41296
41608
|
{
|
|
41297
41609
|
className: "min-h-0 flex-1 overflow-auto p-4",
|
|
41298
41610
|
"data-testid": "ndv-settings",
|
|
41299
|
-
children: /* @__PURE__ */ jsx(NodeSettingsPanel, { config: config2 })
|
|
41611
|
+
children: /* @__PURE__ */ jsx(ReadOnlyFieldset, { children: /* @__PURE__ */ jsx(NodeSettingsPanel, { config: config2 }) })
|
|
41300
41612
|
}
|
|
41301
41613
|
)
|
|
41302
41614
|
]
|
|
@@ -41340,7 +41652,7 @@ function NodeDetailView() {
|
|
|
41340
41652
|
{
|
|
41341
41653
|
type: "button",
|
|
41342
41654
|
onClick: togglePin,
|
|
41343
|
-
disabled: pinning || unpinning,
|
|
41655
|
+
disabled: pinning || unpinning || config2.readOnly,
|
|
41344
41656
|
"data-testid": "ndv-pin-toggle",
|
|
41345
41657
|
title: tr(
|
|
41346
41658
|
isPinned ? "fluidgrids.builder.nodeDetailView.unpinHint" : "fluidgrids.builder.nodeDetailView.pinHint",
|
|
@@ -41983,14 +42295,14 @@ function QuickConfigPanelInner({
|
|
|
41983
42295
|
setShowMapper(true);
|
|
41984
42296
|
}
|
|
41985
42297
|
},
|
|
41986
|
-
children: /* @__PURE__ */ jsx(
|
|
42298
|
+
children: /* @__PURE__ */ jsx(ReadOnlyFieldset, { className: "space-y-4", children: /* @__PURE__ */ jsx(
|
|
41987
42299
|
NodeParamsForm,
|
|
41988
42300
|
{
|
|
41989
42301
|
config: config2,
|
|
41990
42302
|
nodeType: node2.type,
|
|
41991
42303
|
testIdPrefix: "qc"
|
|
41992
42304
|
}
|
|
41993
|
-
)
|
|
42305
|
+
) })
|
|
41994
42306
|
}
|
|
41995
42307
|
),
|
|
41996
42308
|
/* @__PURE__ */ jsx(
|
|
@@ -42115,10 +42427,11 @@ function useAutosave(readOnly) {
|
|
|
42115
42427
|
});
|
|
42116
42428
|
};
|
|
42117
42429
|
const autosave = createAutosaveRunner({
|
|
42118
|
-
mayStart: () => !status().autosavePaused && autosaveAllowedFor(useFlowStore.getState().workflow),
|
|
42430
|
+
mayStart: () => !status().autosavePaused && !editingLeaseLocked() && autosaveAllowedFor(useFlowStore.getState().workflow),
|
|
42119
42431
|
gate: () => {
|
|
42120
42432
|
const { workflow } = useFlowStore.getState();
|
|
42121
42433
|
if (status().autosavePaused || !status().dirty) return "skip";
|
|
42434
|
+
if (editingLeaseLocked()) return "skip";
|
|
42122
42435
|
if (!autosaveAllowedFor(workflow)) return "skip";
|
|
42123
42436
|
const complete = isFlowComplete(workflow.nodes, workflow.edges);
|
|
42124
42437
|
actions.setIncomplete(!complete);
|
|
@@ -42175,9 +42488,18 @@ function useAutosave(readOnly) {
|
|
|
42175
42488
|
}
|
|
42176
42489
|
}
|
|
42177
42490
|
);
|
|
42491
|
+
const unsubscribeLease = useEditLeaseStore.subscribe((state, previous) => {
|
|
42492
|
+
if (!isLocked(previous.phase) || isLocked(state.phase)) return;
|
|
42493
|
+
if (status().failure?.conflict?.reason === "EDIT_LEASE_HELD") {
|
|
42494
|
+
actions.clearFailure();
|
|
42495
|
+
actions.setAutosavePaused(false);
|
|
42496
|
+
}
|
|
42497
|
+
scheduleCheck();
|
|
42498
|
+
});
|
|
42178
42499
|
return () => {
|
|
42179
42500
|
unsubscribeFlow();
|
|
42180
42501
|
unsubscribeStatus();
|
|
42502
|
+
unsubscribeLease();
|
|
42181
42503
|
if (checkTimer) clearTimeout(checkTimer);
|
|
42182
42504
|
autosave.cancel();
|
|
42183
42505
|
saveDeparting(useFlowStore.getState());
|
|
@@ -42249,6 +42571,125 @@ function useLeaveGuards(readOnly) {
|
|
|
42249
42571
|
};
|
|
42250
42572
|
}, [readOnly]);
|
|
42251
42573
|
}
|
|
42574
|
+
function useActorName(actorId) {
|
|
42575
|
+
const config2 = getFluidGridsConfig();
|
|
42576
|
+
const actors = useMemo(
|
|
42577
|
+
() => actorId ? [{ actorId, actorType: "user" }] : [],
|
|
42578
|
+
[actorId]
|
|
42579
|
+
);
|
|
42580
|
+
const profiles = useActorProfiles(actors, {
|
|
42581
|
+
workspaceId: config2.workspaceId || void 0,
|
|
42582
|
+
orgId: config2.organizationId,
|
|
42583
|
+
authToken: config2.authToken
|
|
42584
|
+
});
|
|
42585
|
+
if (!actorId) return null;
|
|
42586
|
+
return profiles[actorId]?.displayName ?? buildActorFallback({ actorId, actorType: "user" }).displayName;
|
|
42587
|
+
}
|
|
42588
|
+
function SaveConflictDialog() {
|
|
42589
|
+
const tr = useTr();
|
|
42590
|
+
const open2 = useSaveStatusStore((s) => s.conflictOpen);
|
|
42591
|
+
const conflict = useSaveStatusStore((s) => s.failure?.conflict);
|
|
42592
|
+
const statusActions = useSaveStatusStore((s) => s.actions);
|
|
42593
|
+
const dbId = useFlowStore((s) => s.workflow.dbId);
|
|
42594
|
+
const { saveToBackend } = useSaveWorkflow();
|
|
42595
|
+
const name = useActorName(conflict?.updatedById);
|
|
42596
|
+
const [busy, setBusy] = useState(false);
|
|
42597
|
+
if (!conflict || conflict.reason !== "STALE_REVISION") return null;
|
|
42598
|
+
const someone = name ?? tr("fluidgrids.builder.saveConflict.someone", "Someone else");
|
|
42599
|
+
const stillDraft = conflict.currentStatus === "DRAFT";
|
|
42600
|
+
const canOverwrite = stillDraft && conflict.currentRevision !== null && !!dbId;
|
|
42601
|
+
const run = (action) => async () => {
|
|
42602
|
+
setBusy(true);
|
|
42603
|
+
try {
|
|
42604
|
+
await action();
|
|
42605
|
+
} finally {
|
|
42606
|
+
setBusy(false);
|
|
42607
|
+
}
|
|
42608
|
+
};
|
|
42609
|
+
const loadLatest = () => {
|
|
42610
|
+
const flow = useFlowStore.getState();
|
|
42611
|
+
statusActions.setBaseline({
|
|
42612
|
+
fingerprint: workflowFingerprint(flow.workflow),
|
|
42613
|
+
generation: flow.loadGeneration
|
|
42614
|
+
});
|
|
42615
|
+
statusActions.setConflictOpen(false);
|
|
42616
|
+
reloadLatestVersion();
|
|
42617
|
+
};
|
|
42618
|
+
const keepAsNewVersion = run(() => saveToBackend({ asNewVersion: true }));
|
|
42619
|
+
const overwrite = run(() => {
|
|
42620
|
+
if (dbId && conflict.currentRevision !== null) {
|
|
42621
|
+
rememberRevision(dbId, conflict.currentRevision);
|
|
42622
|
+
}
|
|
42623
|
+
return saveToBackend();
|
|
42624
|
+
});
|
|
42625
|
+
return /* @__PURE__ */ jsx(
|
|
42626
|
+
AlertDialog,
|
|
42627
|
+
{
|
|
42628
|
+
open: open2,
|
|
42629
|
+
onOpenChange: (next) => {
|
|
42630
|
+
if (!next && !busy) statusActions.setConflictOpen(false);
|
|
42631
|
+
},
|
|
42632
|
+
children: /* @__PURE__ */ jsxs(AlertDialogContent, { "data-testid": "fluidgrids-save-conflict-dialog", children: [
|
|
42633
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
42634
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: tr(
|
|
42635
|
+
"fluidgrids.builder.saveConflict.title",
|
|
42636
|
+
"This workflow changed after you opened it"
|
|
42637
|
+
) }),
|
|
42638
|
+
/* @__PURE__ */ jsx(AlertDialogDescription, { children: stillDraft ? tr(
|
|
42639
|
+
"fluidgrids.builder.saveConflict.changedDescription",
|
|
42640
|
+
"{{name}} saved changes to this version, so your save was stopped to keep them. Choose what to keep.",
|
|
42641
|
+
{ name: someone }
|
|
42642
|
+
) : tr(
|
|
42643
|
+
"fluidgrids.builder.saveConflict.publishedDescription",
|
|
42644
|
+
"This version is no longer a draft, so your changes were not saved into it. Keep them as a new version, or load the latest one."
|
|
42645
|
+
) })
|
|
42646
|
+
] }),
|
|
42647
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { className: "flex-wrap gap-2", children: [
|
|
42648
|
+
/* @__PURE__ */ jsx(AlertDialogCancel, { disabled: busy, children: tr("fluidgrids.builder.saveConflict.decideLater", "Decide later") }),
|
|
42649
|
+
/* @__PURE__ */ jsx(
|
|
42650
|
+
Button$2,
|
|
42651
|
+
{
|
|
42652
|
+
variant: "outline",
|
|
42653
|
+
disabled: busy,
|
|
42654
|
+
"data-testid": "fluidgrids-save-conflict-load-latest",
|
|
42655
|
+
onClick: loadLatest,
|
|
42656
|
+
children: tr(
|
|
42657
|
+
"fluidgrids.builder.saveConflict.loadLatest",
|
|
42658
|
+
"Discard mine and load latest"
|
|
42659
|
+
)
|
|
42660
|
+
}
|
|
42661
|
+
),
|
|
42662
|
+
canOverwrite ? /* @__PURE__ */ jsx(
|
|
42663
|
+
Button$2,
|
|
42664
|
+
{
|
|
42665
|
+
variant: "outline",
|
|
42666
|
+
disabled: busy,
|
|
42667
|
+
"data-testid": "fluidgrids-save-conflict-overwrite",
|
|
42668
|
+
onClick: () => void overwrite(),
|
|
42669
|
+
children: tr(
|
|
42670
|
+
"fluidgrids.builder.saveConflict.overwrite",
|
|
42671
|
+
"Overwrite their changes"
|
|
42672
|
+
)
|
|
42673
|
+
}
|
|
42674
|
+
) : null,
|
|
42675
|
+
/* @__PURE__ */ jsx(
|
|
42676
|
+
Button$2,
|
|
42677
|
+
{
|
|
42678
|
+
"data-agent": "confirm",
|
|
42679
|
+
disabled: busy,
|
|
42680
|
+
"data-testid": "fluidgrids-save-conflict-keep",
|
|
42681
|
+
onClick: () => void keepAsNewVersion(),
|
|
42682
|
+
children: tr(
|
|
42683
|
+
"fluidgrids.builder.saveConflict.keepAsNewVersion",
|
|
42684
|
+
"Keep mine as a new version"
|
|
42685
|
+
)
|
|
42686
|
+
}
|
|
42687
|
+
)
|
|
42688
|
+
] })
|
|
42689
|
+
] })
|
|
42690
|
+
}
|
|
42691
|
+
);
|
|
42692
|
+
}
|
|
42252
42693
|
function LeaveChangesDialog() {
|
|
42253
42694
|
const tr = useTr();
|
|
42254
42695
|
const navigate = useNavigate();
|
|
@@ -42339,14 +42780,18 @@ function SaveQuotaDialog() {
|
|
|
42339
42780
|
}
|
|
42340
42781
|
);
|
|
42341
42782
|
}
|
|
42342
|
-
function BuilderSaveController({
|
|
42783
|
+
function BuilderSaveController({
|
|
42784
|
+
readOnly,
|
|
42785
|
+
locked = false
|
|
42786
|
+
}) {
|
|
42343
42787
|
useAutosave(readOnly);
|
|
42344
|
-
useSaveShortcut(readOnly);
|
|
42788
|
+
useSaveShortcut(readOnly || locked);
|
|
42345
42789
|
useLeaveGuards(readOnly);
|
|
42346
42790
|
if (readOnly) return null;
|
|
42347
42791
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42348
42792
|
/* @__PURE__ */ jsx(LeaveChangesDialog, {}),
|
|
42349
|
-
/* @__PURE__ */ jsx(SaveQuotaDialog, {})
|
|
42793
|
+
/* @__PURE__ */ jsx(SaveQuotaDialog, {}),
|
|
42794
|
+
/* @__PURE__ */ jsx(SaveConflictDialog, {})
|
|
42350
42795
|
] });
|
|
42351
42796
|
}
|
|
42352
42797
|
|
|
@@ -42444,6 +42889,34 @@ function FailedStatus({ className, compact }) {
|
|
|
42444
42889
|
const tr = useTr();
|
|
42445
42890
|
const manualSave = useManualSave();
|
|
42446
42891
|
const message = useSaveStatusStore((s) => s.failure?.message);
|
|
42892
|
+
const staleConflict = useSaveStatusStore(
|
|
42893
|
+
(s) => s.failure?.conflict?.reason === "STALE_REVISION"
|
|
42894
|
+
);
|
|
42895
|
+
const setConflictOpen = useSaveStatusStore((s) => s.actions.setConflictOpen);
|
|
42896
|
+
if (staleConflict) {
|
|
42897
|
+
return /* @__PURE__ */ jsxs(
|
|
42898
|
+
StatusFrame,
|
|
42899
|
+
{
|
|
42900
|
+
state: "conflict",
|
|
42901
|
+
title: message,
|
|
42902
|
+
tone: "text-status-warning-text",
|
|
42903
|
+
className,
|
|
42904
|
+
children: [
|
|
42905
|
+
/* @__PURE__ */ jsx(Icon, { icon: "mynaui:git-branch", className: "size-3.5" }),
|
|
42906
|
+
/* @__PURE__ */ jsx(Label3, { compact, children: tr("fluidgrids.builder.saveStatus.conflict", "Changed elsewhere") }),
|
|
42907
|
+
/* @__PURE__ */ jsx(
|
|
42908
|
+
"button",
|
|
42909
|
+
{
|
|
42910
|
+
type: "button",
|
|
42911
|
+
onClick: () => setConflictOpen(true),
|
|
42912
|
+
className: "ml-1 rounded px-1 font-medium underline-offset-2 hover:underline",
|
|
42913
|
+
children: tr("fluidgrids.builder.saveStatus.resolve", "Resolve")
|
|
42914
|
+
}
|
|
42915
|
+
)
|
|
42916
|
+
]
|
|
42917
|
+
}
|
|
42918
|
+
);
|
|
42919
|
+
}
|
|
42447
42920
|
return /* @__PURE__ */ jsxs(
|
|
42448
42921
|
StatusFrame,
|
|
42449
42922
|
{
|
|
@@ -43055,15 +43528,24 @@ var ActivateWorkflowButton = ({
|
|
|
43055
43528
|
});
|
|
43056
43529
|
if (result) {
|
|
43057
43530
|
setWorkflow({ status: result.status });
|
|
43058
|
-
|
|
43059
|
-
|
|
43060
|
-
|
|
43061
|
-
|
|
43531
|
+
rememberOwnStatusChange(result.id, result.revision);
|
|
43532
|
+
if (result.status === "ACTIVE") {
|
|
43533
|
+
toast.success("Workflow activated", {
|
|
43534
|
+
description: `Version ${result.version} is now ACTIVE. Future saves will create a new draft version.`,
|
|
43535
|
+
dismissible: true
|
|
43536
|
+
});
|
|
43537
|
+
} else {
|
|
43538
|
+
toast.info("Activation is waiting for a replay check", {
|
|
43539
|
+
description: `Version ${result.version} activates once open auto-upgrade runs replay against it. See Versions.`,
|
|
43540
|
+
dismissible: true
|
|
43541
|
+
});
|
|
43542
|
+
}
|
|
43062
43543
|
}
|
|
43063
43544
|
} else {
|
|
43064
43545
|
const result = await deactivateWorkflow(dbId);
|
|
43065
43546
|
if (result) {
|
|
43066
43547
|
setWorkflow({ status: result.status });
|
|
43548
|
+
rememberOwnStatusChange(result.id, result.revision);
|
|
43067
43549
|
toast.success("Workflow deactivated", {
|
|
43068
43550
|
description: `Version ${result.version} is now a DRAFT. Saves will update in-place.`,
|
|
43069
43551
|
dismissible: true
|
|
@@ -43107,6 +43589,24 @@ var ActivateWorkflowButton = ({
|
|
|
43107
43589
|
);
|
|
43108
43590
|
};
|
|
43109
43591
|
|
|
43592
|
+
// src/builder/hooks/refresh-open-revision.ts
|
|
43593
|
+
async function refreshOpenRevision() {
|
|
43594
|
+
const dbId = useFlowStore.getState().workflow.dbId;
|
|
43595
|
+
if (!dbId) return;
|
|
43596
|
+
try {
|
|
43597
|
+
const { data } = await getFluidGridsClient().query(
|
|
43598
|
+
{
|
|
43599
|
+
query: WorkflowDefinitionDocument,
|
|
43600
|
+
variables: { id: dbId },
|
|
43601
|
+
fetchPolicy: "network-only"
|
|
43602
|
+
}
|
|
43603
|
+
);
|
|
43604
|
+
const stored = data?.workflowDefinition;
|
|
43605
|
+
rememberOwnStatusChange(stored?.id, stored?.revision);
|
|
43606
|
+
} catch {
|
|
43607
|
+
}
|
|
43608
|
+
}
|
|
43609
|
+
|
|
43110
43610
|
// src/utils/workflow-definition-diff.ts
|
|
43111
43611
|
function isRecord5(value) {
|
|
43112
43612
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -43254,6 +43754,520 @@ function CurrentVersionAiBadge({ iconOnly }) {
|
|
|
43254
43754
|
const facts = useCurrentVersionAuthoring();
|
|
43255
43755
|
return /* @__PURE__ */ jsx(AiAuthoredBadge, { facts, iconOnly });
|
|
43256
43756
|
}
|
|
43757
|
+
var DRAINAGE_VERSION_LIMIT = 10;
|
|
43758
|
+
async function fetchWorkflowVersioning(workflowKey) {
|
|
43759
|
+
const result = await getFluidGridsClient().query({
|
|
43760
|
+
query: WorkflowVersioningDocument,
|
|
43761
|
+
variables: { workflowKey },
|
|
43762
|
+
fetchPolicy: "network-only"
|
|
43763
|
+
});
|
|
43764
|
+
throwIfResultError(result);
|
|
43765
|
+
return {
|
|
43766
|
+
versions: result.data?.workflowVersions ?? [],
|
|
43767
|
+
rollouts: result.data?.workflowRollouts ?? []
|
|
43768
|
+
};
|
|
43769
|
+
}
|
|
43770
|
+
async function fetchVersionDrainage(workflowKey, version2) {
|
|
43771
|
+
const result = await getFluidGridsClient().query({
|
|
43772
|
+
query: WorkflowVersionDrainageDocument,
|
|
43773
|
+
variables: { workflowKey, version: version2 },
|
|
43774
|
+
fetchPolicy: "network-only"
|
|
43775
|
+
});
|
|
43776
|
+
throwIfResultError(result);
|
|
43777
|
+
return result.data?.workflowVersionDrainage ?? null;
|
|
43778
|
+
}
|
|
43779
|
+
async function saveWorkflowRollout(input2) {
|
|
43780
|
+
const result = await getFluidGridsClient().mutate({
|
|
43781
|
+
mutation: SetWorkflowRolloutDocument,
|
|
43782
|
+
variables: {
|
|
43783
|
+
workflowKey: input2.workflowKey,
|
|
43784
|
+
input: {
|
|
43785
|
+
fromVersion: input2.fromVersion ?? null,
|
|
43786
|
+
toVersion: input2.toVersion,
|
|
43787
|
+
percent: input2.percent,
|
|
43788
|
+
environment: "PROD" /* Prod */
|
|
43789
|
+
}
|
|
43790
|
+
}
|
|
43791
|
+
});
|
|
43792
|
+
throwIfResultError(result);
|
|
43793
|
+
const data = result.data?.setWorkflowRollout;
|
|
43794
|
+
if (!data) throw new Error("The rollout returned no result");
|
|
43795
|
+
return data;
|
|
43796
|
+
}
|
|
43797
|
+
async function removeWorkflowRollout(workflowKey) {
|
|
43798
|
+
const result = await getFluidGridsClient().mutate({
|
|
43799
|
+
mutation: DeleteWorkflowRolloutDocument,
|
|
43800
|
+
variables: { workflowKey, environment: "PROD" /* Prod */ }
|
|
43801
|
+
});
|
|
43802
|
+
throwIfResultError(result);
|
|
43803
|
+
return result.data?.deleteWorkflowRollout ?? false;
|
|
43804
|
+
}
|
|
43805
|
+
async function forceActivateVersion(id) {
|
|
43806
|
+
const result = await getFluidGridsClient().mutate({
|
|
43807
|
+
mutation: ActivateWorkflowVersionCheckedDocument,
|
|
43808
|
+
variables: { id, force: true },
|
|
43809
|
+
refetchQueries: ["WorkflowVersions", "WorkflowDefinitions"]
|
|
43810
|
+
});
|
|
43811
|
+
throwIfResultError(result);
|
|
43812
|
+
const data = result.data?.activateWorkflowDefinition;
|
|
43813
|
+
if (!data) throw new Error("Activation returned no result");
|
|
43814
|
+
return data;
|
|
43815
|
+
}
|
|
43816
|
+
function prodRollout(rollouts) {
|
|
43817
|
+
return rollouts.find(
|
|
43818
|
+
(rollout) => rollout.environment === "PROD" /* Prod */
|
|
43819
|
+
) ?? null;
|
|
43820
|
+
}
|
|
43821
|
+
function isDurableDefinition(definitionJson) {
|
|
43822
|
+
if (!isRecord6(definitionJson)) return false;
|
|
43823
|
+
const code = definitionJson.code;
|
|
43824
|
+
if (!isRecord6(code) || typeof code.buildId !== "string") return false;
|
|
43825
|
+
const workflows = isRecord6(code.exports) ? code.exports.workflows : null;
|
|
43826
|
+
return isRecord6(workflows) && Object.keys(workflows).length > 0;
|
|
43827
|
+
}
|
|
43828
|
+
function isRecord6(value) {
|
|
43829
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43830
|
+
}
|
|
43831
|
+
var EMPTY_STATE = {
|
|
43832
|
+
durable: false,
|
|
43833
|
+
byVersion: /* @__PURE__ */ new Map(),
|
|
43834
|
+
rollout: null,
|
|
43835
|
+
drainage: /* @__PURE__ */ new Map(),
|
|
43836
|
+
candidates: []
|
|
43837
|
+
};
|
|
43838
|
+
async function durableVersions(workflowKey, versions) {
|
|
43839
|
+
const flags = await Promise.all(
|
|
43840
|
+
versions.map(
|
|
43841
|
+
(version2) => loadDefinitionJson(workflowKey, version2).then(
|
|
43842
|
+
isDurableDefinition,
|
|
43843
|
+
() => false
|
|
43844
|
+
)
|
|
43845
|
+
)
|
|
43846
|
+
);
|
|
43847
|
+
return new Set(versions.filter((_, index) => flags[index]));
|
|
43848
|
+
}
|
|
43849
|
+
function useWorkflowVersioning(workflowKey, versions, enabled) {
|
|
43850
|
+
const [state, setState] = useState(EMPTY_STATE);
|
|
43851
|
+
const [error62, setError] = useState(null);
|
|
43852
|
+
const request = useRef(0);
|
|
43853
|
+
const reference = versions.find((entry) => entry.status === "ACTIVE") ?? versions[0];
|
|
43854
|
+
const newest = versions.slice(0, DRAINAGE_VERSION_LIMIT);
|
|
43855
|
+
const versionsKey = JSON.stringify({
|
|
43856
|
+
reference: reference ? { version: reference.version, status: reference.status ?? null } : null,
|
|
43857
|
+
newest: newest.map((entry) => [entry.version, entry.status ?? null])
|
|
43858
|
+
});
|
|
43859
|
+
const refetch = useCallback(async () => {
|
|
43860
|
+
if (!enabled || !workflowKey) return;
|
|
43861
|
+
const id = ++request.current;
|
|
43862
|
+
const parsed = JSON.parse(versionsKey);
|
|
43863
|
+
if (!parsed.reference) {
|
|
43864
|
+
setState(EMPTY_STATE);
|
|
43865
|
+
setError(null);
|
|
43866
|
+
return;
|
|
43867
|
+
}
|
|
43868
|
+
const active = parsed.reference.status === "ACTIVE" ? parsed.reference.version : null;
|
|
43869
|
+
const checked = [
|
|
43870
|
+
.../* @__PURE__ */ new Set([
|
|
43871
|
+
parsed.reference.version,
|
|
43872
|
+
...parsed.newest.map(([version2]) => version2)
|
|
43873
|
+
])
|
|
43874
|
+
];
|
|
43875
|
+
try {
|
|
43876
|
+
const durable = await durableVersions(workflowKey, checked);
|
|
43877
|
+
if (id !== request.current) return;
|
|
43878
|
+
if (!durable.has(parsed.reference.version)) {
|
|
43879
|
+
setState(EMPTY_STATE);
|
|
43880
|
+
setError(null);
|
|
43881
|
+
return;
|
|
43882
|
+
}
|
|
43883
|
+
const drainable = parsed.newest.map(([version2]) => version2).filter((version2) => durable.has(version2));
|
|
43884
|
+
const [versioning, drained] = await Promise.all([
|
|
43885
|
+
fetchWorkflowVersioning(workflowKey),
|
|
43886
|
+
Promise.all(
|
|
43887
|
+
drainable.map(
|
|
43888
|
+
(version2) => fetchVersionDrainage(workflowKey, version2).catch(() => null)
|
|
43889
|
+
)
|
|
43890
|
+
)
|
|
43891
|
+
]);
|
|
43892
|
+
if (id !== request.current) return;
|
|
43893
|
+
const drainage = /* @__PURE__ */ new Map();
|
|
43894
|
+
for (const entry of drained)
|
|
43895
|
+
if (entry) drainage.set(entry.version, entry);
|
|
43896
|
+
const checkedSet = new Set(checked);
|
|
43897
|
+
setState({
|
|
43898
|
+
durable: true,
|
|
43899
|
+
// A version known to be canvas gets no parity badges.
|
|
43900
|
+
byVersion: new Map(
|
|
43901
|
+
versioning.versions.filter(
|
|
43902
|
+
(entry) => !checkedSet.has(entry.version) || durable.has(entry.version)
|
|
43903
|
+
).map((entry) => [entry.version, entry])
|
|
43904
|
+
),
|
|
43905
|
+
rollout: prodRollout(versioning.rollouts),
|
|
43906
|
+
drainage,
|
|
43907
|
+
candidates: parsed.newest.filter(
|
|
43908
|
+
([version2, status]) => status === "DRAFT" && version2 !== active && durable.has(version2)
|
|
43909
|
+
).map(([version2]) => version2)
|
|
43910
|
+
});
|
|
43911
|
+
setError(null);
|
|
43912
|
+
} catch (err) {
|
|
43913
|
+
if (id !== request.current) return;
|
|
43914
|
+
setError(describeOperationError(err));
|
|
43915
|
+
}
|
|
43916
|
+
}, [enabled, workflowKey, versionsKey]);
|
|
43917
|
+
useEffect(() => {
|
|
43918
|
+
void refetch();
|
|
43919
|
+
}, [refetch]);
|
|
43920
|
+
return enabled ? { ...state, error: error62, refetch } : { ...EMPTY_STATE, error: null, refetch };
|
|
43921
|
+
}
|
|
43922
|
+
var CHECK_OPEN = /* @__PURE__ */ new Set([
|
|
43923
|
+
"PENDING" /* Pending */,
|
|
43924
|
+
"VERIFYING" /* Verifying */
|
|
43925
|
+
]);
|
|
43926
|
+
function visibleActivationCheck(versioning) {
|
|
43927
|
+
const check2 = versioning?.activationCheck;
|
|
43928
|
+
if (!check2) return null;
|
|
43929
|
+
if (CHECK_OPEN.has(check2.status) || check2.status === "REJECTED" /* Rejected */)
|
|
43930
|
+
return check2;
|
|
43931
|
+
return null;
|
|
43932
|
+
}
|
|
43933
|
+
function showDrainage(drainage, isActive) {
|
|
43934
|
+
if (!drainage || isActive) return false;
|
|
43935
|
+
return drainage.status === "DRAINING" /* Draining */ || drainage.rolloutTarget || drainage.lastRunStartedAt !== null;
|
|
43936
|
+
}
|
|
43937
|
+
function VersionParityBadges({
|
|
43938
|
+
versioning,
|
|
43939
|
+
drainage,
|
|
43940
|
+
isActive
|
|
43941
|
+
}) {
|
|
43942
|
+
const tr = useTr();
|
|
43943
|
+
const check2 = visibleActivationCheck(versioning);
|
|
43944
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
43945
|
+
versioning?.versioningBehavior === "AUTO_UPGRADE" /* AutoUpgrade */ && /* @__PURE__ */ jsx(
|
|
43946
|
+
Badge,
|
|
43947
|
+
{
|
|
43948
|
+
variant: "outline",
|
|
43949
|
+
className: "h-5 px-1.5 py-0 text-[10px]",
|
|
43950
|
+
"data-testid": "version-behavior-badge",
|
|
43951
|
+
children: tr("fluidgrids.builder.versionHistory.autoUpgrade", "Auto-upgrade")
|
|
43952
|
+
}
|
|
43953
|
+
),
|
|
43954
|
+
showDrainage(drainage, isActive) && /* @__PURE__ */ jsx(
|
|
43955
|
+
Badge,
|
|
43956
|
+
{
|
|
43957
|
+
variant: drainage.status === "DRAINING" /* Draining */ ? "secondary" : "outline",
|
|
43958
|
+
className: "h-5 px-1.5 py-0 text-[10px]",
|
|
43959
|
+
"data-testid": "version-drainage-badge",
|
|
43960
|
+
title: tr(
|
|
43961
|
+
"fluidgrids.builder.versionHistory.drainageTooltip",
|
|
43962
|
+
"Open durable-function runs this version's bundle serves"
|
|
43963
|
+
),
|
|
43964
|
+
children: drainage.status === "DRAINING" /* Draining */ ? tr(
|
|
43965
|
+
"fluidgrids.builder.versionHistory.draining",
|
|
43966
|
+
"Draining \xB7 {{count}} open",
|
|
43967
|
+
{ count: drainage.openRuns }
|
|
43968
|
+
) : drainage.status === "ACTIVE" /* Active */ ? tr("fluidgrids.builder.versionHistory.rolloutTarget", "Rollout") : tr("fluidgrids.builder.versionHistory.drained", "Drained")
|
|
43969
|
+
}
|
|
43970
|
+
),
|
|
43971
|
+
check2 && /* @__PURE__ */ jsx(
|
|
43972
|
+
Badge,
|
|
43973
|
+
{
|
|
43974
|
+
variant: check2.status === "REJECTED" /* Rejected */ ? "destructive" : "secondary",
|
|
43975
|
+
className: "h-5 px-1.5 py-0 text-[10px]",
|
|
43976
|
+
"data-testid": "version-activation-check",
|
|
43977
|
+
children: check2.status === "REJECTED" /* Rejected */ ? tr(
|
|
43978
|
+
"fluidgrids.builder.versionHistory.checkRejected",
|
|
43979
|
+
"Activation check failed"
|
|
43980
|
+
) : tr(
|
|
43981
|
+
"fluidgrids.builder.versionHistory.checkRunning",
|
|
43982
|
+
"Activation check running"
|
|
43983
|
+
)
|
|
43984
|
+
}
|
|
43985
|
+
)
|
|
43986
|
+
] });
|
|
43987
|
+
}
|
|
43988
|
+
function RolloutControl({
|
|
43989
|
+
workflowKey,
|
|
43990
|
+
activeVersion,
|
|
43991
|
+
candidates,
|
|
43992
|
+
rollout,
|
|
43993
|
+
canPublish,
|
|
43994
|
+
onChanged
|
|
43995
|
+
}) {
|
|
43996
|
+
const tr = useTr();
|
|
43997
|
+
const [toVersion, setToVersion] = useState(rollout?.toVersion ?? "");
|
|
43998
|
+
const [percent, setPercent] = useState(rollout?.percent ?? 0);
|
|
43999
|
+
const [saving, setSaving] = useState(false);
|
|
44000
|
+
const [confirmPromote, setConfirmPromote] = useState(false);
|
|
44001
|
+
useEffect(() => {
|
|
44002
|
+
setToVersion(rollout?.toVersion ?? "");
|
|
44003
|
+
setPercent(rollout?.percent ?? 0);
|
|
44004
|
+
}, [rollout?.toVersion, rollout?.percent]);
|
|
44005
|
+
if (!activeVersion || !rollout && candidates.length === 0) return null;
|
|
44006
|
+
const targets = rollout && !candidates.includes(rollout.toVersion) ? [rollout.toVersion, ...candidates] : [...candidates];
|
|
44007
|
+
const unchanged = !!rollout && rollout.toVersion === toVersion && rollout.percent === percent;
|
|
44008
|
+
const locked = !canPublish || saving;
|
|
44009
|
+
const check2 = rollout?.activationCheck;
|
|
44010
|
+
const save = async () => {
|
|
44011
|
+
setSaving(true);
|
|
44012
|
+
try {
|
|
44013
|
+
const saved = await saveWorkflowRollout({
|
|
44014
|
+
workflowKey,
|
|
44015
|
+
toVersion,
|
|
44016
|
+
percent
|
|
44017
|
+
});
|
|
44018
|
+
toast.success(
|
|
44019
|
+
saved.promoted ? tr(
|
|
44020
|
+
"fluidgrids.builder.versionHistory.rolloutPromoted",
|
|
44021
|
+
"Promotion started"
|
|
44022
|
+
) : tr(
|
|
44023
|
+
"fluidgrids.builder.versionHistory.rolloutSaved",
|
|
44024
|
+
"Rollout saved"
|
|
44025
|
+
)
|
|
44026
|
+
);
|
|
44027
|
+
onChanged();
|
|
44028
|
+
} catch (error62) {
|
|
44029
|
+
toast.error(
|
|
44030
|
+
tr(
|
|
44031
|
+
"fluidgrids.builder.versionHistory.rolloutError",
|
|
44032
|
+
"Could not save the rollout"
|
|
44033
|
+
),
|
|
44034
|
+
{ description: describeOperationError(error62) }
|
|
44035
|
+
);
|
|
44036
|
+
} finally {
|
|
44037
|
+
setSaving(false);
|
|
44038
|
+
setConfirmPromote(false);
|
|
44039
|
+
}
|
|
44040
|
+
};
|
|
44041
|
+
const remove = async () => {
|
|
44042
|
+
setSaving(true);
|
|
44043
|
+
try {
|
|
44044
|
+
await removeWorkflowRollout(workflowKey);
|
|
44045
|
+
toast.success(
|
|
44046
|
+
tr(
|
|
44047
|
+
"fluidgrids.builder.versionHistory.rolloutRemoved",
|
|
44048
|
+
"Rollout removed"
|
|
44049
|
+
)
|
|
44050
|
+
);
|
|
44051
|
+
onChanged();
|
|
44052
|
+
} catch (error62) {
|
|
44053
|
+
toast.error(
|
|
44054
|
+
tr(
|
|
44055
|
+
"fluidgrids.builder.versionHistory.rolloutError",
|
|
44056
|
+
"Could not save the rollout"
|
|
44057
|
+
),
|
|
44058
|
+
{ description: describeOperationError(error62) }
|
|
44059
|
+
);
|
|
44060
|
+
} finally {
|
|
44061
|
+
setSaving(false);
|
|
44062
|
+
}
|
|
44063
|
+
};
|
|
44064
|
+
return /* @__PURE__ */ jsxs(
|
|
44065
|
+
"section",
|
|
44066
|
+
{
|
|
44067
|
+
className: "mb-4 rounded-lg border border-border bg-card p-3",
|
|
44068
|
+
"aria-label": tr(
|
|
44069
|
+
"fluidgrids.builder.versionHistory.rolloutTitle",
|
|
44070
|
+
"Gradual rollout"
|
|
44071
|
+
),
|
|
44072
|
+
"data-testid": "version-rollout",
|
|
44073
|
+
children: [
|
|
44074
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2 text-sm font-semibold", children: [
|
|
44075
|
+
/* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-4" }),
|
|
44076
|
+
tr(
|
|
44077
|
+
"fluidgrids.builder.versionHistory.rolloutTitle",
|
|
44078
|
+
"Gradual rollout"
|
|
44079
|
+
)
|
|
44080
|
+
] }),
|
|
44081
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-muted-foreground", children: tr(
|
|
44082
|
+
"fluidgrids.builder.versionHistory.rolloutHint",
|
|
44083
|
+
"A share of new automatic starts runs another version instead of {{version}}.",
|
|
44084
|
+
{ version: activeVersion }
|
|
44085
|
+
) }),
|
|
44086
|
+
/* @__PURE__ */ jsxs(
|
|
44087
|
+
"select",
|
|
44088
|
+
{
|
|
44089
|
+
value: toVersion,
|
|
44090
|
+
onChange: (event) => setToVersion(event.target.value),
|
|
44091
|
+
disabled: locked,
|
|
44092
|
+
className: "mb-2 h-8 w-full rounded-md border border-border bg-background px-2 text-xs",
|
|
44093
|
+
"aria-label": tr(
|
|
44094
|
+
"fluidgrids.builder.versionHistory.rolloutTarget",
|
|
44095
|
+
"Rollout"
|
|
44096
|
+
),
|
|
44097
|
+
"data-testid": "version-rollout-target",
|
|
44098
|
+
children: [
|
|
44099
|
+
/* @__PURE__ */ jsx("option", { value: "", children: tr(
|
|
44100
|
+
"fluidgrids.builder.versionHistory.rolloutChoose",
|
|
44101
|
+
"Choose a version"
|
|
44102
|
+
) }),
|
|
44103
|
+
targets.map((version2) => /* @__PURE__ */ jsx("option", { value: version2, children: version2 }, version2))
|
|
44104
|
+
]
|
|
44105
|
+
}
|
|
44106
|
+
),
|
|
44107
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
44108
|
+
/* @__PURE__ */ jsx(
|
|
44109
|
+
"input",
|
|
44110
|
+
{
|
|
44111
|
+
type: "range",
|
|
44112
|
+
min: 0,
|
|
44113
|
+
max: 100,
|
|
44114
|
+
step: 1,
|
|
44115
|
+
value: percent,
|
|
44116
|
+
disabled: locked || !toVersion,
|
|
44117
|
+
onChange: (event) => setPercent(Number(event.target.value)),
|
|
44118
|
+
className: "min-w-0 flex-1 accent-primary",
|
|
44119
|
+
"aria-label": tr(
|
|
44120
|
+
"fluidgrids.builder.versionHistory.rolloutPercent",
|
|
44121
|
+
"Share of new starts"
|
|
44122
|
+
),
|
|
44123
|
+
"data-testid": "version-rollout-percent"
|
|
44124
|
+
}
|
|
44125
|
+
),
|
|
44126
|
+
/* @__PURE__ */ jsxs("span", { className: "w-10 text-right font-mono text-xs", children: [
|
|
44127
|
+
percent,
|
|
44128
|
+
"%"
|
|
44129
|
+
] })
|
|
44130
|
+
] }),
|
|
44131
|
+
rollout && /* @__PURE__ */ jsxs(
|
|
44132
|
+
"p",
|
|
44133
|
+
{
|
|
44134
|
+
className: "mt-1 text-[11px] text-muted-foreground",
|
|
44135
|
+
"data-testid": "version-rollout-verified",
|
|
44136
|
+
children: [
|
|
44137
|
+
tr(
|
|
44138
|
+
"fluidgrids.builder.versionHistory.rolloutVerified",
|
|
44139
|
+
"In-flight auto-upgrade runs follow {{verified}}% (replay-checked)",
|
|
44140
|
+
{ verified: rollout.verifiedPercent }
|
|
44141
|
+
),
|
|
44142
|
+
check2 && (check2.status === "PENDING" /* Pending */ || check2.status === "VERIFYING" /* Verifying */) ? ` \xB7 ${tr("fluidgrids.builder.versionHistory.checkRunning", "Activation check running")}` : ""
|
|
44143
|
+
]
|
|
44144
|
+
}
|
|
44145
|
+
),
|
|
44146
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-2", children: [
|
|
44147
|
+
/* @__PURE__ */ jsxs(
|
|
44148
|
+
Button$1,
|
|
44149
|
+
{
|
|
44150
|
+
"data-agent": "confirm",
|
|
44151
|
+
size: "sm",
|
|
44152
|
+
variant: "secondary",
|
|
44153
|
+
className: "flex-1",
|
|
44154
|
+
disabled: locked || !toVersion || unchanged,
|
|
44155
|
+
onClick: () => percent === 100 ? setConfirmPromote(true) : void save(),
|
|
44156
|
+
"data-testid": "version-rollout-save",
|
|
44157
|
+
children: [
|
|
44158
|
+
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-2 size-3.5 animate-spin" }),
|
|
44159
|
+
tr("fluidgrids.builder.versionHistory.rolloutSave", "Save rollout")
|
|
44160
|
+
]
|
|
44161
|
+
}
|
|
44162
|
+
),
|
|
44163
|
+
rollout && /* @__PURE__ */ jsx(
|
|
44164
|
+
Button$1,
|
|
44165
|
+
{
|
|
44166
|
+
"data-agent": "confirm",
|
|
44167
|
+
size: "sm",
|
|
44168
|
+
variant: "ghost",
|
|
44169
|
+
disabled: locked,
|
|
44170
|
+
onClick: () => void remove(),
|
|
44171
|
+
"aria-label": tr(
|
|
44172
|
+
"fluidgrids.builder.versionHistory.rolloutRemove",
|
|
44173
|
+
"Remove rollout"
|
|
44174
|
+
),
|
|
44175
|
+
"data-testid": "version-rollout-remove",
|
|
44176
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5" })
|
|
44177
|
+
}
|
|
44178
|
+
)
|
|
44179
|
+
] }),
|
|
44180
|
+
/* @__PURE__ */ jsx(AlertDialog, { open: confirmPromote, onOpenChange: setConfirmPromote, children: /* @__PURE__ */ jsxs(AlertDialogContent, { className: "z-[120]", children: [
|
|
44181
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
44182
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: tr(
|
|
44183
|
+
"fluidgrids.builder.versionHistory.promoteTitle",
|
|
44184
|
+
"Promote {{version}}?",
|
|
44185
|
+
{ version: toVersion }
|
|
44186
|
+
) }),
|
|
44187
|
+
/* @__PURE__ */ jsx(AlertDialogDescription, { children: tr(
|
|
44188
|
+
"fluidgrids.builder.versionHistory.promoteBody",
|
|
44189
|
+
"At 100% the version becomes the active one once open auto-upgrade runs replay against it, and the rollout is removed."
|
|
44190
|
+
) })
|
|
44191
|
+
] }),
|
|
44192
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
|
|
44193
|
+
/* @__PURE__ */ jsx(AlertDialogCancel, { disabled: saving, children: tr(
|
|
44194
|
+
"fluidgrids.builder.versionHistory.deleteDialogCancel",
|
|
44195
|
+
"Cancel"
|
|
44196
|
+
) }),
|
|
44197
|
+
/* @__PURE__ */ jsx(
|
|
44198
|
+
AlertDialogAction,
|
|
44199
|
+
{
|
|
44200
|
+
"data-agent": "confirm",
|
|
44201
|
+
disabled: saving,
|
|
44202
|
+
onClick: () => void save(),
|
|
44203
|
+
children: tr(
|
|
44204
|
+
"fluidgrids.builder.versionHistory.promoteConfirm",
|
|
44205
|
+
"Promote"
|
|
44206
|
+
)
|
|
44207
|
+
}
|
|
44208
|
+
)
|
|
44209
|
+
] })
|
|
44210
|
+
] }) })
|
|
44211
|
+
]
|
|
44212
|
+
}
|
|
44213
|
+
);
|
|
44214
|
+
}
|
|
44215
|
+
function ForceActivateDialog({
|
|
44216
|
+
version: version2,
|
|
44217
|
+
violations,
|
|
44218
|
+
busy,
|
|
44219
|
+
onConfirm,
|
|
44220
|
+
onCancel
|
|
44221
|
+
}) {
|
|
44222
|
+
const tr = useTr();
|
|
44223
|
+
return /* @__PURE__ */ jsx(
|
|
44224
|
+
AlertDialog,
|
|
44225
|
+
{
|
|
44226
|
+
open: version2 !== null,
|
|
44227
|
+
onOpenChange: (open2) => !open2 && onCancel(),
|
|
44228
|
+
children: /* @__PURE__ */ jsxs(
|
|
44229
|
+
AlertDialogContent,
|
|
44230
|
+
{
|
|
44231
|
+
className: "z-[120]",
|
|
44232
|
+
"data-testid": "force-activate-dialog",
|
|
44233
|
+
children: [
|
|
44234
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
44235
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: tr(
|
|
44236
|
+
"fluidgrids.builder.versionHistory.forceTitle",
|
|
44237
|
+
"Activate {{version}} anyway?",
|
|
44238
|
+
{ version: version2 ?? "" }
|
|
44239
|
+
) }),
|
|
44240
|
+
/* @__PURE__ */ jsx(AlertDialogDescription, { children: tr(
|
|
44241
|
+
"fluidgrids.builder.versionHistory.forceBody",
|
|
44242
|
+
"{{count}} open auto-upgrade runs did not replay against this version. They keep failing their workflow task until a fix ships. The activation is audited.",
|
|
44243
|
+
{ count: violations }
|
|
44244
|
+
) })
|
|
44245
|
+
] }),
|
|
44246
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
|
|
44247
|
+
/* @__PURE__ */ jsx(AlertDialogCancel, { disabled: busy, children: tr(
|
|
44248
|
+
"fluidgrids.builder.versionHistory.deleteDialogCancel",
|
|
44249
|
+
"Cancel"
|
|
44250
|
+
) }),
|
|
44251
|
+
/* @__PURE__ */ jsx(
|
|
44252
|
+
AlertDialogAction,
|
|
44253
|
+
{
|
|
44254
|
+
"data-agent": "confirm",
|
|
44255
|
+
disabled: busy,
|
|
44256
|
+
className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
44257
|
+
onClick: onConfirm,
|
|
44258
|
+
children: tr(
|
|
44259
|
+
"fluidgrids.builder.versionHistory.forceConfirm",
|
|
44260
|
+
"Activate anyway"
|
|
44261
|
+
)
|
|
44262
|
+
}
|
|
44263
|
+
)
|
|
44264
|
+
] })
|
|
44265
|
+
]
|
|
44266
|
+
}
|
|
44267
|
+
)
|
|
44268
|
+
}
|
|
44269
|
+
);
|
|
44270
|
+
}
|
|
43257
44271
|
function relativeTime(dateStr) {
|
|
43258
44272
|
if (!dateStr) return "";
|
|
43259
44273
|
const then = new Date(dateStr).getTime();
|
|
@@ -43365,6 +44379,18 @@ function VersionHistoryPanel({
|
|
|
43365
44379
|
const [compareLoading, setCompareLoading] = useState(false);
|
|
43366
44380
|
const [busy, setBusy] = useState(null);
|
|
43367
44381
|
const [deleteTarget, setDeleteTarget] = useState(null);
|
|
44382
|
+
const parityEnabled = useDurableParityEnabled();
|
|
44383
|
+
const { allowed: canPublish } = useFluidGridsPermission(
|
|
44384
|
+
FLUIDGRIDS_PERMISSIONS.WORKFLOW_PUBLISH
|
|
44385
|
+
);
|
|
44386
|
+
const versioning = useWorkflowVersioning(
|
|
44387
|
+
workflowKey,
|
|
44388
|
+
versions,
|
|
44389
|
+
parityEnabled
|
|
44390
|
+
);
|
|
44391
|
+
const refetchVersioning = versioning.refetch;
|
|
44392
|
+
const [forceTarget, setForceTarget] = useState(null);
|
|
44393
|
+
const activeVersion = versions.find((entry) => entry.status === "ACTIVE")?.version ?? null;
|
|
43368
44394
|
useEffect(() => {
|
|
43369
44395
|
if (versions.length < 2) {
|
|
43370
44396
|
setCompareFrom("");
|
|
@@ -43470,6 +44496,23 @@ function VersionHistoryPanel({
|
|
|
43470
44496
|
try {
|
|
43471
44497
|
const result = await activateWorkflow(id);
|
|
43472
44498
|
if (!result) throw new Error("Activation returned no result");
|
|
44499
|
+
if (result.status !== "ACTIVE") {
|
|
44500
|
+
toast.info(
|
|
44501
|
+
tr(
|
|
44502
|
+
"fluidgrids.builder.versionHistory.activationHeld",
|
|
44503
|
+
"Activation is waiting for a replay check"
|
|
44504
|
+
),
|
|
44505
|
+
{
|
|
44506
|
+
description: tr(
|
|
44507
|
+
"fluidgrids.builder.versionHistory.activationHeldDescription",
|
|
44508
|
+
"Open auto-upgrade runs replay against this version first."
|
|
44509
|
+
),
|
|
44510
|
+
dismissible: true
|
|
44511
|
+
}
|
|
44512
|
+
);
|
|
44513
|
+
await Promise.all([refetch(), refetchVersioning()]);
|
|
44514
|
+
return;
|
|
44515
|
+
}
|
|
43473
44516
|
toast.success(`Version ${version2} is now ACTIVE`, {
|
|
43474
44517
|
description: tr(
|
|
43475
44518
|
"fluidgrids.builder.versionHistory.activateSuccessDescription",
|
|
@@ -43479,10 +44522,12 @@ function VersionHistoryPanel({
|
|
|
43479
44522
|
});
|
|
43480
44523
|
if (version2 === currentVersion) {
|
|
43481
44524
|
setWorkflow({ status: "ACTIVE" });
|
|
44525
|
+
rememberOwnStatusChange(result.id, result.revision);
|
|
43482
44526
|
} else {
|
|
43483
44527
|
const refreshed = await refetch();
|
|
43484
44528
|
const current = refreshed.find((v) => v.version === currentVersion);
|
|
43485
44529
|
if (current?.status) setWorkflow({ status: current.status });
|
|
44530
|
+
rememberOwnStatusChange(current?.id, current?.revision);
|
|
43486
44531
|
}
|
|
43487
44532
|
await refetch();
|
|
43488
44533
|
} catch (error62) {
|
|
@@ -43502,6 +44547,39 @@ function VersionHistoryPanel({
|
|
|
43502
44547
|
setBusy(null);
|
|
43503
44548
|
}
|
|
43504
44549
|
};
|
|
44550
|
+
const handleForceActivate = async () => {
|
|
44551
|
+
if (!forceTarget) return;
|
|
44552
|
+
const { id, version: version2 } = forceTarget;
|
|
44553
|
+
setBusy(`activate:${version2}`);
|
|
44554
|
+
try {
|
|
44555
|
+
const result = await forceActivateVersion(id);
|
|
44556
|
+
toast.success(`Version ${version2} is now ${result.status}`, {
|
|
44557
|
+
dismissible: true
|
|
44558
|
+
});
|
|
44559
|
+
if (version2 === currentVersion) setWorkflow({ status: result.status });
|
|
44560
|
+
await Promise.all([
|
|
44561
|
+
refetch(),
|
|
44562
|
+
refetchVersioning(),
|
|
44563
|
+
refreshOpenRevision()
|
|
44564
|
+
]);
|
|
44565
|
+
} catch (error62) {
|
|
44566
|
+
toast.error(
|
|
44567
|
+
tr(
|
|
44568
|
+
"fluidgrids.builder.versionHistory.activateErrorTitle",
|
|
44569
|
+
"Failed to activate version"
|
|
44570
|
+
),
|
|
44571
|
+
{
|
|
44572
|
+
description: error62 instanceof Error ? error62.message : tr(
|
|
44573
|
+
"fluidgrids.builder.versionHistory.activateUnknownError",
|
|
44574
|
+
"Unknown error"
|
|
44575
|
+
)
|
|
44576
|
+
}
|
|
44577
|
+
);
|
|
44578
|
+
} finally {
|
|
44579
|
+
setBusy(null);
|
|
44580
|
+
setForceTarget(null);
|
|
44581
|
+
}
|
|
44582
|
+
};
|
|
43505
44583
|
const handleDelete = async (version2) => {
|
|
43506
44584
|
setBusy(`delete:${version2}`);
|
|
43507
44585
|
try {
|
|
@@ -43546,7 +44624,10 @@ function VersionHistoryPanel({
|
|
|
43546
44624
|
"fluidgrids.builder.versionHistory.triggerButton",
|
|
43547
44625
|
"Versions"
|
|
43548
44626
|
) : void 0,
|
|
43549
|
-
onClick: () =>
|
|
44627
|
+
onClick: () => {
|
|
44628
|
+
void refetch();
|
|
44629
|
+
void refetchVersioning();
|
|
44630
|
+
},
|
|
43550
44631
|
children: [
|
|
43551
44632
|
/* @__PURE__ */ jsx(History, { className: "size-4" }),
|
|
43552
44633
|
!compact && tr("fluidgrids.builder.versionHistory.triggerButton", "Versions")
|
|
@@ -43574,6 +44655,20 @@ function VersionHistoryPanel({
|
|
|
43574
44655
|
] })
|
|
43575
44656
|
] }),
|
|
43576
44657
|
/* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs("div", { className: "mt-4 overflow-y-auto max-h-[calc(100vh-140px)] pr-1", children: [
|
|
44658
|
+
parityEnabled && versioning.durable && !loading && /* @__PURE__ */ jsx(
|
|
44659
|
+
RolloutControl,
|
|
44660
|
+
{
|
|
44661
|
+
workflowKey,
|
|
44662
|
+
activeVersion,
|
|
44663
|
+
candidates: versioning.candidates,
|
|
44664
|
+
rollout: versioning.rollout,
|
|
44665
|
+
canPublish,
|
|
44666
|
+
onChanged: () => {
|
|
44667
|
+
void refetch();
|
|
44668
|
+
void refetchVersioning();
|
|
44669
|
+
}
|
|
44670
|
+
}
|
|
44671
|
+
),
|
|
43577
44672
|
!loading && versions.length > 1 && /* @__PURE__ */ jsxs(
|
|
43578
44673
|
"section",
|
|
43579
44674
|
{
|
|
@@ -43786,7 +44881,15 @@ function VersionHistoryPanel({
|
|
|
43786
44881
|
]
|
|
43787
44882
|
}
|
|
43788
44883
|
),
|
|
43789
|
-
/* @__PURE__ */ jsx(AiAuthoredBadge, { facts: v })
|
|
44884
|
+
/* @__PURE__ */ jsx(AiAuthoredBadge, { facts: v }),
|
|
44885
|
+
parityEnabled && versioning.durable && /* @__PURE__ */ jsx(
|
|
44886
|
+
VersionParityBadges,
|
|
44887
|
+
{
|
|
44888
|
+
versioning: versioning.byVersion.get(v.version),
|
|
44889
|
+
drainage: versioning.drainage.get(v.version),
|
|
44890
|
+
isActive
|
|
44891
|
+
}
|
|
44892
|
+
)
|
|
43790
44893
|
] }),
|
|
43791
44894
|
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center", children: [
|
|
43792
44895
|
!isCurrent && /* @__PURE__ */ jsx(
|
|
@@ -43815,6 +44918,26 @@ function VersionHistoryPanel({
|
|
|
43815
44918
|
onClick: () => handleActivate(v.id, v.version)
|
|
43816
44919
|
}
|
|
43817
44920
|
),
|
|
44921
|
+
parityEnabled && versioning.durable && canPublish && !isActive && visibleActivationCheck(
|
|
44922
|
+
versioning.byVersion.get(v.version)
|
|
44923
|
+
)?.status === "REJECTED" /* Rejected */ && /* @__PURE__ */ jsx(
|
|
44924
|
+
ActionButton,
|
|
44925
|
+
{
|
|
44926
|
+
confirm: true,
|
|
44927
|
+
destructive: true,
|
|
44928
|
+
label: tr(
|
|
44929
|
+
"fluidgrids.builder.versionHistory.actionForce",
|
|
44930
|
+
"Activate anyway"
|
|
44931
|
+
),
|
|
44932
|
+
icon: /* @__PURE__ */ jsx(Play, { className: "size-3.5" }),
|
|
44933
|
+
disabled: busy !== null,
|
|
44934
|
+
onClick: () => setForceTarget({
|
|
44935
|
+
id: v.id,
|
|
44936
|
+
version: v.version,
|
|
44937
|
+
violations: versioning.byVersion.get(v.version)?.activationCheck?.violations.length ?? 0
|
|
44938
|
+
})
|
|
44939
|
+
}
|
|
44940
|
+
),
|
|
43818
44941
|
!isCurrent && /* @__PURE__ */ jsx(
|
|
43819
44942
|
ActionButton,
|
|
43820
44943
|
{
|
|
@@ -43863,6 +44986,16 @@ function VersionHistoryPanel({
|
|
|
43863
44986
|
}) })
|
|
43864
44987
|
] }) })
|
|
43865
44988
|
] }),
|
|
44989
|
+
parityEnabled && /* @__PURE__ */ jsx(
|
|
44990
|
+
ForceActivateDialog,
|
|
44991
|
+
{
|
|
44992
|
+
version: forceTarget?.version ?? null,
|
|
44993
|
+
violations: forceTarget?.violations ?? 0,
|
|
44994
|
+
busy: busy !== null,
|
|
44995
|
+
onConfirm: () => void handleForceActivate(),
|
|
44996
|
+
onCancel: () => setForceTarget(null)
|
|
44997
|
+
}
|
|
44998
|
+
),
|
|
43866
44999
|
/* @__PURE__ */ jsx(
|
|
43867
45000
|
AlertDialog,
|
|
43868
45001
|
{
|
|
@@ -44169,12 +45302,15 @@ function EnvironmentsPanel({
|
|
|
44169
45302
|
const pending = view?.pendingPromotions ?? [];
|
|
44170
45303
|
const policy = view?.policy;
|
|
44171
45304
|
const dev = environments.find((state) => state.environment === "DEV");
|
|
44172
|
-
const afterProdChange = (promotedVersion) => {
|
|
45305
|
+
const afterProdChange = async (promotedVersion) => {
|
|
44173
45306
|
if (promotedVersion === currentVersion) {
|
|
44174
45307
|
setWorkflow({ status: "ACTIVE" });
|
|
44175
45308
|
} else if (openStatus === "ACTIVE") {
|
|
44176
45309
|
setWorkflow({ status: "ARCHIVED" });
|
|
45310
|
+
} else {
|
|
45311
|
+
return;
|
|
44177
45312
|
}
|
|
45313
|
+
await refreshOpenRevision();
|
|
44178
45314
|
};
|
|
44179
45315
|
const run = async (key, action, errorTitle) => {
|
|
44180
45316
|
setBusy(key);
|
|
@@ -44229,7 +45365,8 @@ function EnvironmentsPanel({
|
|
|
44229
45365
|
`${request.version} ${tr("fluidgrids.builder.environments.promotedTo", "promoted to")} ${envLabel(current.target)}`,
|
|
44230
45366
|
{ dismissible: true }
|
|
44231
45367
|
);
|
|
44232
|
-
if (current.target === "PROD")
|
|
45368
|
+
if (current.target === "PROD")
|
|
45369
|
+
await afterProdChange(request.version);
|
|
44233
45370
|
}
|
|
44234
45371
|
},
|
|
44235
45372
|
tr("fluidgrids.builder.environments.promoteError", "Promotion failed")
|
|
@@ -44245,7 +45382,7 @@ function EnvironmentsPanel({
|
|
|
44245
45382
|
`${current.label} ${tr("fluidgrids.builder.environments.approved", "approved and deployed")}`,
|
|
44246
45383
|
{ dismissible: true }
|
|
44247
45384
|
);
|
|
44248
|
-
if (current.target === "PROD") afterProdChange(current.version);
|
|
45385
|
+
if (current.target === "PROD") await afterProdChange(current.version);
|
|
44249
45386
|
},
|
|
44250
45387
|
tr("fluidgrids.builder.environments.approveError", "Approval failed")
|
|
44251
45388
|
);
|
|
@@ -45949,23 +47086,23 @@ function useAiWorkflowTemplates(enabled) {
|
|
|
45949
47086
|
|
|
45950
47087
|
// src/builder/lib/ai-draft.ts
|
|
45951
47088
|
var AI_DRAFT_MAX_PROMPT_LENGTH = 4e3;
|
|
45952
|
-
function
|
|
47089
|
+
function isRecord7(value) {
|
|
45953
47090
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45954
47091
|
}
|
|
45955
47092
|
function stringOr(value, fallback) {
|
|
45956
47093
|
return typeof value === "string" && value.trim() !== "" ? value : fallback;
|
|
45957
47094
|
}
|
|
45958
47095
|
function draftToCanvas(definitionJson) {
|
|
45959
|
-
const data =
|
|
47096
|
+
const data = isRecord7(definitionJson) && isRecord7(definitionJson.data) ? definitionJson.data : {};
|
|
45960
47097
|
const rawNodes = Array.isArray(data.nodes) ? data.nodes : [];
|
|
45961
47098
|
const rawEdges = Array.isArray(data.edges) ? data.edges : [];
|
|
45962
|
-
const nodes = rawNodes.filter(
|
|
47099
|
+
const nodes = rawNodes.filter(isRecord7).flatMap((raw) => {
|
|
45963
47100
|
if (typeof raw.id !== "string" || typeof raw.type !== "string") return [];
|
|
45964
|
-
const position =
|
|
47101
|
+
const position = isRecord7(raw.position) ? {
|
|
45965
47102
|
x: typeof raw.position.x === "number" ? raw.position.x : 0,
|
|
45966
47103
|
y: typeof raw.position.y === "number" ? raw.position.y : 0
|
|
45967
47104
|
} : { x: 0, y: 0 };
|
|
45968
|
-
const nodeData =
|
|
47105
|
+
const nodeData = isRecord7(raw.data) ? raw.data : {};
|
|
45969
47106
|
const node2 = {
|
|
45970
47107
|
...raw,
|
|
45971
47108
|
id: raw.id,
|
|
@@ -45977,7 +47114,7 @@ function draftToCanvas(definitionJson) {
|
|
|
45977
47114
|
return [node2];
|
|
45978
47115
|
});
|
|
45979
47116
|
const ids = new Set(nodes.map((node2) => node2.id));
|
|
45980
|
-
const edges = rawEdges.filter(
|
|
47117
|
+
const edges = rawEdges.filter(isRecord7).flatMap((raw) => {
|
|
45981
47118
|
if (typeof raw.source !== "string" || typeof raw.target !== "string") {
|
|
45982
47119
|
return [];
|
|
45983
47120
|
}
|
|
@@ -45996,7 +47133,7 @@ function draftToCanvas(definitionJson) {
|
|
|
45996
47133
|
}
|
|
45997
47134
|
function enrichDraftNodes(nodes, seed) {
|
|
45998
47135
|
return nodes.map((node2) => {
|
|
45999
|
-
const data =
|
|
47136
|
+
const data = isRecord7(node2.data) ? node2.data : {};
|
|
46000
47137
|
const rootOperation = node2.operation_name;
|
|
46001
47138
|
let operationName;
|
|
46002
47139
|
if (typeof data.operation_name === "string") {
|
|
@@ -46007,10 +47144,10 @@ function enrichDraftNodes(nodes, seed) {
|
|
|
46007
47144
|
if (!node2.type || !operationName) return node2;
|
|
46008
47145
|
const seeded = seed(node2.type, operationName, data);
|
|
46009
47146
|
if (!seeded) return node2;
|
|
46010
|
-
const seededArgs =
|
|
46011
|
-
const defaults =
|
|
46012
|
-
const draftArgs =
|
|
46013
|
-
const draftState =
|
|
47147
|
+
const seededArgs = isRecord7(seeded.args) ? seeded.args : {};
|
|
47148
|
+
const defaults = isRecord7(seededArgs.state) ? seededArgs.state : {};
|
|
47149
|
+
const draftArgs = isRecord7(data.args) ? data.args : {};
|
|
47150
|
+
const draftState = isRecord7(draftArgs.state) ? draftArgs.state : {};
|
|
46014
47151
|
return {
|
|
46015
47152
|
...node2,
|
|
46016
47153
|
data: {
|
|
@@ -46063,7 +47200,7 @@ function AiDraftPanel({
|
|
|
46063
47200
|
...template !== NO_TEMPLATE ? { template } : {}
|
|
46064
47201
|
});
|
|
46065
47202
|
}, [openVersion, proposal, template, trimmed, workflowKey]);
|
|
46066
|
-
const
|
|
47203
|
+
const openWorkflow2 = useCallback(
|
|
46067
47204
|
(key, version2) => {
|
|
46068
47205
|
setOpen(false);
|
|
46069
47206
|
proposal.reset();
|
|
@@ -46115,7 +47252,7 @@ function AiDraftPanel({
|
|
|
46115
47252
|
{ version: version2, newVersion: result.workflow.version }
|
|
46116
47253
|
)
|
|
46117
47254
|
);
|
|
46118
|
-
|
|
47255
|
+
openWorkflow2(result.workflow.workflowKey, result.workflow.version);
|
|
46119
47256
|
} catch (error62) {
|
|
46120
47257
|
toast.error(
|
|
46121
47258
|
tr(
|
|
@@ -46130,7 +47267,7 @@ function AiDraftPanel({
|
|
|
46130
47267
|
setReverting(false);
|
|
46131
47268
|
}
|
|
46132
47269
|
},
|
|
46133
|
-
[
|
|
47270
|
+
[openWorkflow2, restoreVersion, tr]
|
|
46134
47271
|
);
|
|
46135
47272
|
const putOnCanvas = useCallback(() => {
|
|
46136
47273
|
if (!current?.definitionJson) return;
|
|
@@ -46319,7 +47456,7 @@ function AiDraftPanel({
|
|
|
46319
47456
|
onApply: () => void handleApply(),
|
|
46320
47457
|
onReject: () => void handleReject(),
|
|
46321
47458
|
onCancel: () => void proposal.cancel(),
|
|
46322
|
-
onOpenWorkflow:
|
|
47459
|
+
onOpenWorkflow: openWorkflow2,
|
|
46323
47460
|
onRevert: (key, version2) => void handleRevert(key, version2)
|
|
46324
47461
|
}
|
|
46325
47462
|
),
|
|
@@ -47245,6 +48382,236 @@ function CodeVersionNotice() {
|
|
|
47245
48382
|
}
|
|
47246
48383
|
);
|
|
47247
48384
|
}
|
|
48385
|
+
function actorOf(banner) {
|
|
48386
|
+
return banner.kind === "editing" || banner.kind === "taken" ? banner.actorId : null;
|
|
48387
|
+
}
|
|
48388
|
+
function unsavedWorkActions(tr, commands) {
|
|
48389
|
+
return [
|
|
48390
|
+
{
|
|
48391
|
+
key: "keep",
|
|
48392
|
+
label: tr(
|
|
48393
|
+
"fluidgrids.builder.editLease.keepAsNewVersion",
|
|
48394
|
+
"Keep my changes as a new version"
|
|
48395
|
+
),
|
|
48396
|
+
onClick: commands.keepMine,
|
|
48397
|
+
primary: true
|
|
48398
|
+
},
|
|
48399
|
+
{
|
|
48400
|
+
key: "take-over",
|
|
48401
|
+
label: tr(
|
|
48402
|
+
"fluidgrids.builder.editLease.discardAndTakeOver",
|
|
48403
|
+
"Discard my changes and take over"
|
|
48404
|
+
),
|
|
48405
|
+
onClick: commands.takeOver
|
|
48406
|
+
},
|
|
48407
|
+
{
|
|
48408
|
+
key: "latest",
|
|
48409
|
+
label: tr(
|
|
48410
|
+
"fluidgrids.builder.editLease.discardAndViewLatest",
|
|
48411
|
+
"Discard my changes and view latest"
|
|
48412
|
+
),
|
|
48413
|
+
onClick: commands.refresh
|
|
48414
|
+
}
|
|
48415
|
+
];
|
|
48416
|
+
}
|
|
48417
|
+
function unsavedHere(tr) {
|
|
48418
|
+
return tr(
|
|
48419
|
+
"fluidgrids.builder.editLease.unsavedHere",
|
|
48420
|
+
"Your latest changes are only on this screen."
|
|
48421
|
+
);
|
|
48422
|
+
}
|
|
48423
|
+
function editingView(self, someone, dirty, tr, commands) {
|
|
48424
|
+
const editing = self ? tr(
|
|
48425
|
+
"fluidgrids.builder.editLease.editingElsewhereSelf",
|
|
48426
|
+
"You are editing this workflow in another tab or window, so it is read-only here."
|
|
48427
|
+
) : tr(
|
|
48428
|
+
"fluidgrids.builder.editLease.editingElsewhere",
|
|
48429
|
+
"{{name}} is editing this workflow, so it is read-only for you.",
|
|
48430
|
+
{ name: someone }
|
|
48431
|
+
);
|
|
48432
|
+
if (dirty) {
|
|
48433
|
+
return {
|
|
48434
|
+
icon: "mynaui:lock",
|
|
48435
|
+
message: `${editing} ${unsavedHere(tr)}`,
|
|
48436
|
+
actions: unsavedWorkActions(tr, commands)
|
|
48437
|
+
};
|
|
48438
|
+
}
|
|
48439
|
+
return {
|
|
48440
|
+
icon: "mynaui:lock",
|
|
48441
|
+
message: editing,
|
|
48442
|
+
actions: [
|
|
48443
|
+
{
|
|
48444
|
+
key: "take-over",
|
|
48445
|
+
label: self ? tr("fluidgrids.builder.editLease.editHere", "Edit here") : tr("fluidgrids.builder.editLease.takeOver", "Take over"),
|
|
48446
|
+
onClick: commands.takeOver,
|
|
48447
|
+
primary: true
|
|
48448
|
+
},
|
|
48449
|
+
{
|
|
48450
|
+
key: "refresh",
|
|
48451
|
+
label: tr("fluidgrids.builder.editLease.refresh", "Refresh"),
|
|
48452
|
+
onClick: commands.refresh
|
|
48453
|
+
}
|
|
48454
|
+
]
|
|
48455
|
+
};
|
|
48456
|
+
}
|
|
48457
|
+
function takenView(self, someone, dirty, tr, commands) {
|
|
48458
|
+
const taken = self ? tr(
|
|
48459
|
+
"fluidgrids.builder.editLease.takenSelf",
|
|
48460
|
+
"You started editing this workflow in another tab or window."
|
|
48461
|
+
) : tr(
|
|
48462
|
+
"fluidgrids.builder.editLease.taken",
|
|
48463
|
+
"{{name}} took over editing this workflow.",
|
|
48464
|
+
{ name: someone }
|
|
48465
|
+
);
|
|
48466
|
+
if (dirty) {
|
|
48467
|
+
return {
|
|
48468
|
+
icon: "mynaui:lock",
|
|
48469
|
+
message: `${taken} ${unsavedHere(tr)}`,
|
|
48470
|
+
actions: unsavedWorkActions(tr, commands)
|
|
48471
|
+
};
|
|
48472
|
+
}
|
|
48473
|
+
return {
|
|
48474
|
+
icon: "mynaui:lock",
|
|
48475
|
+
message: taken,
|
|
48476
|
+
actions: [
|
|
48477
|
+
{
|
|
48478
|
+
key: "take-over",
|
|
48479
|
+
label: tr("fluidgrids.builder.editLease.takeOver", "Take over"),
|
|
48480
|
+
onClick: commands.takeOver,
|
|
48481
|
+
primary: true
|
|
48482
|
+
},
|
|
48483
|
+
{
|
|
48484
|
+
key: "latest",
|
|
48485
|
+
label: tr("fluidgrids.builder.editLease.viewLatest", "View latest"),
|
|
48486
|
+
onClick: commands.refresh
|
|
48487
|
+
}
|
|
48488
|
+
]
|
|
48489
|
+
};
|
|
48490
|
+
}
|
|
48491
|
+
function bannerView(banner, context, commands) {
|
|
48492
|
+
const { someone, dirty, tr } = context;
|
|
48493
|
+
switch (banner.kind) {
|
|
48494
|
+
case "editing":
|
|
48495
|
+
return editingView(banner.self, someone, dirty, tr, commands);
|
|
48496
|
+
case "taken":
|
|
48497
|
+
return takenView(banner.self, someone, dirty, tr, commands);
|
|
48498
|
+
case "free":
|
|
48499
|
+
return {
|
|
48500
|
+
icon: "mynaui:lock-open",
|
|
48501
|
+
message: tr(
|
|
48502
|
+
"fluidgrids.builder.editLease.free",
|
|
48503
|
+
"Nobody is editing this workflow now."
|
|
48504
|
+
),
|
|
48505
|
+
actions: [
|
|
48506
|
+
{
|
|
48507
|
+
key: "edit",
|
|
48508
|
+
label: tr("fluidgrids.builder.editLease.edit", "Edit"),
|
|
48509
|
+
onClick: commands.takeOver,
|
|
48510
|
+
primary: true
|
|
48511
|
+
}
|
|
48512
|
+
]
|
|
48513
|
+
};
|
|
48514
|
+
case "idle":
|
|
48515
|
+
return {
|
|
48516
|
+
icon: "mynaui:pause",
|
|
48517
|
+
message: tr(
|
|
48518
|
+
"fluidgrids.builder.editLease.idle",
|
|
48519
|
+
"Editing paused after 15 minutes without activity, so others can edit this workflow."
|
|
48520
|
+
),
|
|
48521
|
+
actions: [
|
|
48522
|
+
{
|
|
48523
|
+
key: "resume",
|
|
48524
|
+
label: tr("fluidgrids.builder.editLease.resume", "Resume editing"),
|
|
48525
|
+
onClick: commands.resume,
|
|
48526
|
+
primary: true
|
|
48527
|
+
}
|
|
48528
|
+
]
|
|
48529
|
+
};
|
|
48530
|
+
case "reloading":
|
|
48531
|
+
return {
|
|
48532
|
+
icon: "mynaui:spinner",
|
|
48533
|
+
message: tr(
|
|
48534
|
+
"fluidgrids.builder.editLease.reloading",
|
|
48535
|
+
"Loading the latest version\u2026"
|
|
48536
|
+
),
|
|
48537
|
+
actions: []
|
|
48538
|
+
};
|
|
48539
|
+
}
|
|
48540
|
+
}
|
|
48541
|
+
function EditLeaseBanner() {
|
|
48542
|
+
const tr = useTr();
|
|
48543
|
+
const lease = useEditLeaseStore(
|
|
48544
|
+
useShallow((s) => ({
|
|
48545
|
+
phase: s.phase,
|
|
48546
|
+
held: s.held,
|
|
48547
|
+
holderActorId: s.holderActorId,
|
|
48548
|
+
heldByCaller: s.heldByCaller,
|
|
48549
|
+
takenBy: s.takenBy,
|
|
48550
|
+
takenByCaller: s.takenByCaller
|
|
48551
|
+
}))
|
|
48552
|
+
);
|
|
48553
|
+
const banner = bannerOf(lease);
|
|
48554
|
+
const name = useActorName(banner ? actorOf(banner) : null);
|
|
48555
|
+
const workflowName = useFlowStore((s) => s.workflow.name);
|
|
48556
|
+
const statusDirty = useSaveStatusStore((s) => s.dirty);
|
|
48557
|
+
useSaveStatusStore((s) => s.baseline);
|
|
48558
|
+
const canvasDirty = useFlowStore((s) => editStateFor(s) === "dirty");
|
|
48559
|
+
const dirty = statusDirty || canvasDirty;
|
|
48560
|
+
const { saveToBackend } = useSaveWorkflow();
|
|
48561
|
+
const [busy, setBusy] = useState(false);
|
|
48562
|
+
if (!banner) return null;
|
|
48563
|
+
const run = (action) => () => {
|
|
48564
|
+
setBusy(true);
|
|
48565
|
+
void Promise.resolve().then(action).finally(() => setBusy(false));
|
|
48566
|
+
};
|
|
48567
|
+
const view = bannerView(
|
|
48568
|
+
banner,
|
|
48569
|
+
{
|
|
48570
|
+
someone: name ?? tr("fluidgrids.builder.editLease.someone", "Someone else"),
|
|
48571
|
+
dirty,
|
|
48572
|
+
tr
|
|
48573
|
+
},
|
|
48574
|
+
{
|
|
48575
|
+
takeOver: run(takeOverEditLease),
|
|
48576
|
+
refresh: reloadLatestVersion,
|
|
48577
|
+
keepMine: run(() => saveToBackend({ asNewVersion: true })),
|
|
48578
|
+
resume: run(resumeEditLease)
|
|
48579
|
+
}
|
|
48580
|
+
);
|
|
48581
|
+
return /* @__PURE__ */ jsxs(
|
|
48582
|
+
"div",
|
|
48583
|
+
{
|
|
48584
|
+
role: "status",
|
|
48585
|
+
"data-testid": "fluidgrids-edit-lease-banner",
|
|
48586
|
+
"data-state": banner.kind,
|
|
48587
|
+
className: "mx-4 mt-2 flex flex-wrap items-center gap-x-3 gap-y-2 rounded-t-xl border border-status-warning-border bg-status-warning-bg-subtle px-4 py-2 text-sm text-status-warning-text",
|
|
48588
|
+
children: [
|
|
48589
|
+
/* @__PURE__ */ jsx(
|
|
48590
|
+
Icon,
|
|
48591
|
+
{
|
|
48592
|
+
icon: view.icon,
|
|
48593
|
+
className: banner.kind === "reloading" ? "size-4 animate-spin" : "size-4",
|
|
48594
|
+
"aria-hidden": true
|
|
48595
|
+
}
|
|
48596
|
+
),
|
|
48597
|
+
workflowName ? /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: workflowName }) : null,
|
|
48598
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: view.message }),
|
|
48599
|
+
view.actions.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: view.actions.map((action) => /* @__PURE__ */ jsx(
|
|
48600
|
+
Button$2,
|
|
48601
|
+
{
|
|
48602
|
+
size: "sm",
|
|
48603
|
+
variant: action.primary ? "default" : "outline",
|
|
48604
|
+
disabled: busy,
|
|
48605
|
+
"data-testid": `fluidgrids-edit-lease-${action.key}`,
|
|
48606
|
+
onClick: action.onClick,
|
|
48607
|
+
children: action.label
|
|
48608
|
+
},
|
|
48609
|
+
action.key
|
|
48610
|
+
)) }) : null
|
|
48611
|
+
]
|
|
48612
|
+
}
|
|
48613
|
+
);
|
|
48614
|
+
}
|
|
47248
48615
|
var edgeTypes2 = {
|
|
47249
48616
|
deletable: CustomDeletableEdge
|
|
47250
48617
|
};
|
|
@@ -47261,9 +48628,38 @@ var edgeOptions = {
|
|
|
47261
48628
|
strokeWidth: 1.5
|
|
47262
48629
|
}
|
|
47263
48630
|
};
|
|
48631
|
+
function canvasEditingProps(blocked2, editing) {
|
|
48632
|
+
if (blocked2) {
|
|
48633
|
+
return {
|
|
48634
|
+
nodesDraggable: false,
|
|
48635
|
+
nodesConnectable: false,
|
|
48636
|
+
elementsSelectable: false,
|
|
48637
|
+
multiSelectionKeyCode: null,
|
|
48638
|
+
deleteKeyCode: null
|
|
48639
|
+
};
|
|
48640
|
+
}
|
|
48641
|
+
return {
|
|
48642
|
+
...editing,
|
|
48643
|
+
nodesDraggable: true,
|
|
48644
|
+
nodesConnectable: true,
|
|
48645
|
+
elementsSelectable: true,
|
|
48646
|
+
// Ctrl/Cmd-click adds a node to the selection; box-select via Shift-drag
|
|
48647
|
+
// on empty canvas is React Flow's own default and needs no extra prop.
|
|
48648
|
+
multiSelectionKeyCode: ["Meta", "Control"]
|
|
48649
|
+
};
|
|
48650
|
+
}
|
|
48651
|
+
function useEditingBlocked(isReadOnly) {
|
|
48652
|
+
const { allowed: canEdit } = useFluidGridsPermission(
|
|
48653
|
+
FLUIDGRIDS_PERMISSIONS.WORKFLOW_UPDATE
|
|
48654
|
+
);
|
|
48655
|
+
useEditLease(!isReadOnly && canEdit);
|
|
48656
|
+
const leaseLocked = useEditLeaseLocked() && !isReadOnly;
|
|
48657
|
+
return { leaseLocked, editingBlocked: isReadOnly || leaseLocked };
|
|
48658
|
+
}
|
|
47264
48659
|
var FlowBuilder = ({ readOnly = false }) => {
|
|
47265
48660
|
const searchParams = new URLSearchParams(window.location.search);
|
|
47266
48661
|
const isReadOnly = readOnly || searchParams.get("readonly") === "true";
|
|
48662
|
+
const { leaseLocked, editingBlocked } = useEditingBlocked(isReadOnly);
|
|
47267
48663
|
const durableFunctionsEnabled = useDurableFunctionNodesEnabled();
|
|
47268
48664
|
const durableFunctionsEnabledRef = useRef(durableFunctionsEnabled);
|
|
47269
48665
|
useEffect(() => {
|
|
@@ -47275,7 +48671,7 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
47275
48671
|
}),
|
|
47276
48672
|
[]
|
|
47277
48673
|
);
|
|
47278
|
-
useAgentTools(agentTools, !
|
|
48674
|
+
useAgentTools(agentTools, !editingBlocked);
|
|
47279
48675
|
const [nodes, edges, onNodesChange, onEdgesChange, onConnect] = useFlowStore(
|
|
47280
48676
|
useShallow((s) => {
|
|
47281
48677
|
return [
|
|
@@ -47367,10 +48763,11 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
47367
48763
|
onNodesChange
|
|
47368
48764
|
]
|
|
47369
48765
|
);
|
|
47370
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full w-full overflow-hidden", children: [
|
|
47371
|
-
!
|
|
48766
|
+
return /* @__PURE__ */ jsx(BuilderReadOnlyProvider, { value: editingBlocked, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full w-full overflow-hidden", children: [
|
|
48767
|
+
!editingBlocked && /* @__PURE__ */ jsx(BuilderHeader, {}),
|
|
47372
48768
|
!isReadOnly && /* @__PURE__ */ jsx(CodeVersionNotice, {}),
|
|
47373
|
-
/* @__PURE__ */ jsx(
|
|
48769
|
+
leaseLocked && /* @__PURE__ */ jsx(EditLeaseBanner, {}),
|
|
48770
|
+
/* @__PURE__ */ jsx(BuilderSaveController, { readOnly: isReadOnly, locked: leaseLocked }),
|
|
47374
48771
|
/* @__PURE__ */ jsxs(
|
|
47375
48772
|
"div",
|
|
47376
48773
|
{
|
|
@@ -47404,21 +48801,19 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
47404
48801
|
edgeTypes: edgeTypes2,
|
|
47405
48802
|
edges,
|
|
47406
48803
|
onEdgesChange,
|
|
47407
|
-
|
|
47408
|
-
|
|
47409
|
-
|
|
47410
|
-
|
|
48804
|
+
...canvasEditingProps(editingBlocked, {
|
|
48805
|
+
onConnect,
|
|
48806
|
+
onConnectEnd: handleOnEdgeDropConnectEnd,
|
|
48807
|
+
onDrop,
|
|
48808
|
+
onDragOver,
|
|
48809
|
+
deleteKeyCode
|
|
48810
|
+
}),
|
|
47411
48811
|
onNodeDragStop: (_, node2) => {
|
|
47412
48812
|
autoAdjustNode(node2);
|
|
47413
48813
|
},
|
|
47414
48814
|
onPaneClick: closeQuickConfig,
|
|
47415
48815
|
onNodesDelete,
|
|
47416
48816
|
isValidConnection,
|
|
47417
|
-
nodesDraggable: !isReadOnly,
|
|
47418
|
-
nodesConnectable: !isReadOnly,
|
|
47419
|
-
elementsSelectable: !isReadOnly,
|
|
47420
|
-
multiSelectionKeyCode: isReadOnly ? null : ["Meta", "Control"],
|
|
47421
|
-
deleteKeyCode: isReadOnly ? null : deleteKeyCode,
|
|
47422
48817
|
snapGrid: [16, 16],
|
|
47423
48818
|
snapToGrid: true,
|
|
47424
48819
|
fitView: true,
|
|
@@ -47428,7 +48823,7 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
47428
48823
|
}
|
|
47429
48824
|
),
|
|
47430
48825
|
/* @__PURE__ */ jsx(FluidGridsMark, {}),
|
|
47431
|
-
nodes.length === 0 && !
|
|
48826
|
+
nodes.length === 0 && !editingBlocked && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3 text-center", children: [
|
|
47432
48827
|
/* @__PURE__ */ jsx("div", { className: "size-16 flex items-center justify-center rounded-full bg-primary/10 border-2 border-dashed border-primary/30", children: /* @__PURE__ */ jsx(
|
|
47433
48828
|
Icon,
|
|
47434
48829
|
{
|
|
@@ -47444,10 +48839,8 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
47444
48839
|
),
|
|
47445
48840
|
/* @__PURE__ */ jsx(ChatPanel, {}),
|
|
47446
48841
|
/* @__PURE__ */ jsx(LogsPanel, {}),
|
|
47447
|
-
/* @__PURE__ */
|
|
47448
|
-
|
|
47449
|
-
/* @__PURE__ */ jsx(QuickConfigPanel, {})
|
|
47450
|
-
] }),
|
|
48842
|
+
/* @__PURE__ */ jsx(NodeDetailView, {}),
|
|
48843
|
+
/* @__PURE__ */ jsx(QuickConfigPanel, {}),
|
|
47451
48844
|
!isReadOnly && /* @__PURE__ */ jsx(WebhookRunFollower, {}),
|
|
47452
48845
|
/* @__PURE__ */ jsx(
|
|
47453
48846
|
"div",
|
|
@@ -47459,7 +48852,7 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
47459
48852
|
children: /* @__PURE__ */ jsx("div", { ref: floatingMenuWrapperRef, className: "relative size-full", children: /* @__PURE__ */ jsx(AddNodeFloatingMenu, { onNodeAdd: handleAddConnectedNode }) })
|
|
47460
48853
|
}
|
|
47461
48854
|
)
|
|
47462
|
-
] });
|
|
48855
|
+
] }) });
|
|
47463
48856
|
};
|
|
47464
48857
|
function IntegrationReturnHandler() {
|
|
47465
48858
|
const { setNodes, getNodes } = useReactFlow();
|
|
@@ -47551,6 +48944,7 @@ var FlowBuilderPage = ({
|
|
|
47551
48944
|
const setWorkflow = useFlowStore((s) => s.actions.setWorkflow);
|
|
47552
48945
|
const searchParams = new URLSearchParams(window.location.search);
|
|
47553
48946
|
const isReadOnly = readOnly || searchParams.get("readonly") === "true";
|
|
48947
|
+
const leaseLocked = useEditLeaseLocked();
|
|
47554
48948
|
const resetWorkflow = useFlowStore((s) => s.actions.resetWorkflow);
|
|
47555
48949
|
const [isStoreReady, setIsStoreReady] = useState(false);
|
|
47556
48950
|
const syncedWorkflowRef = useRef(null);
|
|
@@ -47591,9 +48985,9 @@ var FlowBuilderPage = ({
|
|
|
47591
48985
|
/* @__PURE__ */ jsx(HistoricalRunLoader, {}),
|
|
47592
48986
|
/* @__PURE__ */ jsx("div", { className: "flex flex-col h-full", children: /* @__PURE__ */ jsxs("div", { className: "relative flex grow min-h-0 divide-x divide-card-foreground/10", children: [
|
|
47593
48987
|
/* @__PURE__ */ jsx("div", { className: "grow min-w-0 bg-card md:bg-transparent", children: /* @__PURE__ */ jsx(FlowBuilder, { readOnly: isReadOnly }) }),
|
|
47594
|
-
!isReadOnly && /* @__PURE__ */ jsx(SidebarModule, {})
|
|
48988
|
+
!isReadOnly && !leaseLocked && /* @__PURE__ */ jsx(SidebarModule, {})
|
|
47595
48989
|
] }) })
|
|
47596
48990
|
] });
|
|
47597
48991
|
};
|
|
47598
48992
|
|
|
47599
|
-
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, FlowBuilderPage, FluidGridsMark, Popover, PopoverContent, PopoverTrigger, RUNNER_INSTALL_SCRIPT_URL, RunOnSection, RunnerStatusPill, RunsUsageMeter, RunsUsageMeterView, TemplateCard, buildNodeCheck, buildRequiredNodeTypes, external_exports, readRunsQuota, runnerInstallCommand, runsQuotaLevel, summarizeRunsQuota, useImportWorkflowTemplate, useInstalledNodes, useRunnerActions, useRunners, useRunsQuota, useWorkflowTemplates };
|
|
48993
|
+
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, FlowBuilderPage, FluidGridsMark, Popover, PopoverContent, PopoverTrigger, RUNNER_INSTALL_SCRIPT_URL, RunOnSection, RunnerStatusPill, RunsUsageMeter, RunsUsageMeterView, TemplateCard, buildNodeCheck, buildRequiredNodeTypes, external_exports, readRunsQuota, releaseLeaseKeptForReload, runnerInstallCommand, runsQuotaLevel, summarizeRunsQuota, useImportWorkflowTemplate, useInstalledNodes, useRunnerActions, useRunners, useRunsQuota, useWorkflowReloadStore, useWorkflowTemplates };
|