@@ -4,11 +4,12 @@ import { API } from "@api";
44import { storeToRefs } from " pinia" ;
55
66import { type MenuItem , SubMenu , useHint } from " @knime/components" ;
7+ import { Button } from " @knime/kds-components" ;
78import ArrowMoveIcon from " @knime/styles/img/icons/arrow-move.svg" ;
89import CloudUploadIcon from " @knime/styles/img/icons/cloud-upload.svg" ;
910import 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" ;
1213import AnnotationModeIcon from " @/assets/annotation-mode.svg" ;
1314import SelectionModeIcon from " @/assets/selection-mode.svg" ;
1415import ToolbarButton from " @/components/common/ToolbarButton.vue" ;
@@ -24,6 +25,7 @@ import {
2425 useCanvasModesStore ,
2526} from " @/store/application/canvasModes" ;
2627import { useDirtyProjectsTrackingStore } from " @/store/application/dirtyProjectsTracking" ;
28+ import { useLifecycleStore } from " @/store/application/lifecycle" ;
2729import { useSelectionStore } from " @/store/selection" ;
2830import { useSpaceProvidersStore } from " @/store/spaces/providers" ;
2931import { useUIControlsStore } from " @/store/uiControls/uiControls" ;
@@ -44,9 +46,8 @@ import ZoomMenu from "./ZoomMenu.vue";
4446const $shortcuts = useShortcuts ();
4547const uiControls = useUIControlsStore ();
4648const workflowVersionsStore = useWorkflowVersionsStore ();
47- const { activeProjectId, activeProjectOrigin, isUnknownProject } = storeToRefs (
48- useApplicationStore (),
49- );
49+ const { activeProjectId, activeProjectOrigin, isUnknownProject, syncState } =
50+ storeToRefs (useApplicationStore ());
5051const { activeWorkflow, isWorkflowEmpty, isActiveWorkflowFixedVersion } =
5152 storeToRefs (useWorkflowStore ());
5253const { getSelectedNodes : selectedNodes } = storeToRefs (useSelectionStore ());
@@ -265,10 +266,44 @@ const ToolbarButtonWithHint = defineComponent(
265266);
266267
267268const { 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 : 1 px solid var (--knime-silver-sand );
370405
406+ & .sync-button {
407+ margin-right : 12 px ;
408+ }
409+
371410 & .button-list {
372411 transition : opacity 150 ms ease-out;
373412 flex-shrink : 0 ;
0 commit comments