feat: Add share button to workflows list (#4681)

* feat: Add share button to workflows list

* fix: take empty workflow into account when sharing
This commit is contained in:
Alex Grozav 2022-11-22 12:33:40 +02:00 committed by GitHub
parent b5b44d1b59
commit a356d7bdba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 7 deletions

View file

@ -241,7 +241,7 @@ export default mixins(workflowHelpers, titleChange).extend({
if (saved) await this.settingsStore.fetchPromptsData(); if (saved) await this.settingsStore.fetchPromptsData();
}, },
onShareButtonClick() { onShareButtonClick() {
this.uiStore.openModal(WORKFLOW_SHARE_MODAL_KEY); this.uiStore.openModalWithData({ name: WORKFLOW_SHARE_MODAL_KEY, data: { id: this.currentWorkflowId } });
}, },
onTagsEditEnable() { onTagsEditEnable() {
this.$data.appliedTagIds = this.currentWorkflowTagIds; this.$data.appliedTagIds = this.currentWorkflowTagIds;

View file

@ -83,7 +83,13 @@
</ModalRoot> </ModalRoot>
<ModalRoot :name="WORKFLOW_SHARE_MODAL_KEY"> <ModalRoot :name="WORKFLOW_SHARE_MODAL_KEY">
<WorkflowShareModal /> <template #default="{ modalName, active, data }">
<WorkflowShareModal
:data="data"
:isActive="active"
:modalName="modalName"
/>
</template>
</ModalRoot> </ModalRoot>
<ModalRoot :name="ONBOARDING_CALL_SIGNUP_MODAL_KEY"> <ModalRoot :name="ONBOARDING_CALL_SIGNUP_MODAL_KEY">

View file

@ -59,7 +59,7 @@
<script lang="ts"> <script lang="ts">
import mixins from 'vue-typed-mixins'; import mixins from 'vue-typed-mixins';
import {IWorkflowDb, IUser, ITag} from "@/Interface"; import {IWorkflowDb, IUser, ITag} from "@/Interface";
import {DUPLICATE_MODAL_KEY, EnterpriseEditionFeature, VIEWS} from '@/constants'; import {DUPLICATE_MODAL_KEY, EnterpriseEditionFeature, VIEWS, WORKFLOW_SHARE_MODAL_KEY} from '@/constants';
import {showMessage} from "@/components/mixins/showMessage"; import {showMessage} from "@/components/mixins/showMessage";
import {getWorkflowPermissions, IPermissions} from "@/permissions"; import {getWorkflowPermissions, IPermissions} from "@/permissions";
import dateformat from "dateformat"; import dateformat from "dateformat";
@ -74,6 +74,7 @@ import { useWorkflowsStore } from '@/stores/workflows';
export const WORKFLOW_LIST_ITEM_ACTIONS = { export const WORKFLOW_LIST_ITEM_ACTIONS = {
OPEN: 'open', OPEN: 'open',
SHARE: 'share',
DUPLICATE: 'duplicate', DUPLICATE: 'duplicate',
DELETE: 'delete', DELETE: 'delete',
}; };
@ -131,6 +132,10 @@ export default mixins(
label: this.$locale.baseText('workflows.item.open'), label: this.$locale.baseText('workflows.item.open'),
value: WORKFLOW_LIST_ITEM_ACTIONS.OPEN, value: WORKFLOW_LIST_ITEM_ACTIONS.OPEN,
}, },
{
label: this.$locale.baseText('workflows.item.share'),
value: WORKFLOW_LIST_ITEM_ACTIONS.SHARE,
},
{ {
label: this.$locale.baseText('workflows.item.duplicate'), label: this.$locale.baseText('workflows.item.duplicate'),
value: WORKFLOW_LIST_ITEM_ACTIONS.DUPLICATE, value: WORKFLOW_LIST_ITEM_ACTIONS.DUPLICATE,
@ -183,6 +188,8 @@ export default mixins(
tags: (this.data.tags || []).map((tag: ITag) => tag.id), tags: (this.data.tags || []).map((tag: ITag) => tag.id),
}, },
}); });
} else if (action === WORKFLOW_LIST_ITEM_ACTIONS.SHARE) {
this.uiStore.openModalWithData({ name: WORKFLOW_SHARE_MODAL_KEY, data: { id: this.data.id } });
} else if (action === WORKFLOW_LIST_ITEM_ACTIONS.DELETE) { } else if (action === WORKFLOW_LIST_ITEM_ACTIONS.DELETE) {
const deleteConfirmed = await this.confirmMessage( const deleteConfirmed = await this.confirmMessage(
this.$locale.baseText( this.$locale.baseText(

View file

@ -120,14 +120,23 @@ export default mixins(
components: { components: {
Modal, Modal,
}, },
props: {
data: {
type: Object,
default: () => ({}),
},
},
data() { data() {
const workflowsStore = useWorkflowsStore(); const workflowsStore = useWorkflowsStore();
const workflow = this.data.id === PLACEHOLDER_EMPTY_WORKFLOW_ID
? workflowsStore.workflow
: workflowsStore.workflowsById[this.data.id];
return { return {
WORKFLOW_SHARE_MODAL_KEY, WORKFLOW_SHARE_MODAL_KEY,
loading: false, loading: false,
modalBus: new Vue(), modalBus: new Vue(),
sharedWith: [...(workflowsStore.workflow.sharedWith || [])] as Array<Partial<IUser>>, sharedWith: [...(workflow.sharedWith || [])] as Array<Partial<IUser>>,
EnterpriseEditionFeature, EnterpriseEditionFeature,
}; };
}, },
@ -150,7 +159,9 @@ export default mixins(
] as Array<Partial<IUser>>).concat(this.sharedWith || []); ] as Array<Partial<IUser>>).concat(this.sharedWith || []);
}, },
workflow(): IWorkflowDb { workflow(): IWorkflowDb {
return this.workflowsStore.workflow; return this.data.id === PLACEHOLDER_EMPTY_WORKFLOW_ID
? this.workflowsStore.workflow
: this.workflowsStore.workflowsById[this.data.id];
}, },
currentUser(): IUser | null { currentUser(): IUser | null {
return this.usersStore.currentUser; return this.usersStore.currentUser;
@ -221,7 +232,7 @@ export default mixins(
} }
if (confirm) { if (confirm) {
this.sharedWith = this.sharedWith.filter((sharee: IUser) => { this.sharedWith = this.sharedWith.filter((sharee: Partial<IUser>) => {
return sharee.id !== user.id; return sharee.id !== user.id;
}); });
} }

View file

@ -4,7 +4,7 @@ import {
PLACEHOLDER_EMPTY_WORKFLOW_ID, PLACEHOLDER_EMPTY_WORKFLOW_ID,
START_NODE_TYPE, START_NODE_TYPE,
WEBHOOK_NODE_TYPE, WEBHOOK_NODE_TYPE,
VIEWS, VIEWS, EnterpriseEditionFeature,
} from '@/constants'; } from '@/constants';
import { import {
@ -65,6 +65,8 @@ import { IWorkflowSettings } from 'n8n-workflow';
import { useNDVStore } from '@/stores/ndv'; import { useNDVStore } from '@/stores/ndv';
import { useTemplatesStore } from '@/stores/templates'; import { useTemplatesStore } from '@/stores/templates';
import { useNodeTypesStore } from '@/stores/nodeTypes'; import { useNodeTypesStore } from '@/stores/nodeTypes';
import useWorkflowsEEStore from "@/stores/workflows.ee";
import {useUsersStore} from "@/stores/users";
let cachedWorkflowKey: string | null = ''; let cachedWorkflowKey: string | null = '';
let cachedWorkflow: Workflow | null = null; let cachedWorkflow: Workflow | null = null;
@ -83,6 +85,8 @@ export const workflowHelpers = mixins(
useRootStore, useRootStore,
useTemplatesStore, useTemplatesStore,
useWorkflowsStore, useWorkflowsStore,
useWorkflowsEEStore,
useUsersStore,
useUIStore, useUIStore,
), ),
}, },
@ -796,6 +800,10 @@ export const workflowHelpers = mixins(
this.workflowsStore.addWorkflow(workflowData); this.workflowsStore.addWorkflow(workflowData);
this.workflowsStore.setWorkflowHash(workflowData.hash); this.workflowsStore.setWorkflowHash(workflowData.hash);
if (this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.WorkflowSharing) && this.usersStore.currentUser) {
this.workflowsEEStore.setWorkflowOwnedBy({ workflowId: workflowData.id, ownedBy: this.usersStore.currentUser });
}
if (openInNewWindow) { if (openInNewWindow) {
const routeData = this.$router.resolve({name: VIEWS.WORKFLOW, params: {name: workflowData.id}}); const routeData = this.$router.resolve({name: VIEWS.WORKFLOW, params: {name: workflowData.id}});
window.open(routeData.href, '_blank'); window.open(routeData.href, '_blank');

View file

@ -1342,6 +1342,7 @@
"workflows.menu.my": "My workflows", "workflows.menu.my": "My workflows",
"workflows.menu.all": "All workflows", "workflows.menu.all": "All workflows",
"workflows.item.open": "Open", "workflows.item.open": "Open",
"workflows.item.share": "Share...",
"workflows.item.duplicate": "Duplicate", "workflows.item.duplicate": "Duplicate",
"workflows.item.delete": "Delete", "workflows.item.delete": "Delete",
"workflows.item.updated": "Last updated", "workflows.item.updated": "Last updated",