mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(editor): Overhaul document title management (#10999)
This commit is contained in:
parent
63e6f1fa38
commit
bb2895689f
|
@ -34,7 +34,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useProjectsStore } from '@/stores/projects.store';
|
import { useProjectsStore } from '@/stores/projects.store';
|
||||||
|
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import { useTitleChange } from '@/composables/useTitleChange';
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { getResourcePermissions } from '@/permissions';
|
import { getResourcePermissions } from '@/permissions';
|
||||||
|
@ -87,7 +87,7 @@ const locale = useI18n();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const titleChange = useTitleChange();
|
const documentTitle = useDocumentTitle();
|
||||||
const workflowHelpers = useWorkflowHelpers({ router });
|
const workflowHelpers = useWorkflowHelpers({ router });
|
||||||
|
|
||||||
const isTagsEditEnabled = ref(false);
|
const isTagsEditEnabled = ref(false);
|
||||||
|
@ -558,7 +558,7 @@ async function onWorkflowMenuSelect(action: WORKFLOW_MENU_ACTIONS): Promise<void
|
||||||
}
|
}
|
||||||
uiStore.stateIsDirty = false;
|
uiStore.stateIsDirty = false;
|
||||||
// Reset tab title since workflow is deleted.
|
// Reset tab title since workflow is deleted.
|
||||||
titleChange.titleReset();
|
documentTitle.reset();
|
||||||
toast.showMessage({
|
toast.showMessage({
|
||||||
title: locale.baseText('mainSidebar.showMessage.handleSelect1.title'),
|
title: locale.baseText('mainSidebar.showMessage.handleSelect1.title'),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { useI18n } from '@/composables/useI18n';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
||||||
import { setPageTitle } from '@/utils/htmlUtils';
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import WorkerCard from './Workers/WorkerCard.ee.vue';
|
import WorkerCard from './Workers/WorkerCard.ee.vue';
|
||||||
import { usePushConnection } from '@/composables/usePushConnection';
|
import { usePushConnection } from '@/composables/usePushConnection';
|
||||||
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
||||||
|
@ -36,6 +36,7 @@ export default defineComponent({
|
||||||
i18n,
|
i18n,
|
||||||
pushConnection,
|
pushConnection,
|
||||||
...useToast(),
|
...useToast(),
|
||||||
|
documentTitle: useDocumentTitle(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -58,7 +59,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
setPageTitle(`n8n - ${this.pageTitle}`);
|
this.documentTitle.set(this.pageTitle);
|
||||||
|
|
||||||
this.$telemetry.track('User viewed worker view', {
|
this.$telemetry.track('User viewed worker view', {
|
||||||
instance_id: this.rootStore.instanceId,
|
instance_id: this.rootStore.instanceId,
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { mock } from 'vitest-mock-extended';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import type { FrontendSettings } from '@n8n/api-types';
|
||||||
|
import { useDocumentTitle } from '../useDocumentTitle';
|
||||||
|
|
||||||
|
const settings = mock<FrontendSettings>({ releaseChannel: 'stable' });
|
||||||
|
vi.mock('@/stores/settings.store', () => ({
|
||||||
|
useSettingsStore: vi.fn(() => ({ settings })),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('useDocumentTitle', () => {
|
||||||
|
it('should set the document title', () => {
|
||||||
|
const { set } = useDocumentTitle();
|
||||||
|
set('Test Title');
|
||||||
|
expect(document.title).toBe('Test Title - n8n');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset the document title', () => {
|
||||||
|
const { set, reset } = useDocumentTitle();
|
||||||
|
set('Test Title');
|
||||||
|
reset();
|
||||||
|
expect(document.title).toBe('Workflow Automation - n8n');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use the correct prefix for the release channel', () => {
|
||||||
|
settings.releaseChannel = 'beta';
|
||||||
|
const { set } = useDocumentTitle();
|
||||||
|
set('Test Title');
|
||||||
|
expect(document.title).toBe('Test Title - n8n[BETA]');
|
||||||
|
});
|
||||||
|
});
|
|
@ -52,6 +52,7 @@ vi.mock('@/composables/useWorkflowHelpers', () => ({
|
||||||
getCurrentWorkflow: vi.fn(),
|
getCurrentWorkflow: vi.fn(),
|
||||||
saveCurrentWorkflow: vi.fn(),
|
saveCurrentWorkflow: vi.fn(),
|
||||||
getWorkflowDataToSave: vi.fn(),
|
getWorkflowDataToSave: vi.fn(),
|
||||||
|
setDocumentTitle: vi.fn(),
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -61,10 +62,6 @@ vi.mock('@/composables/useNodeHelpers', () => ({
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('@/composables/useTitleChange', () => ({
|
|
||||||
useTitleChange: vi.fn().mockReturnValue({ titleSet: vi.fn() }),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('vue-router', async (importOriginal) => {
|
vi.mock('vue-router', async (importOriginal) => {
|
||||||
const { RouterLink } = await importOriginal<typeof router>();
|
const { RouterLink } = await importOriginal<typeof router>();
|
||||||
return {
|
return {
|
||||||
|
|
21
packages/editor-ui/src/composables/useDocumentTitle.ts
Normal file
21
packages/editor-ui/src/composables/useDocumentTitle.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
|
|
||||||
|
const DEFAULT_TITLE = 'Workflow Automation';
|
||||||
|
|
||||||
|
export function useDocumentTitle() {
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
const { releaseChannel } = settingsStore.settings;
|
||||||
|
const suffix =
|
||||||
|
!releaseChannel || releaseChannel === 'stable' ? 'n8n' : `n8n[${releaseChannel.toUpperCase()}]`;
|
||||||
|
|
||||||
|
const set = (title: string) => {
|
||||||
|
const sections = [title || DEFAULT_TITLE, suffix];
|
||||||
|
document.title = sections.join(' - ');
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
set('');
|
||||||
|
};
|
||||||
|
|
||||||
|
return { set, reset };
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ import type { PushMessage, PushPayload } from '@n8n/api-types';
|
||||||
|
|
||||||
import type { IExecutionResponse, IExecutionsCurrentSummaryExtended } from '@/Interface';
|
import type { IExecutionResponse, IExecutionsCurrentSummaryExtended } from '@/Interface';
|
||||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||||
import { useTitleChange } from '@/composables/useTitleChange';
|
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
|
import { WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
|
||||||
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
||||||
|
@ -43,7 +42,6 @@ type IPushDataExecutionFinishedPayload = PushPayload<'executionFinished'>;
|
||||||
export function usePushConnection({ router }: { router: ReturnType<typeof useRouter> }) {
|
export function usePushConnection({ router }: { router: ReturnType<typeof useRouter> }) {
|
||||||
const workflowHelpers = useWorkflowHelpers({ router });
|
const workflowHelpers = useWorkflowHelpers({ router });
|
||||||
const nodeHelpers = useNodeHelpers();
|
const nodeHelpers = useNodeHelpers();
|
||||||
const titleChange = useTitleChange();
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
@ -324,7 +322,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workflow did start but had been put to wait
|
// Workflow did start but had been put to wait
|
||||||
titleChange.titleSet(workflow.name as string, 'IDLE');
|
workflowHelpers.setDocumentTitle(workflow.name as string, 'IDLE');
|
||||||
toast.showToast({
|
toast.showToast({
|
||||||
title: 'Workflow started waiting',
|
title: 'Workflow started waiting',
|
||||||
message: `${action} <a href="https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/" target="_blank">More info</a>`,
|
message: `${action} <a href="https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/" target="_blank">More info</a>`,
|
||||||
|
@ -333,7 +331,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
});
|
});
|
||||||
} else if (runDataExecuted.finished !== true) {
|
} else if (runDataExecuted.finished !== true) {
|
||||||
titleChange.titleSet(workflow.name as string, 'ERROR');
|
workflowHelpers.setDocumentTitle(workflow.name as string, 'ERROR');
|
||||||
|
|
||||||
if (
|
if (
|
||||||
runDataExecuted.data.resultData.error?.name === 'ExpressionError' &&
|
runDataExecuted.data.resultData.error?.name === 'ExpressionError' &&
|
||||||
|
@ -442,7 +440,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Workflow did execute without a problem
|
// Workflow did execute without a problem
|
||||||
titleChange.titleSet(workflow.name as string, 'IDLE');
|
workflowHelpers.setDocumentTitle(workflow.name as string, 'IDLE');
|
||||||
|
|
||||||
const execution = workflowsStore.getWorkflowExecution;
|
const execution = workflowsStore.getWorkflowExecution;
|
||||||
if (execution?.executedNode) {
|
if (execution?.executedNode) {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import { useToast } from '@/composables/useToast';
|
||||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||||
|
|
||||||
import { CHAT_TRIGGER_NODE_TYPE, WORKFLOW_LM_CHAT_MODAL_KEY } from '@/constants';
|
import { CHAT_TRIGGER_NODE_TYPE, WORKFLOW_LM_CHAT_MODAL_KEY } from '@/constants';
|
||||||
import { useTitleChange } from '@/composables/useTitleChange';
|
|
||||||
import { useRootStore } from '@/stores/root.store';
|
import { useRootStore } from '@/stores/root.store';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
|
@ -41,7 +40,6 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||||
const workflowHelpers = useWorkflowHelpers({ router: useRunWorkflowOpts.router });
|
const workflowHelpers = useWorkflowHelpers({ router: useRunWorkflowOpts.router });
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const { titleSet } = useTitleChange();
|
|
||||||
|
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
|
@ -93,7 +91,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
titleSet(workflow.name as string, 'EXECUTING');
|
workflowHelpers.setDocumentTitle(workflow.name as string, 'EXECUTING');
|
||||||
|
|
||||||
toast.clearAllStickyNotifications();
|
toast.clearAllStickyNotifications();
|
||||||
|
|
||||||
|
@ -309,7 +307,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||||
|
|
||||||
return runWorkflowApiResponse;
|
return runWorkflowApiResponse;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
titleSet(workflow.name as string, 'ERROR');
|
workflowHelpers.setDocumentTitle(workflow.name as string, 'ERROR');
|
||||||
toast.showError(error, i18n.baseText('workflowRun.showError.title'));
|
toast.showError(error, i18n.baseText('workflowRun.showError.title'));
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -387,7 +385,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||||
workflowsStore.executingNode.length = 0;
|
workflowsStore.executingNode.length = 0;
|
||||||
uiStore.removeActiveAction('workflowRunning');
|
uiStore.removeActiveAction('workflowRunning');
|
||||||
|
|
||||||
titleSet(workflowsStore.workflowName, 'IDLE');
|
workflowHelpers.setDocumentTitle(workflowsStore.workflowName, 'IDLE');
|
||||||
toast.showMessage({
|
toast.showMessage({
|
||||||
title: i18n.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.title'),
|
title: i18n.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.title'),
|
||||||
message: i18n.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.message'),
|
message: i18n.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.message'),
|
||||||
|
@ -408,7 +406,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||||
retryOf: execution.retryOf,
|
retryOf: execution.retryOf,
|
||||||
};
|
};
|
||||||
workflowsStore.finishActiveExecution(pushData);
|
workflowsStore.finishActiveExecution(pushData);
|
||||||
titleSet(execution.workflowData.name, 'IDLE');
|
workflowHelpers.setDocumentTitle(execution.workflowData.name, 'IDLE');
|
||||||
workflowsStore.executingNode.length = 0;
|
workflowsStore.executingNode.length = 0;
|
||||||
workflowsStore.setWorkflowExecutionData(executedData as IExecutionResponse);
|
workflowsStore.setWorkflowExecutionData(executedData as IExecutionResponse);
|
||||||
uiStore.removeActiveAction('workflowRunning');
|
uiStore.removeActiveAction('workflowRunning');
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import type { WorkflowTitleStatus } from '@/Interface';
|
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
|
||||||
|
|
||||||
export function useTitleChange() {
|
|
||||||
const prependBeta = (title: string) => {
|
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
const { releaseChannel } = settingsStore.settings;
|
|
||||||
return releaseChannel === 'stable' ? title : `[${releaseChannel.toUpperCase()}] ${title}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const titleSet = (workflow: string, status: WorkflowTitleStatus) => {
|
|
||||||
let icon = '⚠️';
|
|
||||||
if (status === 'EXECUTING') {
|
|
||||||
icon = '🔄';
|
|
||||||
} else if (status === 'IDLE') {
|
|
||||||
icon = '▶️';
|
|
||||||
}
|
|
||||||
|
|
||||||
window.document.title = prependBeta(`n8n - ${icon} ${workflow}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const titleReset = () => {
|
|
||||||
window.document.title = prependBeta('n8n - Workflow Automation');
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
titleSet,
|
|
||||||
titleReset,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -37,6 +37,7 @@ import type {
|
||||||
IWorkflowDataUpdate,
|
IWorkflowDataUpdate,
|
||||||
IWorkflowDb,
|
IWorkflowDb,
|
||||||
TargetItem,
|
TargetItem,
|
||||||
|
WorkflowTitleStatus,
|
||||||
XYPosition,
|
XYPosition,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
|
||||||
|
@ -57,6 +58,7 @@ import { getSourceItems } from '@/utils/pairedItemUtils';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { getCredentialTypeName, isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes';
|
import { getCredentialTypeName, isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
import { useCanvasStore } from '@/stores/canvas.store';
|
import { useCanvasStore } from '@/stores/canvas.store';
|
||||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
|
@ -458,6 +460,17 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
|
const setDocumentTitle = (workflowName: string, status: WorkflowTitleStatus) => {
|
||||||
|
let icon = '⚠️';
|
||||||
|
if (status === 'EXECUTING') {
|
||||||
|
icon = '🔄';
|
||||||
|
} else if (status === 'IDLE') {
|
||||||
|
icon = '▶️';
|
||||||
|
}
|
||||||
|
documentTitle.set(`${icon} ${workflowName}`);
|
||||||
|
};
|
||||||
|
|
||||||
function getNodeTypesMaxCount() {
|
function getNodeTypesMaxCount() {
|
||||||
const nodes = workflowsStore.allNodes;
|
const nodes = workflowsStore.allNodes;
|
||||||
|
@ -1172,6 +1185,7 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
setDocumentTitle,
|
||||||
resolveParameter,
|
resolveParameter,
|
||||||
resolveRequiredParameters,
|
resolveRequiredParameters,
|
||||||
getCurrentWorkflow,
|
getCurrentWorkflow,
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { useUIStore } from './ui.store';
|
||||||
import { useUsersStore } from './users.store';
|
import { useUsersStore } from './users.store';
|
||||||
import { useVersionsStore } from './versions.store';
|
import { useVersionsStore } from './versions.store';
|
||||||
import { makeRestApiRequest } from '@/utils/apiUtils';
|
import { makeRestApiRequest } from '@/utils/apiUtils';
|
||||||
import { useTitleChange } from '@/composables/useTitleChange';
|
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { i18n } from '@/plugins/i18n';
|
import { i18n } from '@/plugins/i18n';
|
||||||
|
|
||||||
|
@ -258,9 +257,6 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
||||||
|
|
||||||
ExpressionEvaluatorProxy.setEvaluator(settings.value.expressions.evaluator);
|
ExpressionEvaluatorProxy.setEvaluator(settings.value.expressions.evaluator);
|
||||||
|
|
||||||
// Re-compute title since settings are now available
|
|
||||||
useTitleChange().titleReset();
|
|
||||||
|
|
||||||
initialized.value = true;
|
initialized.value = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showToast({
|
showToast({
|
||||||
|
|
|
@ -48,10 +48,6 @@ export const sanitizeIfString = <T>(message: T): string | T => {
|
||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function setPageTitle(title: string) {
|
|
||||||
window.document.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertRemToPixels(rem: string) {
|
export function convertRemToPixels(rem: string) {
|
||||||
return parseInt(rem, 10) * parseFloat(getComputedStyle(document.documentElement).fontSize);
|
return parseInt(rem, 10) * parseFloat(getComputedStyle(document.documentElement).fontSize);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import ProjectTabs from '@/components/Projects/ProjectTabs.vue';
|
||||||
import useEnvironmentsStore from '@/stores/environments.ee.store';
|
import useEnvironmentsStore from '@/stores/environments.ee.store';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { getResourcePermissions } from '@/permissions';
|
import { getResourcePermissions } from '@/permissions';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CredentialsView',
|
name: 'CredentialsView',
|
||||||
|
@ -35,6 +36,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
sourceControlStoreUnsubscribe: () => {},
|
sourceControlStoreUnsubscribe: () => {},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
documentTitle: useDocumentTitle(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -86,6 +88,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.documentTitle.set(this.$locale.baseText('credentials.heading'));
|
||||||
this.sourceControlStoreUnsubscribe = this.sourceControlStore.$onAction(({ name, after }) => {
|
this.sourceControlStoreUnsubscribe = this.sourceControlStore.$onAction(({ name, after }) => {
|
||||||
if (name === 'pullWorkfolder' && after) {
|
if (name === 'pullWorkfolder' && after) {
|
||||||
after(() => {
|
after(() => {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeMount, onBeforeUnmount, onMounted } from 'vue';
|
import { onBeforeMount, onBeforeUnmount, onMounted } from 'vue';
|
||||||
import GlobalExecutionsList from '@/components/executions/global/GlobalExecutionsList.vue';
|
import GlobalExecutionsList from '@/components/executions/global/GlobalExecutionsList.vue';
|
||||||
import { setPageTitle } from '@/utils/htmlUtils';
|
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useExecutionsStore } from '@/stores/executions.store';
|
import { useExecutionsStore } from '@/stores/executions.store';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import type { ExecutionFilterType } from '@/Interface';
|
import type { ExecutionFilterType } from '@/Interface';
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ const telemetry = useTelemetry();
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
const workflowsStore = useWorkflowsStore();
|
const workflowsStore = useWorkflowsStore();
|
||||||
const executionsStore = useExecutionsStore();
|
const executionsStore = useExecutionsStore();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ onBeforeMount(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
setPageTitle(`n8n - ${i18n.baseText('executionsList.workflowExecutions')}`);
|
documentTitle.set(i18n.baseText('executionsList.workflowExecutions'));
|
||||||
document.addEventListener('visibilitychange', onDocumentVisibilityChange);
|
document.addEventListener('visibilitychange', onDocumentVisibilityChange);
|
||||||
|
|
||||||
await executionsStore.initialize();
|
await executionsStore.initialize();
|
||||||
|
|
|
@ -78,7 +78,7 @@ import { useCanvasOperations } from '@/composables/useCanvasOperations';
|
||||||
import { useExecutionsStore } from '@/stores/executions.store';
|
import { useExecutionsStore } from '@/stores/executions.store';
|
||||||
import { useCanvasStore } from '@/stores/canvas.store';
|
import { useCanvasStore } from '@/stores/canvas.store';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
import { useTitleChange } from '@/composables/useTitleChange';
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useNpsSurveyStore } from '@/stores/npsSurvey.store';
|
import { useNpsSurveyStore } from '@/stores/npsSurvey.store';
|
||||||
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
|
@ -122,7 +122,7 @@ const telemetry = useTelemetry();
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const { titleReset, titleSet } = useTitleChange();
|
const documentTitle = useDocumentTitle();
|
||||||
const workflowHelpers = useWorkflowHelpers({ router });
|
const workflowHelpers = useWorkflowHelpers({ router });
|
||||||
const nodeHelpers = useNodeHelpers();
|
const nodeHelpers = useNodeHelpers();
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ async function initializeWorkspaceForExistingWorkflow(id: string) {
|
||||||
|
|
||||||
async function openWorkflow(data: IWorkflowDb) {
|
async function openWorkflow(data: IWorkflowDb) {
|
||||||
resetWorkspace();
|
resetWorkspace();
|
||||||
titleSet(editableWorkflow.value.name, 'IDLE');
|
workflowHelpers.setDocumentTitle(editableWorkflow.value.name, 'IDLE');
|
||||||
|
|
||||||
await initializeWorkspace(data);
|
await initializeWorkspace(data);
|
||||||
|
|
||||||
|
@ -1218,7 +1218,7 @@ async function onSourceControlPull() {
|
||||||
if (workflowId.value && !uiStore.stateIsDirty) {
|
if (workflowId.value && !uiStore.stateIsDirty) {
|
||||||
const workflowData = await workflowsStore.fetchWorkflow(workflowId.value);
|
const workflowData = await workflowsStore.fetchWorkflow(workflowId.value);
|
||||||
if (workflowData) {
|
if (workflowData) {
|
||||||
titleSet(workflowData.name, 'IDLE');
|
workflowHelpers.setDocumentTitle(workflowData.name, 'IDLE');
|
||||||
await openWorkflow(workflowData);
|
await openWorkflow(workflowData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1372,7 +1372,7 @@ function checkIfRouteIsAllowed() {
|
||||||
|
|
||||||
async function initializeDebugMode() {
|
async function initializeDebugMode() {
|
||||||
if (route.name === VIEWS.EXECUTION_DEBUG) {
|
if (route.name === VIEWS.EXECUTION_DEBUG) {
|
||||||
titleSet(workflowsStore.workflowName, 'DEBUG');
|
workflowHelpers.setDocumentTitle(workflowsStore.workflowName, 'DEBUG');
|
||||||
|
|
||||||
if (!workflowsStore.isInDebugMode) {
|
if (!workflowsStore.isInDebugMode) {
|
||||||
await applyExecutionData(route.params.executionId as string);
|
await applyExecutionData(route.params.executionId as string);
|
||||||
|
@ -1487,7 +1487,7 @@ onBeforeMount(() => {
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
canvasStore.startLoading();
|
canvasStore.startLoading();
|
||||||
|
|
||||||
titleReset();
|
documentTitle.reset();
|
||||||
resetWorkspace();
|
resetWorkspace();
|
||||||
|
|
||||||
void initializeData().then(() => {
|
void initializeData().then(() => {
|
||||||
|
|
|
@ -46,7 +46,7 @@ import { useGlobalLinkActions } from '@/composables/useGlobalLinkActions';
|
||||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||||
import useCanvasMouseSelect from '@/composables/useCanvasMouseSelect';
|
import useCanvasMouseSelect from '@/composables/useCanvasMouseSelect';
|
||||||
import { useExecutionDebugging } from '@/composables/useExecutionDebugging';
|
import { useExecutionDebugging } from '@/composables/useExecutionDebugging';
|
||||||
import { useTitleChange } from '@/composables/useTitleChange';
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useDataSchema } from '@/composables/useDataSchema';
|
import { useDataSchema } from '@/composables/useDataSchema';
|
||||||
import { type ContextMenuAction, useContextMenu } from '@/composables/useContextMenu';
|
import { type ContextMenuAction, useContextMenu } from '@/composables/useContextMenu';
|
||||||
import { useUniqueNodeName } from '@/composables/useUniqueNodeName';
|
import { useUniqueNodeName } from '@/composables/useUniqueNodeName';
|
||||||
|
@ -258,7 +258,7 @@ export default defineComponent({
|
||||||
callDebounced,
|
callDebounced,
|
||||||
...useCanvasMouseSelect(),
|
...useCanvasMouseSelect(),
|
||||||
...useGlobalLinkActions(),
|
...useGlobalLinkActions(),
|
||||||
...useTitleChange(),
|
documentTitle: useDocumentTitle(),
|
||||||
...useToast(),
|
...useToast(),
|
||||||
...useMessage(),
|
...useMessage(),
|
||||||
...useUniqueNodeName(),
|
...useUniqueNodeName(),
|
||||||
|
@ -591,7 +591,7 @@ export default defineComponent({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.canvasStore.initInstance(this.nodeViewRef);
|
this.canvasStore.initInstance(this.nodeViewRef);
|
||||||
this.titleReset();
|
this.documentTitle.reset();
|
||||||
|
|
||||||
window.addEventListener('message', this.onPostMessageReceived);
|
window.addEventListener('message', this.onPostMessageReceived);
|
||||||
|
|
||||||
|
@ -1719,7 +1719,7 @@ export default defineComponent({
|
||||||
this.workflowsStore.executingNode.length = 0;
|
this.workflowsStore.executingNode.length = 0;
|
||||||
this.uiStore.removeActiveAction('workflowRunning');
|
this.uiStore.removeActiveAction('workflowRunning');
|
||||||
|
|
||||||
this.titleSet(this.workflowsStore.workflowName, 'IDLE');
|
this.workflowHelpers.setDocumentTitle(this.workflowsStore.workflowName, 'IDLE');
|
||||||
this.showMessage({
|
this.showMessage({
|
||||||
title: this.$locale.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.title'),
|
title: this.$locale.baseText('nodeView.showMessage.stopExecutionCatch.unsaved.title'),
|
||||||
message: this.$locale.baseText(
|
message: this.$locale.baseText(
|
||||||
|
@ -1743,7 +1743,7 @@ export default defineComponent({
|
||||||
retryOf: execution.retryOf,
|
retryOf: execution.retryOf,
|
||||||
};
|
};
|
||||||
this.workflowsStore.finishActiveExecution(pushData);
|
this.workflowsStore.finishActiveExecution(pushData);
|
||||||
this.titleSet(execution.workflowData.name, 'IDLE');
|
this.workflowHelpers.setDocumentTitle(execution.workflowData.name, 'IDLE');
|
||||||
this.workflowsStore.executingNode.length = 0;
|
this.workflowsStore.executingNode.length = 0;
|
||||||
this.workflowsStore.setWorkflowExecutionData(executedData as IExecutionResponse);
|
this.workflowsStore.setWorkflowExecutionData(executedData as IExecutionResponse);
|
||||||
this.uiStore.removeActiveAction('workflowRunning');
|
this.uiStore.removeActiveAction('workflowRunning');
|
||||||
|
@ -3410,7 +3410,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workflow) {
|
if (workflow) {
|
||||||
this.titleSet(workflow.name, 'IDLE');
|
this.workflowHelpers.setDocumentTitle(workflow.name, 'IDLE');
|
||||||
await this.openWorkflow(workflow);
|
await this.openWorkflow(workflow);
|
||||||
await this.checkAndInitDebugMode();
|
await this.checkAndInitDebugMode();
|
||||||
|
|
||||||
|
@ -4371,7 +4371,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
async checkAndInitDebugMode() {
|
async checkAndInitDebugMode() {
|
||||||
if (this.$route.name === VIEWS.EXECUTION_DEBUG) {
|
if (this.$route.name === VIEWS.EXECUTION_DEBUG) {
|
||||||
this.titleSet(this.workflowName, 'DEBUG');
|
this.workflowHelpers.setDocumentTitle(this.workflowName, 'DEBUG');
|
||||||
if (!this.workflowsStore.isInDebugMode) {
|
if (!this.workflowsStore.isInDebugMode) {
|
||||||
await this.applyExecutionData(this.$route.params.executionId as string);
|
await this.applyExecutionData(this.$route.params.executionId as string);
|
||||||
this.workflowsStore.isInDebugMode = true;
|
this.workflowsStore.isInDebugMode = true;
|
||||||
|
@ -4444,7 +4444,7 @@ export default defineComponent({
|
||||||
const workflow: IWorkflowDb | undefined =
|
const workflow: IWorkflowDb | undefined =
|
||||||
await this.workflowsStore.fetchWorkflow(workflowId);
|
await this.workflowsStore.fetchWorkflow(workflowId);
|
||||||
if (workflow) {
|
if (workflow) {
|
||||||
this.titleSet(workflow.name, 'IDLE');
|
this.workflowHelpers.setDocumentTitle(workflow.name, 'IDLE');
|
||||||
await this.openWorkflow(workflow);
|
await this.openWorkflow(workflow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { useRolesStore } from '@/stores/roles.store';
|
||||||
import type { ProjectRole } from '@/types/roles.types';
|
import type { ProjectRole } from '@/types/roles.types';
|
||||||
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
type FormDataDiff = {
|
type FormDataDiff = {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
@ -33,6 +34,7 @@ const cloudPlanStore = useCloudPlanStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
const upgradeDialogVisible = ref(false);
|
const upgradeDialogVisible = ref(false);
|
||||||
|
|
||||||
|
@ -250,6 +252,7 @@ onBeforeMount(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
documentTitle.set(locale.baseText('projects.settings'));
|
||||||
selectProjectNameIfMatchesDefault();
|
selectProjectNameIfMatchesDefault();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { defineComponent } from 'vue';
|
||||||
import type { ApiKey, IUser } from '@/Interface';
|
import type { ApiKey, IUser } from '@/Interface';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
import CopyInput from '@/components/CopyInput.vue';
|
import CopyInput from '@/components/CopyInput.vue';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
|
@ -23,6 +24,7 @@ export default defineComponent({
|
||||||
...useToast(),
|
...useToast(),
|
||||||
...useMessage(),
|
...useMessage(),
|
||||||
...useUIStore(),
|
...useUIStore(),
|
||||||
|
documentTitle: useDocumentTitle(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -35,6 +37,7 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.documentTitle.set(this.$locale.baseText('settings.api'));
|
||||||
if (!this.isPublicApiEnabled) return;
|
if (!this.isPublicApiEnabled) return;
|
||||||
|
|
||||||
void this.getApiKeys();
|
void this.getApiKeys();
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import CommunityPackageCard from '@/components/CommunityPackageCard.vue';
|
import CommunityPackageCard from '@/components/CommunityPackageCard.vue';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import type { PublicInstalledPackage } from 'n8n-workflow';
|
import type { PublicInstalledPackage } from 'n8n-workflow';
|
||||||
|
|
||||||
import { useCommunityNodesStore } from '@/stores/communityNodes.store';
|
import { useCommunityNodesStore } from '@/stores/communityNodes.store';
|
||||||
|
@ -31,6 +32,7 @@ const externalHooks = useExternalHooks();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const communityNodesStore = useCommunityNodesStore();
|
const communityNodesStore = useCommunityNodesStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
|
@ -85,6 +87,7 @@ onBeforeMount(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
documentTitle.set(i18n.baseText('settings.communityNodes'));
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await communityNodesStore.fetchInstalledPackages();
|
await communityNodesStore.fetchInstalledPackages();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useExternalSecretsStore } from '@/stores/externalSecrets.ee.store';
|
import { useExternalSecretsStore } from '@/stores/externalSecrets.ee.store';
|
||||||
import { computed, onMounted } from 'vue';
|
import { computed, onMounted } from 'vue';
|
||||||
import ExternalSecretsProviderCard from '@/components/ExternalSecretsProviderCard.ee.vue';
|
import ExternalSecretsProviderCard from '@/components/ExternalSecretsProviderCard.ee.vue';
|
||||||
|
@ -11,6 +12,7 @@ const i18n = useI18n();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const externalSecretsStore = useExternalSecretsStore();
|
const externalSecretsStore = useExternalSecretsStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const sortedProviders = computed(() => {
|
const sortedProviders = computed(() => {
|
||||||
return ([...externalSecretsStore.providers] as ExternalSecretsProvider[]).sort((a, b) => {
|
return ([...externalSecretsStore.providers] as ExternalSecretsProvider[]).sort((a, b) => {
|
||||||
|
@ -19,6 +21,7 @@ const sortedProviders = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
documentTitle.set(i18n.baseText('settings.externalSecrets.title'));
|
||||||
if (!externalSecretsStore.isEnterpriseExternalSecretsEnabled) return;
|
if (!externalSecretsStore.isEnterpriseExternalSecretsEnabled) return;
|
||||||
try {
|
try {
|
||||||
void externalSecretsStore.fetchAllSecrets();
|
void externalSecretsStore.fetchAllSecrets();
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { capitalizeFirstLetter } from '@/utils/htmlUtils';
|
||||||
import { convertToDisplayDate } from '@/utils/typesUtils';
|
import { convertToDisplayDate } from '@/utils/typesUtils';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import type {
|
import type {
|
||||||
ILdapConfig,
|
ILdapConfig,
|
||||||
ILdapSyncData,
|
ILdapSyncData,
|
||||||
|
@ -65,6 +66,7 @@ type CellClassStyleMethodParams<T> = {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
|
@ -585,6 +587,7 @@ const reloadLdapSynchronizations = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
documentTitle.set(i18n.baseText('settings.ldap'));
|
||||||
if (!isLDAPFeatureEnabled.value) return;
|
if (!isLDAPFeatureEnabled.value) return;
|
||||||
await getLdapConfig();
|
await getLdapConfig();
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,6 +13,7 @@ import type { MessageEventBusDestinationOptions } from 'n8n-workflow';
|
||||||
import { deepCopy, defaultMessageEventBusDestinationOptions } from 'n8n-workflow';
|
import { deepCopy, defaultMessageEventBusDestinationOptions } from 'n8n-workflow';
|
||||||
import EventDestinationCard from '@/components/SettingsLogStreaming/EventDestinationCard.ee.vue';
|
import EventDestinationCard from '@/components/SettingsLogStreaming/EventDestinationCard.ee.vue';
|
||||||
import { createEventBus } from 'n8n-design-system/utils';
|
import { createEventBus } from 'n8n-design-system/utils';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SettingsLogStreamingView',
|
name: 'SettingsLogStreamingView',
|
||||||
|
@ -26,9 +27,11 @@ export default defineComponent({
|
||||||
destinations: Array<MessageEventBusDestinationOptions>,
|
destinations: Array<MessageEventBusDestinationOptions>,
|
||||||
disableLicense: false,
|
disableLicense: false,
|
||||||
allDestinations: [] as MessageEventBusDestinationOptions[],
|
allDestinations: [] as MessageEventBusDestinationOptions[],
|
||||||
|
documentTitle: useDocumentTitle(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
this.documentTitle.set(this.$locale.baseText('settings.log-streaming.heading'));
|
||||||
if (!this.isLicensed) return;
|
if (!this.isLicensed) return;
|
||||||
|
|
||||||
// Prepare credentialsStore so modals can pick up credentials
|
// Prepare credentialsStore so modals can pick up credentials
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
|
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import type { IFormInputs, IUser, ThemeOption } from '@/Interface';
|
import type { IFormInputs, IUser, ThemeOption } from '@/Interface';
|
||||||
import {
|
import {
|
||||||
CHANGE_PASSWORD_MODAL_KEY,
|
CHANGE_PASSWORD_MODAL_KEY,
|
||||||
|
@ -28,6 +29,7 @@ type UserBasicDetailsWithMfa = UserBasicDetailsForm & {
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const { showToast, showError } = useToast();
|
const { showToast, showError } = useToast();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const hasAnyBasicInfoChanges = ref<boolean>(false);
|
const hasAnyBasicInfoChanges = ref<boolean>(false);
|
||||||
const formInputs = ref<null | IFormInputs>(null);
|
const formInputs = ref<null | IFormInputs>(null);
|
||||||
|
@ -80,6 +82,7 @@ const hasAnyChanges = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
documentTitle.set(i18n.baseText('settings.personal.personalSettings'));
|
||||||
formInputs.value = [
|
formInputs.value = [
|
||||||
{
|
{
|
||||||
name: 'firstName',
|
name: 'firstName',
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { useToast } from '@/composables/useToast';
|
||||||
import { useLoadingService } from '@/composables/useLoadingService';
|
import { useLoadingService } from '@/composables/useLoadingService';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import CopyInput from '@/components/CopyInput.vue';
|
import CopyInput from '@/components/CopyInput.vue';
|
||||||
import type { TupleToUnion } from '@/utils/typeHelpers';
|
import type { TupleToUnion } from '@/utils/typeHelpers';
|
||||||
import type { SshKeyTypes } from '@/Interface';
|
import type { SshKeyTypes } from '@/Interface';
|
||||||
|
@ -17,6 +18,7 @@ const sourceControlStore = useSourceControlStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
const loadingService = useLoadingService();
|
const loadingService = useLoadingService();
|
||||||
|
|
||||||
const isConnected = ref(false);
|
const isConnected = ref(false);
|
||||||
|
@ -112,6 +114,7 @@ const initialize = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
documentTitle.set(locale.baseText('settings.sourceControl.title'));
|
||||||
if (!sourceControlStore.isEnterpriseSourceControlEnabled) return;
|
if (!sourceControlStore.isEnterpriseSourceControlEnabled) return;
|
||||||
await initialize();
|
await initialize();
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { useI18n } from '@/composables/useI18n';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useRootStore } from '@/stores/root.store';
|
import { useRootStore } from '@/stores/root.store';
|
||||||
|
|
||||||
const IdentityProviderSettingsType = {
|
const IdentityProviderSettingsType = {
|
||||||
|
@ -21,6 +22,7 @@ const ssoStore = useSSOStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const ssoActivatedLabel = computed(() =>
|
const ssoActivatedLabel = computed(() =>
|
||||||
ssoStore.isSamlLoginEnabled
|
ssoStore.isSamlLoginEnabled
|
||||||
|
@ -144,6 +146,7 @@ const isToggleSsoDisabled = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
documentTitle.set(i18n.baseText('settings.sso.title'));
|
||||||
if (!ssoStore.isEnterpriseSamlEnabled) {
|
if (!ssoStore.isEnterpriseSamlEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { telemetry } from '@/plugins/telemetry';
|
||||||
import { i18n as locale } from '@/plugins/i18n';
|
import { i18n as locale } from '@/plugins/i18n';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { hasPermission } from '@/utils/rbac/permissions';
|
import { hasPermission } from '@/utils/rbac/permissions';
|
||||||
|
|
||||||
const usageStore = useUsageStore();
|
const usageStore = useUsageStore();
|
||||||
|
@ -14,6 +15,7 @@ const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const queryParamCallback = ref<string>(
|
const queryParamCallback = ref<string>(
|
||||||
`callback=${encodeURIComponent(`${window.location.origin}${window.location.pathname}`)}`,
|
`callback=${encodeURIComponent(`${window.location.origin}${window.location.pathname}`)}`,
|
||||||
|
@ -64,6 +66,7 @@ const onLicenseActivation = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
documentTitle.set(locale.baseText('settings.usageAndPlan.title'));
|
||||||
usageStore.setLoading(true);
|
usageStore.setLoading(true);
|
||||||
if (route.query.key) {
|
if (route.query.key) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { useClipboard } from '@/composables/useClipboard';
|
||||||
import type { UpdateGlobalRolePayload } from '@/api/users';
|
import type { UpdateGlobalRolePayload } from '@/api/users';
|
||||||
import { computed, onMounted } from 'vue';
|
import { computed, onMounted } from 'vue';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
const clipboard = useClipboard();
|
const clipboard = useClipboard();
|
||||||
const { showToast, showError } = useToast();
|
const { showToast, showError } = useToast();
|
||||||
|
@ -20,6 +21,7 @@ const settingsStore = useSettingsStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const usersStore = useUsersStore();
|
const usersStore = useUsersStore();
|
||||||
const ssoStore = useSSOStore();
|
const ssoStore = useSSOStore();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
@ -28,6 +30,8 @@ const showUMSetupWarning = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
documentTitle.set(i18n.baseText('settings.users'));
|
||||||
|
|
||||||
if (!showUMSetupWarning.value) {
|
if (!showUMSetupWarning.value) {
|
||||||
await usersStore.fetchUsers();
|
await usersStore.fetchUsers();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import { isFullTemplatesCollection } from '@/utils/templates/typeGuards';
|
import { isFullTemplatesCollection } from '@/utils/templates/typeGuards';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { setPageTitle } from '@/utils/htmlUtils';
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
|
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
|
@ -25,6 +25,7 @@ const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const notFoundError = ref(false);
|
const notFoundError = ref(false);
|
||||||
|
@ -89,9 +90,9 @@ watch(
|
||||||
() => collection.value,
|
() => collection.value,
|
||||||
() => {
|
() => {
|
||||||
if (collection.value && 'full' in collection.value && collection.value.full) {
|
if (collection.value && 'full' in collection.value && collection.value.full) {
|
||||||
setPageTitle(`n8n - Template collection: ${collection.value.name}`);
|
documentTitle.set(`Template collection: ${collection.value.name}`);
|
||||||
} else {
|
} else {
|
||||||
setPageTitle('n8n - Templates');
|
documentTitle.set('Templates');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,6 @@ import type {
|
||||||
ITemplatesCategory,
|
ITemplatesCategory,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
import type { IDataObject } from 'n8n-workflow';
|
import type { IDataObject } from 'n8n-workflow';
|
||||||
import { setPageTitle } from '@/utils/htmlUtils';
|
|
||||||
import { CREATOR_HUB_URL, VIEWS } from '@/constants';
|
import { CREATOR_HUB_URL, VIEWS } from '@/constants';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
|
@ -22,6 +21,7 @@ import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { usePostHog } from '@/stores/posthog.store';
|
import { usePostHog } from '@/stores/posthog.store';
|
||||||
import { useDebounce } from '@/composables/useDebounce';
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
interface ISearchEvent {
|
interface ISearchEvent {
|
||||||
search_string: string;
|
search_string: string;
|
||||||
|
@ -55,6 +55,7 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
callDebounced,
|
callDebounced,
|
||||||
...useToast(),
|
...useToast(),
|
||||||
|
documentTitle: useDocumentTitle(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -116,7 +117,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
setPageTitle('n8n - Templates');
|
this.documentTitle.set('Templates');
|
||||||
await this.loadCategories();
|
await this.loadCategories();
|
||||||
void this.loadWorkflowsAndCollections(true);
|
void this.loadWorkflowsAndCollections(true);
|
||||||
void this.usersStore.showPersonalizationSurvey();
|
void this.usersStore.showPersonalizationSurvey();
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { setPageTitle } from '@/utils/htmlUtils';
|
|
||||||
import { useTemplatesStore } from '@/stores/templates.store';
|
import { useTemplatesStore } from '@/stores/templates.store';
|
||||||
import { usePostHog } from '@/stores/posthog.store';
|
import { usePostHog } from '@/stores/posthog.store';
|
||||||
import { useTemplateWorkflow } from '@/utils/templates/templateActions';
|
import { useTemplateWorkflow } from '@/utils/templates/templateActions';
|
||||||
|
@ -8,6 +7,7 @@ import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import TemplatesView from './TemplatesView.vue';
|
import TemplatesView from './TemplatesView.vue';
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
|
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const showPreview = ref(true);
|
const showPreview = ref(true);
|
||||||
|
@ -63,9 +64,9 @@ watch(
|
||||||
() => template.value,
|
() => template.value,
|
||||||
(newTemplate) => {
|
(newTemplate) => {
|
||||||
if (newTemplate) {
|
if (newTemplate) {
|
||||||
setPageTitle(`n8n - Template template: ${newTemplate.name}`);
|
documentTitle.set(`Template template: ${newTemplate.name}`);
|
||||||
} else {
|
} else {
|
||||||
setPageTitle('n8n - Templates');
|
documentTitle.set('Templates');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, onBeforeMount, onBeforeUnmount } from 'vue';
|
import { computed, ref, onBeforeMount, onBeforeUnmount, onMounted } from 'vue';
|
||||||
import { useEnvironmentsStore } from '@/stores/environments.ee.store';
|
import { useEnvironmentsStore } from '@/stores/environments.ee.store';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
|
@ -9,6 +9,7 @@ import { useI18n } from '@/composables/useI18n';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
import type { IResource } from '@/components/layouts/ResourcesListLayout.vue';
|
import type { IResource } from '@/components/layouts/ResourcesListLayout.vue';
|
||||||
import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue';
|
import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue';
|
||||||
|
@ -28,6 +29,7 @@ const telemetry = useTelemetry();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const sourceControlStore = useSourceControlStore();
|
const sourceControlStore = useSourceControlStore();
|
||||||
|
const documentTitle = useDocumentTitle();
|
||||||
let sourceControlStoreUnsubscribe = () => {};
|
let sourceControlStoreUnsubscribe = () => {};
|
||||||
|
|
||||||
const layoutRef = ref<InstanceType<typeof ResourcesListLayout> | null>(null);
|
const layoutRef = ref<InstanceType<typeof ResourcesListLayout> | null>(null);
|
||||||
|
@ -248,6 +250,10 @@ onBeforeMount(() => {
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
sourceControlStoreUnsubscribe();
|
sourceControlStoreUnsubscribe();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
documentTitle.set(i18n.baseText('variables.heading'));
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -17,6 +17,7 @@ import ProjectTabs from '@/components/Projects/ProjectTabs.vue';
|
||||||
import { useTemplatesStore } from '@/stores/templates.store';
|
import { useTemplatesStore } from '@/stores/templates.store';
|
||||||
import { getResourcePermissions } from '@/permissions';
|
import { getResourcePermissions } from '@/permissions';
|
||||||
import { usePostHog } from '@/stores/posthog.store';
|
import { usePostHog } from '@/stores/posthog.store';
|
||||||
|
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||||
|
|
||||||
interface Filters {
|
interface Filters {
|
||||||
search: string;
|
search: string;
|
||||||
|
@ -49,6 +50,7 @@ const WorkflowsView = defineComponent({
|
||||||
} as Filters,
|
} as Filters,
|
||||||
sourceControlStoreUnsubscribe: () => {},
|
sourceControlStoreUnsubscribe: () => {},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
documentTitle: useDocumentTitle(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -149,6 +151,7 @@ const WorkflowsView = defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
this.documentTitle.set(this.$locale.baseText('workflows.heading'));
|
||||||
await this.setFiltersFromQueryString();
|
await this.setFiltersFromQueryString();
|
||||||
|
|
||||||
void this.usersStore.showPersonalizationSurvey();
|
void this.usersStore.showPersonalizationSurvey();
|
||||||
|
|
Loading…
Reference in a new issue