+
-
This is a card.
+
This is a card.
@@ -13,12 +13,12 @@ exports[`components > N8nCard > should render correctly 1`] = `
`;
exports[`components > N8nCard > should render correctly with header and footer 1`] = `
-"
+"
-
"
diff --git a/packages/design-system/src/components/N8nInfoTip/__tests__/__snapshots__/InfoTip.spec.ts.snap b/packages/design-system/src/components/N8nInfoTip/__tests__/__snapshots__/InfoTip.spec.ts.snap
index 1bd09e20c7..5cf5e78f89 100644
--- a/packages/design-system/src/components/N8nInfoTip/__tests__/__snapshots__/InfoTip.spec.ts.snap
+++ b/packages/design-system/src/components/N8nInfoTip/__tests__/__snapshots__/InfoTip.spec.ts.snap
@@ -1,9 +1,9 @@
// Vitest Snapshot v1
-exports[`N8nInfoTip > should render correctly as note 1`] = `"
"`;
+exports[`N8nInfoTip > should render correctly as note 1`] = `"
"`;
exports[`N8nInfoTip > should render correctly as tooltip 1`] = `
"
"
`;
diff --git a/packages/design-system/src/components/N8nLink/Link.vue b/packages/design-system/src/components/N8nLink/Link.vue
index b34caa1213..0bbb693a25 100644
--- a/packages/design-system/src/components/N8nLink/Link.vue
+++ b/packages/design-system/src/components/N8nLink/Link.vue
@@ -107,6 +107,11 @@ export default Vue.extend({
text-decoration: underline;
}
+.text-underline {
+ composes: text;
+ text-decoration: underline;
+}
+
.danger-underline {
composes: danger;
text-decoration: underline;
diff --git a/packages/design-system/src/components/N8nMenu/Menu.vue b/packages/design-system/src/components/N8nMenu/Menu.vue
index ac4a694b13..816d3c0c57 100644
--- a/packages/design-system/src/components/N8nMenu/Menu.vue
+++ b/packages/design-system/src/components/N8nMenu/Menu.vue
@@ -73,7 +73,7 @@ export default Vue.extend({
},
data() {
return {
- activeTab: '',
+ activeTab: this.value,
};
},
props: {
@@ -101,6 +101,10 @@ export default Vue.extend({
items: {
type: Array as PropType
,
},
+ value: {
+ type: String,
+ default: '',
+ },
},
mounted() {
if (this.mode === 'router') {
@@ -112,6 +116,8 @@ export default Vue.extend({
} else {
this.activeTab = this.items.length > 0 ? this.items[0].id : '';
}
+
+ this.$emit('input', this.activeTab);
},
computed: {
upperMenuItems(): IMenuItem[] {
@@ -127,6 +133,12 @@ export default Vue.extend({
this.activeTab = option;
}
this.$emit('select', option);
+ this.$emit('input', this.activeTab);
+ },
+ },
+ watch: {
+ value(value: string) {
+ this.activeTab = value;
},
},
});
@@ -148,7 +160,7 @@ export default Vue.extend({
& > div > :global(.el-menu) {
background: none;
- padding: 12px;
+ padding: var(--menu-padding, 12px);
}
}
diff --git a/packages/design-system/src/components/N8nTag/Tag.vue b/packages/design-system/src/components/N8nTag/Tag.vue
index 2b0e0a70fb..514abc3352 100644
--- a/packages/design-system/src/components/N8nTag/Tag.vue
+++ b/packages/design-system/src/components/N8nTag/Tag.vue
@@ -20,10 +20,16 @@ export default Vue.extend({
diff --git a/packages/design-system/src/components/N8nTags/Tags.stories.js b/packages/design-system/src/components/N8nTags/Tags.stories.js
index 5b3370f349..0983464ca6 100644
--- a/packages/design-system/src/components/N8nTags/Tags.stories.js
+++ b/packages/design-system/src/components/N8nTags/Tags.stories.js
@@ -33,3 +33,31 @@ Tags.args = {
},
],
};
+
+
+export const Truncated = Template.bind({});
+Truncated.args = {
+ truncate: true,
+ tags: [
+ {
+ id: 1,
+ name: 'very long tag name',
+ },
+ {
+ id: 2,
+ name: 'tag1',
+ },
+ {
+ id: 3,
+ name: 'tag2 yo',
+ },
+ {
+ id: 4,
+ name: 'tag3',
+ },
+ {
+ id: 5,
+ name: 'tag4',
+ },
+ ],
+};
diff --git a/packages/design-system/src/components/N8nTags/Tags.vue b/packages/design-system/src/components/N8nTags/Tags.vue
index 52a3b304cc..a047472a2b 100644
--- a/packages/design-system/src/components/N8nTags/Tags.vue
+++ b/packages/design-system/src/components/N8nTags/Tags.vue
@@ -1,21 +1,65 @@
-
+
+
+ {{ t('tags.showMore', hiddenTagsLength) }}
+
+
+
diff --git a/packages/editor-ui/src/components/CollectionsCarousel.vue b/packages/editor-ui/src/components/CollectionsCarousel.vue
index 9066120013..e48d4fdd4e 100644
--- a/packages/editor-ui/src/components/CollectionsCarousel.vue
+++ b/packages/editor-ui/src/components/CollectionsCarousel.vue
@@ -21,7 +21,7 @@
-
+
+
diff --git a/packages/editor-ui/src/components/WorkflowCard.vue b/packages/editor-ui/src/components/WorkflowCard.vue
index 12c1c0cee5..4af6ba0336 100644
--- a/packages/editor-ui/src/components/WorkflowCard.vue
+++ b/packages/editor-ui/src/components/WorkflowCard.vue
@@ -1,66 +1,240 @@
-
-
-
-
-
-
-
+
+
+ {{ data.name }}
+
+
+
+
+ {{$locale.baseText('workflows.item.updated')}} |
+ {{$locale.baseText('workflows.item.created')}} {{ formattedCreatedAtDate }}
+
+
+
+
+
+
+
+
+
+ {{$locale.baseText('workflows.item.owner')}}
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/editor-ui/src/components/WorkflowOpen.vue b/packages/editor-ui/src/components/WorkflowOpen.vue
deleted file mode 100644
index 1a67b904f6..0000000000
--- a/packages/editor-ui/src/components/WorkflowOpen.vue
+++ /dev/null
@@ -1,333 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- {{scope.row.name}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/editor-ui/src/components/forms/ResourceFiltersDropdown.vue b/packages/editor-ui/src/components/forms/ResourceFiltersDropdown.vue
new file mode 100644
index 0000000000..695b3ba677
--- /dev/null
+++ b/packages/editor-ui/src/components/forms/ResourceFiltersDropdown.vue
@@ -0,0 +1,173 @@
+
+
+
+
+
+ {{ filtersLength }}
+
+ {{ $locale.baseText('forms.resourceFiltersDropdown.filters') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $locale.baseText('forms.resourceFiltersDropdown.reset') }}
+
+
+
+
+
+
+
+
+
diff --git a/packages/editor-ui/src/components/forms/ResourceOwnershipSelect.ee.vue b/packages/editor-ui/src/components/forms/ResourceOwnershipSelect.ee.vue
new file mode 100644
index 0000000000..67bbe032ba
--- /dev/null
+++ b/packages/editor-ui/src/components/forms/ResourceOwnershipSelect.ee.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
diff --git a/packages/editor-ui/src/components/layouts/ResourcesListLayout.vue b/packages/editor-ui/src/components/layouts/ResourcesListLayout.vue
new file mode 100644
index 0000000000..4742e00996
--- /dev/null
+++ b/packages/editor-ui/src/components/layouts/ResourcesListLayout.vue
@@ -0,0 +1,408 @@
+
+
+
+
+
+ {{ $locale.baseText(`${resourceKey}.heading`) }}
+
+
+
+
+
+ {{ $locale.baseText(`${resourceKey}.add`) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $locale.baseText(`${resourceKey}.filters.active`) }}
+
+ {{ $locale.baseText(`${resourceKey}.filters.active.reset`) }}
+
+
+
+
+
+
+
+ {{ $locale.baseText(`${resourceKey}.noResults`) }}
+
+
+ ({{ $locale.baseText(`${resourceKey}.noResults.switchToShared.preamble`) }}
+ {{$locale.baseText(`${resourceKey}.noResults.switchToShared.link`) }})
+
+
+ ({{ $locale.baseText(`${resourceKey}.noResults.withSearch.switchToShared.preamble`) }}
+ {{$locale.baseText(`${resourceKey}.noResults.withSearch.switchToShared.link`) }})
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/editor-ui/src/components/mixins/workflowActivate.ts b/packages/editor-ui/src/components/mixins/workflowActivate.ts
index dcf92dc10f..783be2a84f 100644
--- a/packages/editor-ui/src/components/mixins/workflowActivate.ts
+++ b/packages/editor-ui/src/components/mixins/workflowActivate.ts
@@ -35,7 +35,6 @@ export const workflowActivate = mixins(
}
currWorkflowId = this.$store.getters.workflowId as string;
}
-
const isCurrentWorkflow = currWorkflowId === this.$store.getters['workflowId'];
const activeWorkflows = this.$store.getters.getActiveWorkflows;
diff --git a/packages/editor-ui/src/components/mixins/workflowHelpers.ts b/packages/editor-ui/src/components/mixins/workflowHelpers.ts
index 7e8f308807..74210ae741 100644
--- a/packages/editor-ui/src/components/mixins/workflowHelpers.ts
+++ b/packages/editor-ui/src/components/mixins/workflowHelpers.ts
@@ -730,11 +730,11 @@ export const workflowHelpers = mixins(
}
},
- async saveAsNewWorkflow ({name, tags, resetWebhookUrls, resetNodeIds, openInNewWindow}: {name?: string, tags?: string[], resetWebhookUrls?: boolean, openInNewWindow?: boolean, resetNodeIds?: boolean} = {}, redirect = true): Promise {
+ async saveAsNewWorkflow ({ name, tags, resetWebhookUrls, resetNodeIds, openInNewWindow, data }: {name?: string, tags?: string[], resetWebhookUrls?: boolean, openInNewWindow?: boolean, resetNodeIds?: boolean, data?: IWorkflowDataUpdate} = {}, redirect = true): Promise {
try {
this.$store.commit('addActiveAction', 'workflowSaving');
- const workflowDataRequest: IWorkflowDataUpdate = await this.getWorkflowDataToSave();
+ const workflowDataRequest: IWorkflowDataUpdate = data || await this.getWorkflowDataToSave();
// make sure that the new ones are not active
workflowDataRequest.active = false;
const changedNodes = {} as IDataObject;
@@ -765,6 +765,9 @@ export const workflowHelpers = mixins(
workflowDataRequest.tags = tags;
}
const workflowData = await this.restApi().createNewWorkflow(workflowDataRequest);
+
+ this.$store.commit('addWorkflow', workflowData);
+
if (openInNewWindow) {
const routeData = this.$router.resolve({name: VIEWS.WORKFLOW, params: {name: workflowData.id}});
window.open(routeData.href, '_blank');
diff --git a/packages/editor-ui/src/constants.ts b/packages/editor-ui/src/constants.ts
index d9a6390c7e..77ece21da3 100644
--- a/packages/editor-ui/src/constants.ts
+++ b/packages/editor-ui/src/constants.ts
@@ -30,7 +30,6 @@ export const DELETE_USER_MODAL_KEY = 'deleteUser';
export const INVITE_USER_MODAL_KEY = 'inviteUser';
export const DUPLICATE_MODAL_KEY = 'duplicate';
export const TAGS_MANAGER_MODAL_KEY = 'tagsManager';
-export const WORKFLOW_OPEN_MODAL_KEY = 'workflowOpen';
export const VERSIONS_MODAL_KEY = 'versions';
export const WORKFLOW_SETTINGS_MODAL_KEY = 'settings';
export const PERSONALIZATION_MODAL_KEY = 'personalization';
diff --git a/packages/editor-ui/src/modules/ui.ts b/packages/editor-ui/src/modules/ui.ts
index aec5b5e05f..3b182708cd 100644
--- a/packages/editor-ui/src/modules/ui.ts
+++ b/packages/editor-ui/src/modules/ui.ts
@@ -17,7 +17,6 @@ import {
VALUE_SURVEY_MODAL_KEY,
VERSIONS_MODAL_KEY,
WORKFLOW_ACTIVE_MODAL_KEY,
- WORKFLOW_OPEN_MODAL_KEY,
WORKFLOW_SETTINGS_MODAL_KEY,
VIEWS,
ONBOARDING_CALL_SIGNUP_MODAL_KEY,
@@ -77,9 +76,6 @@ const module: Module = {
[TAGS_MANAGER_MODAL_KEY]: {
open: false,
},
- [WORKFLOW_OPEN_MODAL_KEY]: {
- open: false,
- },
[VALUE_SURVEY_MODAL_KEY]: {
open: false,
},
@@ -213,6 +209,9 @@ const module: Module = {
getModalMode: (state: IUiState) => {
return (name: string) => state.modals[name].mode;
},
+ getModalData: (state: IUiState) => {
+ return (name: string) => state.modals[name].data;
+ },
sidebarMenuCollapsed: (state: IUiState): boolean => state.sidebarMenuCollapsed,
ndvSessionId: (state: IUiState): string => state.ndv.sessionId,
getPanelDisplayMode: (state: IUiState) => {
@@ -276,6 +275,11 @@ const module: Module = {
const { name, id } = params;
Vue.set(state.modals[name], 'activeId', id);
},
+ setModalData: (state: IUiState, params: { name: string, data: Record }) => {
+ const { name, data } = params;
+
+ Vue.set(state.modals[name], 'data', data);
+ },
setCurlCommand: (state: IUiState, params: {name: string, command: string}) => {
const { name, command } = params;
Vue.set(state.modals[name], 'curlCommand', command);
@@ -379,6 +383,10 @@ const module: Module = {
openModal: async (context: ActionContext, modalKey: string) => {
context.commit('openModal', modalKey);
},
+ openModalWithData: async (context: ActionContext, payload: { name: string, data: Record }) => {
+ context.commit('setModalData', payload);
+ context.commit('openModal', payload.name);
+ },
openDeleteUserModal: async (context: ActionContext, { id }: {id: string}) => {
context.commit('setActiveId', { name: DELETE_USER_MODAL_KEY, id });
context.commit('openModal', DELETE_USER_MODAL_KEY);
diff --git a/packages/editor-ui/src/modules/workflows.ts b/packages/editor-ui/src/modules/workflows.ts
index 64b69481bb..c464ee195d 100644
--- a/packages/editor-ui/src/modules/workflows.ts
+++ b/packages/editor-ui/src/modules/workflows.ts
@@ -27,9 +27,7 @@ const module: Module = {
return workflowData;
},
- getDuplicateCurrentWorkflowName: async (context: ActionContext): Promise => {
- const currentWorkflowName = context.rootGetters.workflowName;
-
+ getDuplicateCurrentWorkflowName: async (context: ActionContext, currentWorkflowName: string): Promise => {
if (currentWorkflowName && (currentWorkflowName.length + DUPLICATE_POSTFFIX.length) >= MAX_WORKFLOW_NAME_LENGTH) {
return currentWorkflowName;
}
diff --git a/packages/editor-ui/src/permissions.ts b/packages/editor-ui/src/permissions.ts
index 261729ffdc..8048e9af7f 100644
--- a/packages/editor-ui/src/permissions.ts
+++ b/packages/editor-ui/src/permissions.ts
@@ -4,7 +4,7 @@
* @usage getCredentialPermissions(user, credential).isOwner;
*/
-import {IUser, ICredentialsResponse, IRootState} from "@/Interface";
+import {IUser, ICredentialsResponse, IRootState, IWorkflowDb} from "@/Interface";
import {Store} from "vuex";
import {EnterpriseEditionFeature} from "@/constants";
@@ -69,3 +69,22 @@ export const getCredentialPermissions = (user: IUser, credential: ICredentialsRe
return parsePermissionsTable(user, table);
};
+
+export const getWorkflowPermissions = (user: IUser, workflow: IWorkflowDb, store: Store) => {
+ const table: IPermissionsTable = [
+ // { name: UserRole.ResourceOwner, test: () => !!(workflow && workflow.ownedBy && workflow.ownedBy.id === user.id) || !store.getters['settings/isEnterpriseFeatureEnabled'](EnterpriseEditionFeature.Sharing) },
+ { name: UserRole.ResourceOwner, test: () => true },
+ // { name: UserRole.ResourceReader, test: () => !!(workflow && workflow.sharedWith && workflow.sharedWith.find((sharee) => sharee.id === user.id)) },
+ { name: UserRole.ResourceReader, test: () => true },
+ { name: 'read', test: [UserRole.ResourceOwner, UserRole.InstanceOwner, UserRole.ResourceReader] },
+ { name: 'save', test: [UserRole.ResourceOwner, UserRole.InstanceOwner] },
+ { name: 'updateName', test: [UserRole.ResourceOwner, UserRole.InstanceOwner] },
+ { name: 'updateConnection', test: [UserRole.ResourceOwner] },
+ { name: 'updateSharing', test: [UserRole.ResourceOwner] },
+ { name: 'updateNodeAccess', test: [UserRole.ResourceOwner] },
+ { name: 'delete', test: [UserRole.ResourceOwner, UserRole.InstanceOwner] },
+ { name: 'use', test: [UserRole.ResourceOwner, UserRole.ResourceReader] },
+ ];
+
+ return parsePermissionsTable(user, table);
+};
diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json
index 02d2ac9eb4..eb51f1bbfb 100644
--- a/packages/editor-ui/src/plugins/i18n/locales/en.json
+++ b/packages/editor-ui/src/plugins/i18n/locales/en.json
@@ -325,20 +325,15 @@
"credentials.empty.heading.userNotSetup": "Set up a credential",
"credentials.empty.description": "Credentials let workflows interact with your apps and services",
"credentials.empty.button": "Add first credential",
- "credentials.menu.myCredentials": "My credentials",
- "credentials.menu.allCredentials": "All credentials",
+ "credentials.menu.my": "My credentials",
+ "credentials.menu.all": "All credentials",
"credentials.item.open": "Open",
"credentials.item.delete": "Delete",
"credentials.item.updated": "Last updated",
"credentials.item.created": "Created",
"credentials.item.owner": "Owner",
"credentials.search.placeholder": "Search credentials...",
- "credentials.filters": "Filters",
"credentials.filters.type": "Type",
- "credentials.filters.ownedBy": "Owned by",
- "credentials.filters.sharedWith": "Shared with",
- "credentials.filters.apply": "Apply filters",
- "credentials.filters.reset": "Reset all",
"credentials.filters.active": "Some credentials may be hidden since filters are applied.",
"credentials.filters.active.reset": "Remove filters",
"credentials.sort.lastUpdated": "Sort by last updated",
@@ -480,6 +475,10 @@
"forgotPassword.returnToSignIn": "Back to sign in",
"forgotPassword.sendingEmailError": "Problem sending email",
"forgotPassword.smtpErrorContactAdministrator": "Please contact your administrator (problem with your SMTP setup)",
+ "forms.resourceFiltersDropdown.filters": "Filters",
+ "forms.resourceFiltersDropdown.ownedBy": "Owned by",
+ "forms.resourceFiltersDropdown.sharedWith": "Shared with",
+ "forms.resourceFiltersDropdown.reset": "Reset all",
"generic.oauth1Api": "OAuth1 API",
"generic.oauth2Api": "OAuth2 API",
"genericHelpers.loading": "Loading",
@@ -1197,6 +1196,8 @@
"workflowActivator.workflowIsActive": "Workflow is already active",
"workflowActivator.activateWorkflow": "Activate workflow",
"workflowActivator.deactivateWorkflow": "Deactivate workflow",
+ "workflowActivator.active": "Active",
+ "workflowActivator.inactive": "Inactive",
"workflowActivator.showError.title": "Workflow could not be {newStateName}",
"workflowActivator.showMessage.activeChangedNodesIssuesExistTrue.message": "Please resolve outstanding issues before you activate it",
"workflowActivator.showMessage.activeChangedNodesIssuesExistTrue.title": "Problem activating workflow",
@@ -1280,6 +1281,39 @@
"workflowSettings.timeoutAfter": "Timeout After",
"workflowSettings.timeoutWorkflow": "Timeout Workflow",
"workflowSettings.timezone": "Timezone",
+ "workflows.heading": "Workflows",
+ "workflows.add": "Add Workflow",
+ "workflows.menu.my": "My workflows",
+ "workflows.menu.all": "All workflows",
+ "workflows.item.open": "Open",
+ "workflows.item.duplicate": "Duplicate",
+ "workflows.item.delete": "Delete",
+ "workflows.item.updated": "Last updated",
+ "workflows.item.created": "Created",
+ "workflows.item.owner": "Owner",
+ "workflows.search.placeholder": "Search workflows...",
+ "workflows.filters": "Filters",
+ "workflows.filters.tags": "Tags",
+ "workflows.filters.ownedBy": "Owned by",
+ "workflows.filters.sharedWith": "Shared with",
+ "workflows.filters.apply": "Apply filters",
+ "workflows.filters.reset": "Reset all",
+ "workflows.filters.active": "Some workflows may be hidden since filters are applied.",
+ "workflows.filters.active.reset": "Remove filters",
+ "workflows.sort.lastUpdated": "Sort by last updated",
+ "workflows.sort.lastCreated": "Sort by last created",
+ "workflows.sort.nameAsc": "Sort by name (A-Z)",
+ "workflows.sort.nameDesc": "Sort by name (Z-A)",
+ "workflows.noResults": "No workflows found",
+ "workflows.noResults.withSearch.switchToShared.preamble": "some workflows may be",
+ "workflows.noResults.withSearch.switchToShared.link": "hidden",
+ "workflows.noResults.switchToShared.preamble": "but there are some",
+ "workflows.noResults.switchToShared.link": "shared with you",
+ "workflows.empty.heading": "👋 Welcome {name}!",
+ "workflows.empty.heading.userNotSetup": "👋 Welcome!",
+ "workflows.empty.description": "Create your first workflow",
+ "workflows.empty.startFromScratch": "Start from scratch",
+ "workflows.empty.browseTemplates": "Browse templates",
"importCurlModal.title": "Import cURL command",
"importCurlModal.input.label": "cURL Command",
"importCurlModal.input.placeholder": "Paste the cURL command here",
diff --git a/packages/editor-ui/src/router.ts b/packages/editor-ui/src/router.ts
index ca2944998a..477642698b 100644
--- a/packages/editor-ui/src/router.ts
+++ b/packages/editor-ui/src/router.ts
@@ -20,13 +20,13 @@ import TemplatesCollectionView from '@/views/TemplatesCollectionView.vue';
import TemplatesWorkflowView from '@/views/TemplatesWorkflowView.vue';
import TemplatesSearchView from '@/views/TemplatesSearchView.vue';
import CredentialsView from '@/views/CredentialsView.vue';
+import WorkflowsView from '@/views/WorkflowsView.vue';
import { Store } from 'vuex';
import { IPermissions, IRootState, IWorkflowsState } from './Interface';
import { LOGIN_STATUS, ROLE } from './modules/userHelpers';
import { RouteConfigSingleView } from 'vue-router/types/router';
import { VIEWS } from './constants';
import { store } from './store';
-import e from 'express';
Vue.use(Router);
@@ -69,7 +69,7 @@ const router = new Router({
name: VIEWS.HOMEPAGE,
meta: {
getRedirect(store: Store) {
- return { name: VIEWS.NEW_WORKFLOW };
+ return { name: VIEWS.WORKFLOWS };
},
permissions: {
allow: {
@@ -189,6 +189,21 @@ const router = new Router({
},
},
},
+ {
+ path: '/workflows',
+ name: VIEWS.WORKFLOWS,
+ components: {
+ default: WorkflowsView,
+ sidebar: MainSidebar,
+ },
+ meta: {
+ permissions: {
+ allow: {
+ loginStatus: [LOGIN_STATUS.LoggedIn],
+ },
+ },
+ },
+ },
{
path: '/workflow',
name: VIEWS.NEW_WORKFLOW,
diff --git a/packages/editor-ui/src/store.ts b/packages/editor-ui/src/store.ts
index ed9163cbaa..b18211592d 100644
--- a/packages/editor-ui/src/store.ts
+++ b/packages/editor-ui/src/store.ts
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import Vuex from 'vuex';
+import Vuex, {ActionContext} from 'vuex';
import {
PLACEHOLDER_EMPTY_WORKFLOW_ID,
@@ -32,6 +32,8 @@ import {
IWorkflowDb,
XYPosition,
IRestApiContext,
+ IWorkflowsState,
+ IWorkflowsMap,
} from './Interface';
import nodeTypes from './modules/nodeTypes';
@@ -48,6 +50,7 @@ import {dataPinningEventBus} from "@/event-bus/data-pinning-event-bus";
import communityNodes from './modules/communityNodes';
import nodeCreator from './modules/nodeCreator';
import { isJsonKeyObject } from './utils';
+import {getActiveWorkflows, getWorkflows} from "@/api/workflows";
import { getPairedItemsMapping } from './pairedItemUtils';
Vue.use(Vuex);
@@ -100,6 +103,7 @@ const state: IRootState = {
tags: [],
pinData: {},
},
+ workflowsById: {},
sidebarMenuItems: [],
instanceId: '',
nodeMetadata: {},
@@ -181,6 +185,25 @@ export const store = new Vuex.Store({
Vue.set(state, 'activeExecutions', newActiveExecutions);
},
+ // Workflows
+ setWorkflows: (state: IRootState, workflows: IWorkflowDb[]) => {
+ state.workflowsById = workflows.reduce((acc, workflow: IWorkflowDb) => {
+ if (workflow.id) {
+ acc[workflow.id] = workflow;
+ }
+
+ return acc;
+ }, {});
+ },
+ deleteWorkflow: (state: IRootState, id: string) => {
+ const { [id]: deletedWorkflow, ...workflows } = state.workflowsById;
+
+ state.workflowsById = workflows;
+ },
+ addWorkflow: (state: IRootState, workflow: IWorkflowDb) => {
+ Vue.set(state.workflowsById, workflow.id, workflow);
+ },
+
// Active Workflows
setActiveWorkflows(state, newActiveWorkflows: string[]) {
state.activeWorkflows = newActiveWorkflows;
@@ -191,12 +214,20 @@ export const store = new Vuex.Store({
if (index === -1) {
state.activeWorkflows.push(workflowId);
}
+
+ if (state.workflowsById[workflowId]) {
+ Vue.set(state.workflowsById[workflowId], 'active', true);
+ }
},
setWorkflowInactive(state, workflowId: string) {
const index = state.activeWorkflows.indexOf(workflowId);
if (index !== -1) {
state.activeWorkflows.splice(index, 1);
}
+
+ if (state.workflowsById[workflowId]) {
+ Vue.set(state.workflowsById[workflowId], 'active', false);
+ }
},
// Set state condition dirty or not
// ** Dirty: if current workflow state has been synchronized with database AKA has it been saved
@@ -831,6 +862,12 @@ export const store = new Vuex.Store({
return state.sessionId;
},
+ // Workflows
+ allWorkflows(state: IRootState): IWorkflowDb[] {
+ return Object.values(state.workflowsById)
+ .sort((a, b) => a.name.localeCompare(b.name));
+ },
+
// Active Workflows
getActiveWorkflows: (state): string[] => {
return state.activeWorkflows;
@@ -1011,4 +1048,18 @@ export const store = new Vuex.Store({
return state.sidebarMenuItems;
},
},
+ actions: {
+ fetchAllWorkflows: async (context: ActionContext): Promise => {
+ const workflows = await getWorkflows(context.rootGetters.getRestApiContext);
+ context.commit('setWorkflows', workflows);
+
+ return workflows;
+ },
+ fetchActiveWorkflows: async (context: ActionContext): Promise => {
+ const activeWorkflows = await getActiveWorkflows(context.rootGetters.getRestApiContext);
+ context.commit('setActiveWorkflows', activeWorkflows);
+
+ return activeWorkflows;
+ },
+ },
});
diff --git a/packages/editor-ui/src/views/CredentialsView.vue b/packages/editor-ui/src/views/CredentialsView.vue
index 258df9e900..c4d6e1f87d 100644
--- a/packages/editor-ui/src/views/CredentialsView.vue
+++ b/packages/editor-ui/src/views/CredentialsView.vue
@@ -1,229 +1,45 @@
-
-
-
-
- {{ $locale.baseText('credentials.heading') }}
-
-
-
-
-
- {{ $locale.baseText('credentials.add') }}
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ filtersLength }}
-
- {{ $locale.baseText('credentials.filters') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $locale.baseText('credentials.filters.reset') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $locale.baseText('credentials.filters.active') }}
-
- {{ $locale.baseText('credentials.filters.active.reset') }}
-
-
-
-
-
-
-
- {{ $locale.baseText('credentials.noResults') }}
-
-
- ({{ $locale.baseText('credentials.noResults.switchToShared.preamble') }}
- {{
- $locale.baseText('credentials.noResults.switchToShared.link')
- }})
-
-
- ({{ $locale.baseText('credentials.noResults.withSearch.switchToShared.preamble') }}
- {{
- $locale.baseText('credentials.noResults.withSearch.switchToShared.link')
- }})
-
-
-
-
-
-
+
+
+