Skip to content

Commit

Permalink
extract all collaboration code into CollaborationPane
Browse files Browse the repository at this point in the history
  • Loading branch information
netroy committed Sep 10, 2024
1 parent f40d82f commit acdc168
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 40 deletions.
39 changes: 35 additions & 4 deletions packages/editor-ui/src/components/MainHeader/CollaborationPane.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
<script setup lang="ts">
import { computed, ref, onBeforeMount, onBeforeUnmount, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { TIME } from '@/constants';
import { useBeforeUnload } from '@/composables/useBeforeUnload';
import { useUsersStore } from '@/stores/users.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { useCollaborationStore } from '@/stores/collaboration.store';
import { onBeforeUnmount, onMounted, computed, ref } from 'vue';
import { TIME } from '@/constants';
import { useUIStore } from '@/stores/ui.store';
import { isUserGlobalOwner } from '@/utils/userUtils';
const route = useRoute();
const collaborationStore = useCollaborationStore();
const usersStore = useUsersStore();
const workflowsStore = useWorkflowsStore();
const uiStore = useUIStore();
const HEARTBEAT_INTERVAL = 5 * TIME.MINUTE;
const heartbeatTimer = ref<number | null>(null);
Expand Down Expand Up @@ -53,16 +59,41 @@ const onDocumentVisibilityChange = () => {
}
};
onMounted(() => {
const { addBeforeUnloadHandler } = useBeforeUnload({ route });
const unloadTimeout = ref<NodeJS.Timeout | null>(null);
const beforeUnloadHandler = () => {
const { workflowId } = workflowsStore;
// Notify that workflow is closed straight away
collaborationStore.notifyWorkflowClosed(workflowId);
if (uiStore.stateIsDirty) {
// If user decided to stay on the page we notify that the workflow is opened again
unloadTimeout.value = setTimeout(() => {
collaborationStore.notifyWorkflowOpened(workflowId);
}, 5 * TIME.SECOND);
}
};
onBeforeMount(() => {
collaborationStore.initialize();
startHeartbeat();
document.addEventListener('visibilitychange', onDocumentVisibilityChange);
addBeforeUnloadHandler(beforeUnloadHandler);
});
onMounted(() => {
collaborationStore.notifyWorkflowOpened(workflowsStore.workflowId);
});
onBeforeUnmount(() => {
collaborationStore.notifyWorkflowClosed(workflowsStore.workflowId);
collaborationStore.terminate();
document.removeEventListener('visibilitychange', onDocumentVisibilityChange);
stopHeartbeat();
collaborationStore.terminate();
if (unloadTimeout.value) {
clearTimeout(unloadTimeout.value);
}
});
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ function showCreateWorkflowSuccessToast(id?: string) {
</span>
<EnterpriseEdition :features="[EnterpriseEditionFeature.Sharing]">
<div :class="$style.group">
<CollaborationPane v-if="nodeViewVersion === '2'" />
<CollaborationPane v-if="nodeViewVersion === '2' && !isNewWorkflow" />
<N8nButton
type="secondary"
data-test-id="workflow-share-button"
Expand Down
5 changes: 4 additions & 1 deletion packages/editor-ui/src/stores/collaboration.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineStore } from 'pinia';
import { computed, ref } from 'vue';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { usePushConnectionStore } from '@/stores/pushConnection.store';
import { STORES } from '@/constants';
import { STORES, PLACEHOLDER_EMPTY_WORKFLOW_ID } from '@/constants';
import type { IUser } from '@/Interface';
import { useUsersStore } from '@/stores/users.store';

Expand Down Expand Up @@ -44,6 +44,7 @@ export const useCollaborationStore = defineStore(STORES.COLLABORATION, () => {
pushStoreEventListenerRemovalFn.value();
pushStoreEventListenerRemovalFn.value = null;
}
pushStore.clearQueue();
}

function workflowUsersUpdated(data: ActiveUsersForWorkflows) {
Expand All @@ -62,13 +63,15 @@ export const useCollaborationStore = defineStore(STORES.COLLABORATION, () => {
}

function notifyWorkflowOpened(workflowId: string) {
if (workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID) return;
pushStore.send({
type: 'workflowOpened',
workflowId,
});
}

function notifyWorkflowClosed(workflowId: string) {
if (workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID) return;
pushStore.send({ type: 'workflowClosed', workflowId });

functionRemoveCurrentUserFromActiveUsers(workflowId);
Expand Down
5 changes: 5 additions & 0 deletions packages/editor-ui/src/stores/pushConnection.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ export const usePushConnectionStore = defineStore(STORES.PUSH, () => {
onMessageReceivedHandlers.value.forEach((handler) => handler(receivedData));
}

const clearQueue = () => {
outgoingQueue.value = [];
};

return {
pushRef,
pushSource,
Expand All @@ -159,5 +163,6 @@ export const usePushConnectionStore = defineStore(STORES.PUSH, () => {
pushConnect,
pushDisconnect,
send,
clearQueue,
};
});
33 changes: 6 additions & 27 deletions packages/editor-ui/src/views/NodeView.v2.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ import {
PLACEHOLDER_EMPTY_WORKFLOW_ID,
START_NODE_TYPE,
STICKY_NODE_TYPE,
TIME,
VALID_WORKFLOW_IMPORT_URL_REGEX,
VIEWS,
WORKFLOW_LM_CHAT_MODAL_KEY,
Expand Down Expand Up @@ -104,7 +103,6 @@ import { createEventBus } from 'n8n-design-system';
import type { PinDataSource } from '@/composables/usePinnedData';
import { useClipboard } from '@/composables/useClipboard';
import { useBeforeUnload } from '@/composables/useBeforeUnload';
import { useCollaborationStore } from '@/stores/collaboration.store';
import { getResourcePermissions } from '@/permissions';
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
Expand Down Expand Up @@ -138,7 +136,6 @@ const credentialsStore = useCredentialsStore();
const environmentsStore = useEnvironmentsStore();
const externalSecretsStore = useExternalSecretsStore();
const rootStore = useRootStore();
const collaborationStore = useCollaborationStore();
const executionsStore = useExecutionsStore();
const canvasStore = useCanvasStore();
const npsSurveyStore = useNpsSurveyStore();
Expand All @@ -152,10 +149,9 @@ const templatesStore = useTemplatesStore();
const canvasEventBus = createEventBus<CanvasEventBusEvents>();
const { addBeforeUnloadEventBindings, removeBeforeUnloadEventBindings, addBeforeUnloadHandler } =
useBeforeUnload({
route,
});
const { addBeforeUnloadEventBindings, removeBeforeUnloadEventBindings } = useBeforeUnload({
route,
});
const { registerCustomAction, unregisterCustomAction } = useGlobalLinkActions();
const { runWorkflow, stopCurrentExecution, stopWaitingForWebhook } = useRunWorkflow({ router });
const {
Expand Down Expand Up @@ -355,8 +351,6 @@ async function initializeWorkspaceForExistingWorkflow(id: string) {
await projectsStore.setProjectNavActiveIdByWorkflowHomeProject(
editableWorkflow.value.homeProject,
);
collaborationStore.notifyWorkflowOpened(id);
} catch (error) {
toast.showError(error, i18n.baseText('openWorkflow.workflowNotFoundError'));
Expand Down Expand Up @@ -1484,12 +1478,9 @@ watch(
onBeforeMount(() => {
if (!isDemoRoute.value) {
pushConnectionStore.pushConnect();
collaborationStore.initialize();
}
});
const unloadTimeout = ref<NodeJS.Timeout | null>(null);
onMounted(() => {
canvasStore.startLoading();
Expand Down Expand Up @@ -1522,18 +1513,6 @@ onMounted(() => {
addImportEventBindings();
addExecutionOpenedEventBindings();
registerCustomActions();
addBeforeUnloadHandler(() => {
const { workflowId } = workflowsStore;
// Notify that workflow is closed straight away
collaborationStore.notifyWorkflowClosed(workflowId);
if (uiStore.stateIsDirty) {
// If user decided to stay on the page we notify that the workflow is opened again
unloadTimeout.value = setTimeout(() => {
collaborationStore.notifyWorkflowOpened(workflowId);
}, 5 * TIME.SECOND);
}
});
});
onActivated(async () => {
Expand All @@ -1552,9 +1531,9 @@ onBeforeUnmount(() => {
removeImportEventBindings();
removeExecutionOpenedEventBindings();
unregisterCustomActions();
collaborationStore.terminate();
if (unloadTimeout.value) {
clearTimeout(unloadTimeout.value);
if (!isDemoRoute.value) {
pushConnectionStore.pushDisconnect();
}
});
</script>
Expand Down
10 changes: 3 additions & 7 deletions packages/editor-ui/src/views/NodeViewSwitcher.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ onBeforeRouteLeave(async (to, from, next) => {
await workflowHelpers.promptSaveUnsavedWorkflowChanges(next, {
async confirm() {
// Make sure workflow id is empty when leaving the editor
workflowsStore.setWorkflowId(PLACEHOLDER_EMPTY_WORKFLOW_ID);
if (from.name === VIEWS.NEW_WORKFLOW) {
// Replace the current route with the new workflow route
// before navigating to the new route when saving new workflow.
Expand All @@ -72,11 +69,10 @@ onBeforeRouteLeave(async (to, from, next) => {
return false;
}
return true;
},
async cancel() {
// Make sure workflow id is empty when leaving the editor
workflowsStore.setWorkflowId(PLACEHOLDER_EMPTY_WORKFLOW_ID);
resetWorkspace();
return true;
},
});
});
Expand Down

0 comments on commit acdc168

Please sign in to comment.