mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-26 05:04:05 -08:00
feat: Add dynamic translations. Change how sharing unavailable is handled (no-changelog) (#4758)
* feat: Add dynamic translations. Change how sharing unavailable is handled (no-changelog) * fix: Add not-allowed cursor for disabled share button * fix: Remove fakedoor features from workflow details * fix: Remove fakedoor code from workflow share modal * fix: change dynamic translation to match shareModal title * chore: Removed unused import
This commit is contained in:
parent
86a4965e9a
commit
b1287ba8cb
|
@ -1022,6 +1022,10 @@ export interface IModalState {
|
||||||
httpNodeParameters?: string;
|
httpNodeParameters?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NestedRecord<T> {
|
||||||
|
[key: string]: T | NestedRecord<T>;
|
||||||
|
}
|
||||||
|
|
||||||
export type IRunDataDisplayMode = 'table' | 'json' | 'binary';
|
export type IRunDataDisplayMode = 'table' | 'json' | 'binary';
|
||||||
export type nodePanelType = 'input' | 'output';
|
export type nodePanelType = 'input' | 'output';
|
||||||
|
|
||||||
|
@ -1095,6 +1099,7 @@ export interface UIState {
|
||||||
currentView: string;
|
currentView: string;
|
||||||
mainPanelPosition: number;
|
mainPanelPosition: number;
|
||||||
fakeDoorFeatures: IFakeDoor[];
|
fakeDoorFeatures: IFakeDoor[];
|
||||||
|
dynamicTranslations: NestedRecord<string>;
|
||||||
draggable: {
|
draggable: {
|
||||||
isDragging: boolean;
|
isDragging: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
|
|
|
@ -75,6 +75,25 @@
|
||||||
>
|
>
|
||||||
{{ $locale.baseText('workflowDetails.share') }}
|
{{ $locale.baseText('workflowDetails.share') }}
|
||||||
</n8n-button>
|
</n8n-button>
|
||||||
|
<template #fallback>
|
||||||
|
<n8n-tooltip>
|
||||||
|
<n8n-button
|
||||||
|
type="secondary"
|
||||||
|
:class="['mr-2xs', $style.disabledShareButton]"
|
||||||
|
>
|
||||||
|
{{ $locale.baseText('workflowDetails.share') }}
|
||||||
|
</n8n-button>
|
||||||
|
<template #content>
|
||||||
|
<i18n :path="dynamicTranslations.workflows.sharing.unavailable.description" tag="span">
|
||||||
|
<template #action>
|
||||||
|
<a :href="dynamicTranslations.workflows.sharing.unavailable.linkURL" target="_blank">
|
||||||
|
{{ $locale.baseText(dynamicTranslations.workflows.sharing.unavailable.action) }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</i18n>
|
||||||
|
</template>
|
||||||
|
</n8n-tooltip>
|
||||||
|
</template>
|
||||||
</enterprise-edition>
|
</enterprise-edition>
|
||||||
<SaveButton
|
<SaveButton
|
||||||
type="primary"
|
type="primary"
|
||||||
|
@ -114,7 +133,7 @@ import SaveButton from "@/components/SaveButton.vue";
|
||||||
import TagsDropdown from "@/components/TagsDropdown.vue";
|
import TagsDropdown from "@/components/TagsDropdown.vue";
|
||||||
import InlineTextEdit from "@/components/InlineTextEdit.vue";
|
import InlineTextEdit from "@/components/InlineTextEdit.vue";
|
||||||
import BreakpointsObserver from "@/components/BreakpointsObserver.vue";
|
import BreakpointsObserver from "@/components/BreakpointsObserver.vue";
|
||||||
import {IWorkflowDataUpdate, IWorkflowDb, IWorkflowToShare} from "@/Interface";
|
import {IWorkflowDataUpdate, IWorkflowDb, IWorkflowToShare, NestedRecord} from "@/Interface";
|
||||||
|
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import { titleChange } from "@/mixins/titleChange";
|
import { titleChange } from "@/mixins/titleChange";
|
||||||
|
@ -169,6 +188,9 @@ export default mixins(workflowHelpers, titleChange).extend({
|
||||||
useWorkflowsStore,
|
useWorkflowsStore,
|
||||||
useUsersStore,
|
useUsersStore,
|
||||||
),
|
),
|
||||||
|
dynamicTranslations(): NestedRecord<string> {
|
||||||
|
return this.uiStore.dynamicTranslations;
|
||||||
|
},
|
||||||
isWorkflowActive(): boolean {
|
isWorkflowActive(): boolean {
|
||||||
return this.workflowsStore.isWorkflowActive;
|
return this.workflowsStore.isWorkflowActive;
|
||||||
},
|
},
|
||||||
|
@ -548,4 +570,8 @@ $--header-spacing: 20px;
|
||||||
.deleteItem {
|
.deleteItem {
|
||||||
color: var(--color-danger);
|
color: var(--color-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disabledShareButton {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Modal
|
<Modal
|
||||||
width="460px"
|
width="460px"
|
||||||
:title="$locale.baseText(fakeDoor.actionBoxTitle, { interpolate: { name: workflow.name } })"
|
:title="$locale.baseText(dynamicTranslations.workflows.shareModal.title, { interpolate: { name: workflow.name } })"
|
||||||
:eventBus="modalBus"
|
:eventBus="modalBus"
|
||||||
:name="WORKFLOW_SHARE_MODAL_KEY"
|
:name="WORKFLOW_SHARE_MODAL_KEY"
|
||||||
:center="true"
|
:center="true"
|
||||||
|
@ -52,7 +52,9 @@
|
||||||
</n8n-users-list>
|
</n8n-users-list>
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
<n8n-text>
|
<n8n-text>
|
||||||
{{ $locale.baseText(fakeDoor.actionBoxDescription) }}
|
<i18n :path="dynamicTranslations.workflows.sharing.unavailable.description" tag="span">
|
||||||
|
<template #action />
|
||||||
|
</i18n>
|
||||||
</n8n-text>
|
</n8n-text>
|
||||||
</template>
|
</template>
|
||||||
</enterprise-edition>
|
</enterprise-edition>
|
||||||
|
@ -80,12 +82,12 @@
|
||||||
</n8n-button>
|
</n8n-button>
|
||||||
|
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
<n8n-link :to="fakeDoor.linkURL">
|
<n8n-link :to="dynamicTranslations.workflows.sharing.unavailable.linkURL">
|
||||||
<n8n-button
|
<n8n-button
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
size="medium"
|
size="medium"
|
||||||
>
|
>
|
||||||
{{ $locale.baseText(fakeDoor.actionBoxButtonLabel) }}
|
{{ $locale.baseText(dynamicTranslations.workflows.sharing.unavailable.button) }}
|
||||||
</n8n-button>
|
</n8n-button>
|
||||||
</n8n-link>
|
</n8n-link>
|
||||||
</template>
|
</template>
|
||||||
|
@ -99,11 +101,10 @@ import Vue from 'vue';
|
||||||
import Modal from './Modal.vue';
|
import Modal from './Modal.vue';
|
||||||
import {
|
import {
|
||||||
EnterpriseEditionFeature,
|
EnterpriseEditionFeature,
|
||||||
FAKE_DOOR_FEATURES,
|
|
||||||
PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
||||||
WORKFLOW_SHARE_MODAL_KEY,
|
WORKFLOW_SHARE_MODAL_KEY,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import {IFakeDoor, IUser, IWorkflowDb} from "@/Interface";
|
import {IUser, IWorkflowDb, NestedRecord} from "@/Interface";
|
||||||
import { getWorkflowPermissions, IPermissions } from "@/permissions";
|
import { getWorkflowPermissions, IPermissions } from "@/permissions";
|
||||||
import mixins from "vue-typed-mixins";
|
import mixins from "vue-typed-mixins";
|
||||||
import {showMessage} from "@/mixins/showMessage";
|
import {showMessage} from "@/mixins/showMessage";
|
||||||
|
@ -174,8 +175,8 @@ export default mixins(
|
||||||
isSharingAvailable(): boolean {
|
isSharingAvailable(): boolean {
|
||||||
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.WorkflowSharing) === true;
|
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.WorkflowSharing) === true;
|
||||||
},
|
},
|
||||||
fakeDoor(): IFakeDoor | undefined {
|
dynamicTranslations(): NestedRecord<string> {
|
||||||
return this.uiStore.getFakeDoorById(FAKE_DOOR_FEATURES.WORKFLOWS_SHARING);
|
return this.uiStore.dynamicTranslations;
|
||||||
},
|
},
|
||||||
isDirty(): boolean {
|
isDirty(): boolean {
|
||||||
const previousSharedWith = this.workflow.sharedWith || [];
|
const previousSharedWith = this.workflow.sharedWith || [];
|
||||||
|
|
|
@ -489,11 +489,6 @@
|
||||||
"fakeDoor.credentialEdit.sharing.actionBox.title.cloud.upgrade": "Upgrade to add users",
|
"fakeDoor.credentialEdit.sharing.actionBox.title.cloud.upgrade": "Upgrade to add users",
|
||||||
"fakeDoor.credentialEdit.sharing.actionBox.description.cloud.upgrade": "Power and Pro plan users can create multiple user accounts and share credentials. (Sharing workflows is coming soon)",
|
"fakeDoor.credentialEdit.sharing.actionBox.description.cloud.upgrade": "Power and Pro plan users can create multiple user accounts and share credentials. (Sharing workflows is coming soon)",
|
||||||
"fakeDoor.credentialEdit.sharing.actionBox.button.cloud.upgrade": "Upgrade",
|
"fakeDoor.credentialEdit.sharing.actionBox.button.cloud.upgrade": "Upgrade",
|
||||||
"fakeDoor.workflowsSharing.title.cloud.upgrade": "Upgrade to add users",
|
|
||||||
"fakeDoor.workflowsSharing.description": "Sharing workflows with others is currently available only on n8n cloud, our hosted offering.",
|
|
||||||
"fakeDoor.workflowsSharing.description.cloud.upgrade": "Power and Pro plan users can create multiple user accounts and share workflows.",
|
|
||||||
"fakeDoor.workflowsSharing.button": "Explore n8n cloud",
|
|
||||||
"fakeDoor.workflowsSharing.button.cloud.upgrade": "Upgrade",
|
|
||||||
"fakeDoor.settings.environments.name": "Environments",
|
"fakeDoor.settings.environments.name": "Environments",
|
||||||
"fakeDoor.settings.environments.infoText": "Environments allow you to use different settings and credentials in a workflow when you're building it vs when it's running in production",
|
"fakeDoor.settings.environments.infoText": "Environments allow you to use different settings and credentials in a workflow when you're building it vs when it's running in production",
|
||||||
"fakeDoor.settings.environments.actionBox.title": "We’re working on environments (as a paid feature)",
|
"fakeDoor.settings.environments.actionBox.title": "We’re working on environments (as a paid feature)",
|
||||||
|
@ -1404,5 +1399,14 @@
|
||||||
"importParameter.showError.invalidCurlCommand.message": "This command is in an unsupported format",
|
"importParameter.showError.invalidCurlCommand.message": "This command is in an unsupported format",
|
||||||
"importParameter.showError.invalidProtocol1.title": "Use the {node} node",
|
"importParameter.showError.invalidProtocol1.title": "Use the {node} node",
|
||||||
"importParameter.showError.invalidProtocol2.title": "Invalid Protocol",
|
"importParameter.showError.invalidProtocol2.title": "Invalid Protocol",
|
||||||
"importParameter.showError.invalidProtocol.message": "The HTTP node doesn’t support {protocol} requests"
|
"importParameter.showError.invalidProtocol.message": "The HTTP node doesn’t support {protocol} requests",
|
||||||
|
"dynamic.workflows.shareModal.title": "Share '{name}'",
|
||||||
|
"dynamic.workflows.shareModal.title.cloud.upgrade": "Upgrade to add users",
|
||||||
|
"dynamic.workflows.sharing.unavailable.description": "Sharing workflows with others is currently available only on n8n cloud, our hosted offering. {action}",
|
||||||
|
"dynamic.workflows.sharing.unavailable.description.cloud.upgrade": "Sharing is available for Team and Enterprise plans. {action} to unlock more features.",
|
||||||
|
"dynamic.workflows.sharing.unavailable.action": "Explore n8n cloud",
|
||||||
|
"dynamic.workflows.sharing.unavailable.action.cloud.upgrade": "Upgrade now",
|
||||||
|
"dynamic.workflows.sharing.unavailable.button": "Explore n8n cloud",
|
||||||
|
"dynamic.workflows.sharing.unavailable.button.cloud.upgrade": "Upgrade now",
|
||||||
|
"dynamic.workflows.sharing.unavailable.linkUrl": "https://n8n.cloud"
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,21 @@ export const useUIStore = defineStore(STORES.UI, {
|
||||||
uiLocations: ['workflowShareModal'],
|
uiLocations: ['workflowShareModal'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
dynamicTranslations: {
|
||||||
|
workflows: {
|
||||||
|
shareModal: {
|
||||||
|
title: 'dynamic.workflows.shareModal.title',
|
||||||
|
},
|
||||||
|
sharing: {
|
||||||
|
unavailable: {
|
||||||
|
description: 'dynamic.workflows.sharing.unavailable.description',
|
||||||
|
action: 'dynamic.workflows.sharing.unavailable.action',
|
||||||
|
button: 'dynamic.workflows.sharing.unavailable.button',
|
||||||
|
linkURL: 'https://n8n.cloud',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
draggable: {
|
draggable: {
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
type: '',
|
type: '',
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { STORES } from "@/constants";
|
import { STORES } from "@/constants";
|
||||||
import { IFakeDoor, INodeUi, IRootState } from "@/Interface";
|
import {IFakeDoor, INodeUi, IRootState, NestedRecord} from "@/Interface";
|
||||||
import { IMenuItem } from "n8n-design-system";
|
import { IMenuItem } from "n8n-design-system";
|
||||||
import { IWorkflowSettings } from "n8n-workflow";
|
import { IWorkflowSettings } from "n8n-workflow";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
@ -15,6 +15,9 @@ export const useWebhooksStore = defineStore(STORES.WEBHOOKS, {
|
||||||
globalRoleName(): string {
|
globalRoleName(): string {
|
||||||
return useUsersStore().globalRoleName;
|
return useUsersStore().globalRoleName;
|
||||||
},
|
},
|
||||||
|
getDynamicTranslations () {
|
||||||
|
return useUIStore().dynamicTranslations;
|
||||||
|
},
|
||||||
getFakeDoorFeatures () {
|
getFakeDoorFeatures () {
|
||||||
return useUIStore().fakeDoorFeatures;
|
return useUIStore().fakeDoorFeatures;
|
||||||
},
|
},
|
||||||
|
@ -61,5 +64,8 @@ export const useWebhooksStore = defineStore(STORES.WEBHOOKS, {
|
||||||
setFakeDoorFeatures(fakeDoors: IFakeDoor[]): void {
|
setFakeDoorFeatures(fakeDoors: IFakeDoor[]): void {
|
||||||
useUIStore().fakeDoorFeatures = fakeDoors;
|
useUIStore().fakeDoorFeatures = fakeDoors;
|
||||||
},
|
},
|
||||||
|
setDynamicTranslations(translations: NestedRecord<string>): void {
|
||||||
|
useUIStore().dynamicTranslations = translations;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue