Skip to content

Commit f0e2589

Browse files
committed
NXT-4224: WIP: Adding hacky first iteration UI
NXT-4224 (Automatically / Manually sync when editing workflows in the browser)
1 parent 9690094 commit f0e2589

File tree

3 files changed

+64
-4
lines changed

3 files changed

+64
-4
lines changed

org.knime.ui.js/src/components/toolbar/WorkflowToolbar.vue

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import { API } from "@api";
44
import { storeToRefs } from "pinia";
55
66
import { type MenuItem, SubMenu, useHint } from "@knime/components";
7+
import { Button } from "@knime/kds-components";
78
import ArrowMoveIcon from "@knime/styles/img/icons/arrow-move.svg";
89
import CloudUploadIcon from "@knime/styles/img/icons/cloud-upload.svg";
910
import DeploymentIcon from "@knime/styles/img/icons/deployment.svg";
1011
11-
import { WorkflowInfo } from "@/api/gateway-api/generated-api";
12+
import { AppState, WorkflowInfo } from "@/api/gateway-api/generated-api";
1213
import AnnotationModeIcon from "@/assets/annotation-mode.svg";
1314
import SelectionModeIcon from "@/assets/selection-mode.svg";
1415
import ToolbarButton from "@/components/common/ToolbarButton.vue";
@@ -24,6 +25,7 @@ import {
2425
useCanvasModesStore,
2526
} from "@/store/application/canvasModes";
2627
import { useDirtyProjectsTrackingStore } from "@/store/application/dirtyProjectsTracking";
28+
import { useLifecycleStore } from "@/store/application/lifecycle";
2729
import { useSelectionStore } from "@/store/selection";
2830
import { useSpaceProvidersStore } from "@/store/spaces/providers";
2931
import { useUIControlsStore } from "@/store/uiControls/uiControls";
@@ -44,9 +46,8 @@ import ZoomMenu from "./ZoomMenu.vue";
4446
const $shortcuts = useShortcuts();
4547
const uiControls = useUIControlsStore();
4648
const workflowVersionsStore = useWorkflowVersionsStore();
47-
const { activeProjectId, activeProjectOrigin, isUnknownProject } = storeToRefs(
48-
useApplicationStore(),
49-
);
49+
const { activeProjectId, activeProjectOrigin, isUnknownProject, syncState } =
50+
storeToRefs(useApplicationStore());
5051
const { activeWorkflow, isWorkflowEmpty, isActiveWorkflowFixedVersion } =
5152
storeToRefs(useWorkflowStore());
5253
const { getSelectedNodes: selectedNodes } = storeToRefs(useSelectionStore());
@@ -265,10 +266,44 @@ const ToolbarButtonWithHint = defineComponent(
265266
);
266267
267268
const { isSVGRenderer } = useCanvasRendererUtils();
269+
270+
// Hacky sync button logic
271+
const isSyncButtonVisible = computed(() => {
272+
return isBrowser();
273+
});
274+
275+
// Hacky sync button logic
276+
const onSyncClick = async () => {
277+
const projectId = activeProjectId.value!;
278+
const { toastPresets } = getToastPresets();
279+
280+
try {
281+
useLifecycleStore().setIsLoadingWorkflow(true);
282+
await API.workflow.saveProject({ projectId });
283+
useLifecycleStore().setIsLoadingWorkflow(false);
284+
} catch (error) {
285+
toastPresets.app.syncProjectFailed({ error });
286+
useLifecycleStore().setIsLoadingWorkflow(false);
287+
}
288+
};
289+
290+
// Hacky sync button logic
291+
const isSyncButtonDisabled = computed(() => {
292+
return syncState.value !== AppState.SyncStateEnum.OUTOFSYNC;
293+
});
268294
</script>
269295

270296
<template>
271297
<div class="toolbar">
298+
<!-- Hacky sync button directly displayed here -->
299+
<Button
300+
v-if="isSyncButtonVisible"
301+
:label="syncState"
302+
:disabled="isSyncButtonDisabled"
303+
class="sync-button"
304+
@click="onSyncClick"
305+
/>
306+
272307
<transition-group tag="div" name="button-list">
273308
<!--
274309
setting :key="the list of all visible buttons",
@@ -368,6 +403,10 @@ const { isSVGRenderer } = useCanvasRendererUtils();
368403
background-color: var(--knime-gray-ultra-light);
369404
border-bottom: 1px solid var(--knime-silver-sand);
370405
406+
& .sync-button {
407+
margin-right: 12px;
408+
}
409+
371410
& .button-list {
372411
transition: opacity 150ms ease-out;
373412
flex-shrink: 0;

org.knime.ui.js/src/store/application/application.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ export interface ApplicationState {
8585
dismissedUpdateBanner: boolean; // Property to track banner dismissal
8686
dismissedHomePageTile: boolean;
8787
dismissedHubLoginBanner: boolean;
88+
/**
89+
* Current synchronization state for automatic sync
90+
*/
91+
syncState: AppState.SyncStateEnum;
8892
}
8993

9094
/*
@@ -113,6 +117,7 @@ export const useApplicationStore = defineStore("application", {
113117
dismissedUpdateBanner: false,
114118
dismissedHomePageTile: false,
115119
dismissedHubLoginBanner: false,
120+
syncState: AppState.SyncStateEnum.SYNCED,
116121
}),
117122
actions: {
118123
setActiveProjectId(projectId: string | null) {
@@ -214,6 +219,10 @@ export const useApplicationStore = defineStore("application", {
214219
this.dismissedUpdateBanner = dismissed;
215220
},
216221

222+
setSyncState(syncState: AppState.SyncStateEnum) {
223+
this.syncState = syncState;
224+
},
225+
217226
// eslint-disable-next-line complexity
218227
replaceApplicationState(applicationState: AppState) {
219228
const applicationSettingsStore = useApplicationSettingsStore();
@@ -342,6 +351,10 @@ export const useApplicationStore = defineStore("application", {
342351
if (applicationState.hasOwnProperty("nodeRepositoryLoaded")) {
343352
this.setNodeRepositoryLoaded(applicationState.nodeRepositoryLoaded!);
344353
}
354+
355+
if (applicationState.hasOwnProperty("syncState")) {
356+
this.setSyncState(applicationState.syncState!);
357+
}
345358
},
346359
},
347360
getters: {

org.knime.ui.js/src/toastPresets/application.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { ToastPresetErrorHandler } from "./types";
66
export type ApplicationToastPresets = {
77
openProjectFailed: ToastPresetErrorHandler;
88
saveProjectFailed: ToastPresetErrorHandler;
9+
syncProjectFailed: ToastPresetErrorHandler;
910
};
1011

1112
export const getPresets = (
@@ -24,5 +25,12 @@ export const getPresets = (
2425
type: "error",
2526
headline: "Could not save workflow",
2627
}),
28+
29+
// Hacky sync error handling logic
30+
syncProjectFailed: ({ error }) =>
31+
defaultAPIErrorHandler($toast, error, {
32+
type: "error",
33+
headline: "Could not sync workflow",
34+
}),
2735
};
2836
};

0 commit comments

Comments
 (0)