From 184ed8e17da0715727195b227e99ad11bc12bb97 Mon Sep 17 00:00:00 2001 From: oleg Date: Fri, 5 Jan 2024 12:23:28 +0100 Subject: [PATCH] refactor: Migrate `genericHelpers` mixin to composable (#8220) ## Summary - Moved out canvas loading handling to canvas store - Tag editable routes via meta to remove router dependency from generic helpers - Replace all occurrences of `genericHelpers` mixin with composable and audit usage - Moved out `isRedirectSafe` and `getRedirectQueryParameter` out of genericHelpers to remove dependency on router Removing the router dependency is important, because `useRouter` and `useRoute` compostables are only available if called from component instance. So if composable is nested within another composable, we wouldn't be able to use these. In this case we'd always need to inject the router and pass it through several composables. That's why I moved the `readonly` logic to router meta and `isRedirectSafe` and `getRedirectQueryParameter` out as they were only used in a single component. --------- Signed-off-by: Oleg Ivaniv --- .../src/components/BreakpointsObserver.vue | 3 +- .../src/components/CollectionWorkflowCard.vue | 2 - .../src/components/ExecutionTime.vue | 10 +-- .../src/components/ExecutionsList.vue | 5 +- .../src/components/ExpressionEdit.vue | 38 ++++++-- .../components/MainHeader/WorkflowDetails.vue | 9 +- .../editor-ui/src/components/MainSidebar.vue | 24 ++--- .../src/components/NodeCredentials.vue | 4 +- .../editor-ui/src/components/NodeList.vue | 2 - .../editor-ui/src/components/OutputPanel.vue | 2 +- .../src/components/ParameterInput.vue | 2 +- .../ResourceLocator/ResourceLocator.vue | 2 +- packages/editor-ui/src/components/RunData.vue | 12 +-- .../src/components/RunDataJsonActions.vue | 9 +- .../editor-ui/src/components/TemplateCard.vue | 2 - .../src/components/TemplateFilters.vue | 2 - .../editor-ui/src/components/TemplateList.vue | 2 - .../src/components/TemplatesInfoCard.vue | 2 - .../src/components/TemplatesInfoCarousel.vue | 3 - .../src/components/WorkerList.ee.vue | 3 +- .../src/components/WorkflowSettings.vue | 7 +- .../src/composables/useHistoryHelper.ts | 10 +-- .../src/composables/useLoadingService.ts | 5 +- .../src/composables/useNodeHelpers.ts | 1 - packages/editor-ui/src/constants.ts | 2 + .../editor-ui/src/mixins/executionsHelpers.ts | 8 +- .../editor-ui/src/mixins/genericHelpers.ts | 89 ------------------- .../editor-ui/src/mixins/workflowHelpers.ts | 12 +-- packages/editor-ui/src/plugins/i18n/index.ts | 16 ++++ packages/editor-ui/src/router.ts | 17 +++- packages/editor-ui/src/stores/canvas.store.ts | 6 ++ packages/editor-ui/src/types/router.ts | 1 + .../src/utils/formatters/dateFormatter.ts | 12 +++ packages/editor-ui/src/views/MfaView.vue | 2 - packages/editor-ui/src/views/NodeView.vue | 73 ++++++++------- packages/editor-ui/src/views/SigninView.vue | 13 ++- .../src/views/TemplatesSearchView.vue | 3 +- .../editor-ui/src/views/WorkflowsView.vue | 5 +- 38 files changed, 199 insertions(+), 221 deletions(-) delete mode 100644 packages/editor-ui/src/mixins/genericHelpers.ts diff --git a/packages/editor-ui/src/components/BreakpointsObserver.vue b/packages/editor-ui/src/components/BreakpointsObserver.vue index fb5e1e9530..e433c4b5c4 100644 --- a/packages/editor-ui/src/components/BreakpointsObserver.vue +++ b/packages/editor-ui/src/components/BreakpointsObserver.vue @@ -17,14 +17,13 @@ import { BREAKPOINT_SM, BREAKPOINT_MD, BREAKPOINT_LG, BREAKPOINT_XL } from '@/co * xl >= 1920 */ -import { genericHelpers } from '@/mixins/genericHelpers'; import { debounceHelper } from '@/mixins/debounce'; import { useUIStore } from '@/stores/ui.store'; import { getBannerRowHeight } from '@/utils/htmlUtils'; export default defineComponent({ name: 'BreakpointsObserver', - mixins: [genericHelpers, debounceHelper], + mixins: [debounceHelper], props: ['valueXS', 'valueXL', 'valueLG', 'valueMD', 'valueSM', 'valueDefault'], data() { return { diff --git a/packages/editor-ui/src/components/CollectionWorkflowCard.vue b/packages/editor-ui/src/components/CollectionWorkflowCard.vue index f1ece84c48..82f6f1b1bc 100644 --- a/packages/editor-ui/src/components/CollectionWorkflowCard.vue +++ b/packages/editor-ui/src/components/CollectionWorkflowCard.vue @@ -12,11 +12,9 @@ - - diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index b62aca72f2..749e09834c 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -107,7 +107,7 @@ v-else-if="execution.stoppedAt !== null && execution.stoppedAt !== undefined" > {{ - displayTimer( + i18n.displayTimer( new Date(execution.stoppedAt).getTime() - new Date(execution.startedAt).getTime(), true, @@ -288,7 +288,6 @@ import { mapStores } from 'pinia'; import ExecutionTime from '@/components/ExecutionTime.vue'; import ExecutionFilter from '@/components/ExecutionFilter.vue'; import { MODAL_CONFIRM, VIEWS, WAIT_TIME_UNLIMITED } from '@/constants'; -import { genericHelpers } from '@/mixins/genericHelpers'; import { executionHelpers } from '@/mixins/executionsHelpers'; import { useToast } from '@/composables/useToast'; import { useMessage } from '@/composables/useMessage'; @@ -318,7 +317,7 @@ export default defineComponent({ ExecutionTime, ExecutionFilter, }, - mixins: [genericHelpers, executionHelpers], + mixins: [executionHelpers], props: { autoRefreshEnabled: { type: Boolean, diff --git a/packages/editor-ui/src/components/ExpressionEdit.vue b/packages/editor-ui/src/components/ExpressionEdit.vue index f9254c895d..537ca68dff 100644 --- a/packages/editor-ui/src/components/ExpressionEdit.vue +++ b/packages/editor-ui/src/components/ExpressionEdit.vue @@ -50,7 +50,7 @@ ({}), + }, + path: { + type: String, + default: '', + }, + modelValue: { + type: String, + default: '', + }, + eventSource: { + type: String, + default: '', + }, + redactValues: { + type: Boolean, + default: false, + }, + isReadOnly: { + type: Boolean, + default: false, + }, + }, setup() { const externalHooks = useExternalHooks(); + return { externalHooks, }; diff --git a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue index e69019c1f7..c405bf6146 100644 --- a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue +++ b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue @@ -183,8 +183,8 @@ import type { IPermissions } from '@/permissions'; import { getWorkflowPermissions } from '@/permissions'; import { createEventBus } from 'n8n-design-system/utils'; import { nodeViewEventBus } from '@/event-bus'; -import { genericHelpers } from '@/mixins/genericHelpers'; import { hasPermission } from '@/rbac/permissions'; +import { useCanvasStore } from '@/stores/canvas.store'; const hasChanged = (prev: string[], curr: string[]) => { if (prev.length !== curr.length) { @@ -208,7 +208,7 @@ export default defineComponent({ BreakpointsObserver, CollaborationPane, }, - mixins: [workflowHelpers, genericHelpers], + mixins: [workflowHelpers], props: { readOnly: { type: Boolean, @@ -244,6 +244,7 @@ export default defineComponent({ useWorkflowsStore, useUsersStore, useSourceControlStore, + useCanvasStore, ), currentUser(): IUser | null { return this.usersStore.currentUser; @@ -586,7 +587,7 @@ export default defineComponent({ break; } case WORKFLOW_MENU_ACTIONS.PUSH: { - this.startLoading(); + this.canvasStore.startLoading(); try { await this.onSaveButtonClick(); @@ -610,7 +611,7 @@ export default defineComponent({ this.showError(error, this.$locale.baseText('error')); } } finally { - this.stopLoading(); + this.canvasStore.stopLoading(); } break; diff --git a/packages/editor-ui/src/components/MainSidebar.vue b/packages/editor-ui/src/components/MainSidebar.vue index 2ae5335341..32b8e07a0f 100644 --- a/packages/editor-ui/src/components/MainSidebar.vue +++ b/packages/editor-ui/src/components/MainSidebar.vue @@ -104,11 +104,7 @@ import type { CloudPlanAndUsageData, IExecutionResponse, IMenuItem, IVersion } from '@/Interface'; import GiftNotificationIcon from './GiftNotificationIcon.vue'; -import { genericHelpers } from '@/mixins/genericHelpers'; import { useMessage } from '@/composables/useMessage'; -import { workflowHelpers } from '@/mixins/workflowHelpers'; -import { workflowRun } from '@/mixins/workflowRun'; - import { ABOUT_MODAL_KEY, VERSIONS_MODAL_KEY, VIEWS } from '@/constants'; import { userHelpers } from '@/mixins/userHelpers'; import { debounceHelper } from '@/mixins/debounce'; @@ -135,15 +131,13 @@ export default defineComponent({ ExecutionsUsage, MainSidebarSourceControl, }, - mixins: [genericHelpers, workflowHelpers, workflowRun, userHelpers, debounceHelper], + mixins: [userHelpers, debounceHelper], setup(props, ctx) { const externalHooks = useExternalHooks(); return { externalHooks, ...useMessage(), - // eslint-disable-next-line @typescript-eslint/no-misused-promises - ...workflowRun.setup?.(props, ctx), }; }, data() { @@ -418,31 +412,31 @@ export default defineComponent({ async handleSelect(key: string) { switch (key) { case 'workflows': { - if (this.$router.currentRoute.name !== VIEWS.WORKFLOWS) { + if (this.$router.currentRoute.value.name !== VIEWS.WORKFLOWS) { this.goToRoute({ name: VIEWS.WORKFLOWS }); } break; } case 'templates': { - if (this.$router.currentRoute.name !== VIEWS.TEMPLATES) { + if (this.$router.currentRoute.value.name !== VIEWS.TEMPLATES) { this.goToRoute({ name: VIEWS.TEMPLATES }); } break; } case 'credentials': { - if (this.$router.currentRoute.name !== VIEWS.CREDENTIALS) { + if (this.$router.currentRoute.value.name !== VIEWS.CREDENTIALS) { this.goToRoute({ name: VIEWS.CREDENTIALS }); } break; } case 'variables': { - if (this.$router.currentRoute.name !== VIEWS.VARIABLES) { + if (this.$router.currentRoute.value.name !== VIEWS.VARIABLES) { this.goToRoute({ name: VIEWS.VARIABLES }); } break; } case 'executions': { - if (this.$router.currentRoute.name !== VIEWS.EXECUTIONS) { + if (this.$router.currentRoute.value.name !== VIEWS.EXECUTIONS) { this.goToRoute({ name: VIEWS.EXECUTIONS }); } break; @@ -451,7 +445,7 @@ export default defineComponent({ const defaultRoute = this.findFirstAccessibleSettingsRoute(); if (defaultRoute) { const route = this.$router.resolve({ name: defaultRoute }); - if (this.$router.currentRoute.name !== defaultRoute) { + if (this.$router.currentRoute.value.name !== defaultRoute) { this.goToRoute(route.path); } } @@ -463,7 +457,7 @@ export default defineComponent({ break; } case 'cloud-admin': { - this.cloudPlanStore.redirectToDashboard(); + void this.cloudPlanStore.redirectToDashboard(); break; } case 'quickstart': @@ -494,7 +488,7 @@ export default defineComponent({ let defaultSettingsRoute = null; for (const route of settingsRoutes) { - if (this.canUserAccessRouteByName(route)) { + if (this.canUserAccessRouteByName(route.toString())) { defaultSettingsRoute = route; break; } diff --git a/packages/editor-ui/src/components/NodeCredentials.vue b/packages/editor-ui/src/components/NodeCredentials.vue index 03704239da..65c9555e4a 100644 --- a/packages/editor-ui/src/components/NodeCredentials.vue +++ b/packages/editor-ui/src/components/NodeCredentials.vue @@ -15,7 +15,7 @@ color="text-dark" data-test-id="credentials-label" > -
+
import { defineComponent } from 'vue'; import NodeIcon from '@/components/NodeIcon.vue'; -import { genericHelpers } from '@/mixins/genericHelpers'; import type { ITemplatesNode } from '@/Interface'; import { filterTemplateNodes } from '@/utils/nodeTypesUtils'; @@ -24,7 +23,6 @@ export default defineComponent({ components: { NodeIcon, }, - mixins: [genericHelpers], props: { nodes: { type: Array, diff --git a/packages/editor-ui/src/components/OutputPanel.vue b/packages/editor-ui/src/components/OutputPanel.vue index 33c8faaba9..61fcd57677 100644 --- a/packages/editor-ui/src/components/OutputPanel.vue +++ b/packages/editor-ui/src/components/OutputPanel.vue @@ -1,5 +1,6 @@