Skip to content

Commit c5d537f

Browse files
Fix intermittent flicker after run from canvas, close run panel (#4628)
* close run panel after successful click * fix race condition * close run panel after run * CL
1 parent 1d8f156 commit c5d537f

4 files changed

Lines changed: 32 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ and this project adheres to
4242

4343
### Fixed
4444

45+
- Flickering/disappearing visualization on
46+
[#4198](https://github.com/OpenFn/lightning/issues/4198) fixed in
47+
[PR#4628](https://github.com/OpenFn/lightning/pull/4628)
4548
- AI-generated workflows can now be saved when the workflow name collides with
4649
an existing workflow or when jobs have duplicate names
4750
[#4607](https://github.com/OpenFn/lightning/issues/4607)

assets/js/collaborative-editor/components/ManualRunPanel.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export function ManualRunPanel({
149149
const { canRun: canRunWorkflow, tooltipMessage: workflowRunTooltipMessage } =
150150
useCanRun();
151151

152-
const { params } = useURLState();
152+
const { params, updateSearchParams } = useURLState();
153153
const followedRunId = params.run ?? null;
154154

155155
// Connect to run channel when following a run in standalone mode
@@ -449,10 +449,17 @@ export function ManualRunPanel({
449449
25 // RUN_PANEL priority
450450
);
451451

452+
// Close the run panel and clear the URL param so the URL→state sync
453+
// in WorkflowEditor doesn't immediately reopen it.
454+
const closeAfterRun = useCallback(() => {
455+
updateSearchParams({ panel: null });
456+
onClose();
457+
}, [updateSearchParams, onClose]);
458+
452459
// Run/retry shortcuts (standalone mode only - embedded uses IDEHeader)
453460
useRunRetryShortcuts({
454-
onRun: () => void handleRun(),
455-
onRetry: () => void handleRetry(),
461+
onRun: () => void handleRun().then(ok => ok && closeAfterRun()),
462+
onRetry: () => void handleRetry().then(ok => ok && closeAfterRun()),
456463
canRun,
457464
isRunning: isSubmitting || runIsProcessing,
458465
isRetryable,
@@ -634,10 +641,10 @@ export function ManualRunPanel({
634641
isDisabled={!canRun}
635642
isSubmitting={isSubmitting || runIsProcessing}
636643
onRun={() => {
637-
void handleRun();
644+
void handleRun().then(ok => ok && closeAfterRun());
638645
}}
639646
onRetry={() => {
640-
void handleRetry();
647+
void handleRetry().then(ok => ok && closeAfterRun());
641648
}}
642649
buttonText={{
643650
run: 'Run',

assets/js/collaborative-editor/hooks/useRunRetry.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ export interface UseRunRetryOptions {
7979
}
8080

8181
export interface UseRunRetryReturn {
82-
handleRun: () => Promise<void>;
83-
handleRetry: () => Promise<void>;
82+
handleRun: () => Promise<boolean>;
83+
handleRetry: () => Promise<boolean>;
8484
isSubmitting: boolean;
8585
isRetryable: boolean;
8686
runIsProcessing: boolean;
@@ -237,7 +237,7 @@ export function useRunRetry({
237237
const contextId = runContext.id;
238238
if (!contextId) {
239239
logger.error('No context ID available');
240-
return;
240+
return false;
241241
}
242242

243243
// Check workflow-level permissions before running
@@ -246,7 +246,7 @@ export function useRunRetry({
246246
title: 'Cannot run workflow',
247247
description: workflowRunTooltipMessage,
248248
});
249-
return;
249+
return false;
250250
}
251251

252252
setIsSubmitting(true);
@@ -297,6 +297,8 @@ export function useRunRetry({
297297
updateSearchParams({ run: response.data.run_id });
298298
setIsSubmitting(false);
299299
}
300+
301+
return true;
300302
} catch (error) {
301303
logger.error('Failed to submit run:', error);
302304
notifications.alert({
@@ -305,6 +307,7 @@ export function useRunRetry({
305307
error instanceof Error ? error.message : 'An unknown error occurred',
306308
});
307309
setIsSubmitting(false);
310+
return false;
308311
}
309312
}, [
310313
workflowId,
@@ -326,14 +329,14 @@ export function useRunRetry({
326329
const handleRetry = useCallback(async () => {
327330
// Guard against double-calls (e.g., from rapid keyboard shortcuts)
328331
if (isRetryingRef.current) {
329-
return;
332+
return false;
330333
}
331334
isRetryingRef.current = true;
332335

333336
if (!followedRunId || !followedRunStep) {
334337
logger.error('Cannot retry: missing run or step data');
335338
isRetryingRef.current = false;
336-
return;
339+
return false;
337340
}
338341

339342
if (!canRunWorkflow) {
@@ -342,7 +345,7 @@ export function useRunRetry({
342345
description: workflowRunTooltipMessage,
343346
});
344347
isRetryingRef.current = false;
345-
return;
348+
return false;
346349
}
347350

348351
setIsSubmitting(true);
@@ -396,6 +399,8 @@ export function useRunRetry({
396399
setIsSubmitting(false);
397400
isRetryingRef.current = false;
398401
}
402+
403+
return true;
399404
} catch (error) {
400405
logger.error('Failed to retry run:', error);
401406
notifications.alert({
@@ -404,6 +409,7 @@ export function useRunRetry({
404409
});
405410
setIsSubmitting(false);
406411
isRetryingRef.current = false;
412+
return false;
407413
}
408414
}, [
409415
followedRunId,

assets/js/collaborative-editor/stores/createHistoryStore.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -336,13 +336,10 @@ export const createHistoryStore = (
336336
});
337337
notify('handleHistoryUpdated');
338338

339-
// Fallback cache invalidation: If a run has completed (reached final state)
340-
// and there are active subscribers watching it, invalidate the cache to ensure
341-
// they get the complete final data on next read.
342-
//
343-
// This provides a safety net for components that use useRunSteps() without
344-
// useFollowRun() - they won't get real-time step updates, but will get
345-
// refreshed data when the run completes.
339+
// Stale-while-revalidate: If a run has completed (reached final state)
340+
// and there are active subscribers watching it, refetch the complete
341+
// final data in the background. We keep the existing cache entry visible
342+
// so the canvas highlighting doesn't flash/disappear during the refetch.
346343

347344
if ((action === 'run_updated' || action === 'run_created') && run) {
348345
const currentState = getSnapshot();
@@ -353,11 +350,6 @@ export const createHistoryStore = (
353350
subscribersForThisRun.size > 0 &&
354351
isFinalState(run.state)
355352
) {
356-
state = produce(state, draft => {
357-
Reflect.deleteProperty(draft.runStepsCache, run.id);
358-
});
359-
notify('cacheInvalidated');
360-
361353
void requestRunSteps(run.id);
362354
}
363355
}

0 commit comments

Comments
 (0)