mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(editor): Version Control settings update (WIP) (#6233)
This commit is contained in:
parent
51c89db6dc
commit
0666377ef8
|
@ -1438,7 +1438,8 @@ export type VersionControlPreferences = {
|
||||||
repositoryUrl: string;
|
repositoryUrl: string;
|
||||||
authorName: string;
|
authorName: string;
|
||||||
authorEmail: string;
|
authorEmail: string;
|
||||||
branchName: string;
|
currentBranch: string;
|
||||||
|
branches: string[];
|
||||||
branchReadOnly: boolean;
|
branchReadOnly: boolean;
|
||||||
branchColor: string;
|
branchColor: string;
|
||||||
publicKey?: string;
|
publicKey?: string;
|
||||||
|
|
|
@ -1290,18 +1290,26 @@
|
||||||
"settings.versionControl.actionBox.title": "Available on Enterprise plan",
|
"settings.versionControl.actionBox.title": "Available on Enterprise plan",
|
||||||
"settings.versionControl.actionBox.description": "Use Version Control to connect your instance to an external Git repository to backup and track changes made to your workflows, variables, and credentials. With Version Control you can also sync instances across multiple environments (development, production...).",
|
"settings.versionControl.actionBox.description": "Use Version Control to connect your instance to an external Git repository to backup and track changes made to your workflows, variables, and credentials. With Version Control you can also sync instances across multiple environments (development, production...).",
|
||||||
"settings.versionControl.actionBox.buttonText": "See plans",
|
"settings.versionControl.actionBox.buttonText": "See plans",
|
||||||
"settings.versionControl.description": "Versioning allows you to connect your n8n instance to a Git branch of a repository. You can connect your branches to multiples n8n instances to create a multi environments setup. Learn how to set up versioning and environments in n8n.",
|
"settings.versionControl.description": "Versioning allows you to connect your n8n instance to a Git branch of a repository. You can connect your branches to multiples n8n instances to create a multi environments setup. {link}",
|
||||||
"settings.versionControl.repoUrl": "Git repository URL",
|
"settings.versionControl.description.link": "Learn how to set up versioning and environments in n8n.",
|
||||||
|
"settings.versionControl.gitConfig": "Git configuration",
|
||||||
|
"settings.versionControl.repoUrl": "Git repository URL (SSH)",
|
||||||
"settings.versionControl.repoUrlPlaceholder": "e.g. git@github.com:my-team/my-repository",
|
"settings.versionControl.repoUrlPlaceholder": "e.g. git@github.com:my-team/my-repository",
|
||||||
"settings.versionControl.repoUrlDescription": "The SSH url of your Git repository",
|
"settings.versionControl.repoUrlDescription": "The SSH url of your Git repository",
|
||||||
"settings.versionControl.authorName": "Author name",
|
"settings.versionControl.authorName": "Commit author name",
|
||||||
"settings.versionControl.authorEmail": "Author email",
|
"settings.versionControl.authorEmail": "Commit author email",
|
||||||
"settings.versionControl.sshKey": "SSH Key",
|
"settings.versionControl.sshKey": "SSH Key",
|
||||||
"settings.versionControl.sshKeyDescription": "Paste the SSH key in yout git repository settings. {link}.",
|
"settings.versionControl.sshKeyDescription": "Paste the SSH key in yout git repository settings. {link}.",
|
||||||
"settings.versionControl.sshKeyDescriptionLink": "More info.",
|
"settings.versionControl.sshKeyDescriptionLink": "More info.",
|
||||||
"settings.versionControl.button.continue": "Continue",
|
"settings.versionControl.button.continue": "Continue",
|
||||||
"settings.versionControl.button.connect": "Connect",
|
"settings.versionControl.button.connect": "Connect",
|
||||||
"settings.versionControl.branches": "Select branch",
|
"settings.versionControl.button.save": "Save settings",
|
||||||
|
"settings.versionControl.instanceSettings": "Instance settings",
|
||||||
|
"settings.versionControl.branches": "Branch connected to this n8n instance",
|
||||||
|
"settings.versionControl.readonly": "{bold}: prevent editing workflows (recommended for production environments). {link}",
|
||||||
|
"settings.versionControl.readonly.bold": "Read-only instance",
|
||||||
|
"settings.versionControl.readonly.link": "Learn more.",
|
||||||
|
"settings.versionControl.color": "Color",
|
||||||
"settings.versionControl.switchBranch.title": "Switch to {branch} branch",
|
"settings.versionControl.switchBranch.title": "Switch to {branch} branch",
|
||||||
"settings.versionControl.switchBranch.description": "Please confirm you want to switch the current n8n instance to the branch: {branch}",
|
"settings.versionControl.switchBranch.description": "Please confirm you want to switch the current n8n instance to the branch: {branch}",
|
||||||
"settings.versionControl.sync.prompt.title": "Sync changes in {branch} branch",
|
"settings.versionControl.sync.prompt.title": "Sync changes in {branch} branch",
|
||||||
|
|
|
@ -16,12 +16,13 @@ export const useVersionControlStore = defineStore('versionControl', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const preferences = reactive<VersionControlPreferences>({
|
const preferences = reactive<VersionControlPreferences>({
|
||||||
branchName: '',
|
currentBranch: '',
|
||||||
|
branches: [],
|
||||||
authorName: '',
|
authorName: '',
|
||||||
authorEmail: '',
|
authorEmail: '',
|
||||||
repositoryUrl: '',
|
repositoryUrl: '',
|
||||||
branchReadOnly: false,
|
branchReadOnly: false,
|
||||||
branchColor: '#000000',
|
branchColor: '#F4A6DC',
|
||||||
connected: false,
|
connected: false,
|
||||||
publicKey: '',
|
publicKey: '',
|
||||||
});
|
});
|
||||||
|
@ -77,6 +78,7 @@ export const useVersionControlStore = defineStore('versionControl', () => {
|
||||||
return {
|
return {
|
||||||
isEnterpriseVersionControlEnabled,
|
isEnterpriseVersionControlEnabled,
|
||||||
state,
|
state,
|
||||||
|
preferences,
|
||||||
initSsh,
|
initSsh,
|
||||||
initRepository,
|
initRepository,
|
||||||
sync,
|
sync,
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import { i18n as locale } from '@/plugins/i18n';
|
import { i18n as locale } from '@/plugins/i18n';
|
||||||
import { useVersionControlStore } from '@/stores/versionControl.store';
|
import { useVersionControlStore } from '@/stores/versionControl.store';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useMessage } from '@/composables';
|
import { useMessage } from '@/composables';
|
||||||
|
import CopyInput from '@/components/CopyInput.vue';
|
||||||
|
|
||||||
const versionControlStore = useVersionControlStore();
|
const versionControlStore = useVersionControlStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
|
|
||||||
const sshKey = computed(() => versionControlStore.state.sshKey);
|
|
||||||
const branch = computed(() => versionControlStore.state.currentBranch);
|
|
||||||
const branches = ref<string[]>([]);
|
|
||||||
const selectElement = ref<HTMLSelectElement | null>(null);
|
|
||||||
|
|
||||||
const onContinue = () => {
|
const onContinue = () => {
|
||||||
void versionControlStore.initSsh({
|
void versionControlStore.initSsh({
|
||||||
name: versionControlStore.state.authorName,
|
name: versionControlStore.state.authorName,
|
||||||
|
@ -26,22 +21,15 @@ const onConnect = () => {
|
||||||
void versionControlStore.initRepository();
|
void versionControlStore.initRepository();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSave = () => {
|
||||||
|
void versionControlStore.savePreferences(versionControlStore.preferences);
|
||||||
|
};
|
||||||
|
|
||||||
const onSelect = async (b: string) => {
|
const onSelect = async (b: string) => {
|
||||||
if (b === branch.value) {
|
if (b === versionControlStore.preferences.currentBranch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const switchBranch = await message
|
versionControlStore.preferences.currentBranch = b;
|
||||||
.confirm(
|
|
||||||
locale.baseText('settings.versionControl.switchBranch.description', {
|
|
||||||
interpolate: { branch: b },
|
|
||||||
}),
|
|
||||||
locale.baseText('settings.versionControl.switchBranch.title', { interpolate: { branch: b } }),
|
|
||||||
)
|
|
||||||
.catch(() => {});
|
|
||||||
if (switchBranch === 'confirm') {
|
|
||||||
versionControlStore.state.currentBranch = b;
|
|
||||||
selectElement.value?.blur();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const goToUpgrade = () => {
|
const goToUpgrade = () => {
|
||||||
|
@ -51,40 +39,59 @@ const goToUpgrade = () => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<n8n-heading size="2xlarge">{{ locale.baseText('settings.versionControl.title') }}</n8n-heading>
|
<n8n-heading size="2xlarge" tag="h1">{{
|
||||||
|
locale.baseText('settings.versionControl.title')
|
||||||
|
}}</n8n-heading>
|
||||||
<div
|
<div
|
||||||
v-if="versionControlStore.isEnterpriseVersionControlEnabled"
|
v-if="versionControlStore.isEnterpriseVersionControlEnabled"
|
||||||
data-test-id="version-control-content-licensed"
|
data-test-id="version-control-content-licensed"
|
||||||
>
|
>
|
||||||
<n8n-callout theme="secondary" icon="info-circle" class="mt-2xl mb-l">{{
|
<n8n-callout theme="secondary" icon="info-circle" class="mt-2xl mb-l">
|
||||||
locale.baseText('settings.versionControl.description')
|
<i18n path="settings.versionControl.description">
|
||||||
}}</n8n-callout>
|
<template #link>
|
||||||
|
<a href="#" target="_blank">
|
||||||
|
{{ locale.baseText('settings.versionControl.description.link') }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</i18n>
|
||||||
|
</n8n-callout>
|
||||||
|
<n8n-heading size="xlarge" tag="h2" class="mb-s">{{
|
||||||
|
locale.baseText('settings.versionControl.gitConfig')
|
||||||
|
}}</n8n-heading>
|
||||||
<div :class="$style.group">
|
<div :class="$style.group">
|
||||||
<label for="repoUrl">{{ locale.baseText('settings.versionControl.repoUrl') }}</label>
|
<label for="repoUrl">{{ locale.baseText('settings.versionControl.repoUrl') }}</label>
|
||||||
<n8n-input
|
<n8n-input
|
||||||
id="repoUrl"
|
id="repoUrl"
|
||||||
:placeholder="locale.baseText('settings.versionControl.repoUrlPlaceholder')"
|
:placeholder="locale.baseText('settings.versionControl.repoUrlPlaceholder')"
|
||||||
v-model="versionControlStore.state.repositoryUrl"
|
v-model="versionControlStore.preferences.repositoryUrl"
|
||||||
/>
|
/>
|
||||||
<small>{{ locale.baseText('settings.versionControl.repoUrlDescription') }}</small>
|
<small>{{ locale.baseText('settings.versionControl.repoUrlDescription') }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.group">
|
<div :class="[$style.group, $style.groupFlex]">
|
||||||
<label for="authorName">{{ locale.baseText('settings.versionControl.authorName') }}</label>
|
<div>
|
||||||
<n8n-input id="authorName" v-model="versionControlStore.state.authorName" />
|
<label for="authorName">{{
|
||||||
|
locale.baseText('settings.versionControl.authorName')
|
||||||
|
}}</label>
|
||||||
|
<n8n-input id="authorName" v-model="versionControlStore.preferences.authorName" />
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.group">
|
<div>
|
||||||
<label for="authorEmail">{{
|
<label for="authorEmail">{{
|
||||||
locale.baseText('settings.versionControl.authorEmail')
|
locale.baseText('settings.versionControl.authorEmail')
|
||||||
}}</label>
|
}}</label>
|
||||||
<n8n-input id="authorEmail" v-model="versionControlStore.state.authorEmail" />
|
<n8n-input id="authorEmail" v-model="versionControlStore.preferences.authorEmail" />
|
||||||
</div>
|
</div>
|
||||||
<n8n-button v-if="!sshKey" @click="onContinue" size="large" class="mt-2xs">{{
|
</div>
|
||||||
locale.baseText('settings.versionControl.button.continue')
|
<n8n-button
|
||||||
}}</n8n-button>
|
v-if="!versionControlStore.preferences.publicKey"
|
||||||
<div v-if="sshKey" :class="$style.group">
|
@click="onContinue"
|
||||||
|
size="large"
|
||||||
|
class="mt-2xs"
|
||||||
|
>{{ locale.baseText('settings.versionControl.button.continue') }}</n8n-button
|
||||||
|
>
|
||||||
|
<div v-if="versionControlStore.preferences.publicKey" :class="$style.group">
|
||||||
<label>{{ locale.baseText('settings.versionControl.sshKey') }}</label>
|
<label>{{ locale.baseText('settings.versionControl.sshKey') }}</label>
|
||||||
<CopyInput
|
<CopyInput
|
||||||
:value="versionControlStore.state.sshKey"
|
:value="versionControlStore.preferences.publicKey"
|
||||||
:copy-button-text="locale.baseText('generic.clickToCopy')"
|
:copy-button-text="locale.baseText('generic.clickToCopy')"
|
||||||
/>
|
/>
|
||||||
<n8n-notice type="info" class="mt-s">
|
<n8n-notice type="info" class="mt-s">
|
||||||
|
@ -97,25 +104,70 @@ const goToUpgrade = () => {
|
||||||
</i18n>
|
</i18n>
|
||||||
</n8n-notice>
|
</n8n-notice>
|
||||||
</div>
|
</div>
|
||||||
<n8n-button v-if="sshKey" @click="onConnect" size="large" :class="$style.connect">{{
|
<n8n-button
|
||||||
locale.baseText('settings.versionControl.button.connect')
|
v-if="
|
||||||
}}</n8n-button>
|
versionControlStore.preferences.publicKey &&
|
||||||
<div v-if="versionControlStore.state.branches.length" :class="$style.group">
|
!versionControlStore.preferences.branches.length
|
||||||
|
"
|
||||||
|
@click="onConnect"
|
||||||
|
size="large"
|
||||||
|
:class="$style.connect"
|
||||||
|
>{{ locale.baseText('settings.versionControl.button.connect') }}</n8n-button
|
||||||
|
>
|
||||||
|
<div v-if="versionControlStore.preferences.branches.length">
|
||||||
|
<div :class="$style.group">
|
||||||
|
<hr />
|
||||||
|
<n8n-heading size="xlarge" tag="h2" class="mb-s">{{
|
||||||
|
locale.baseText('settings.versionControl.instanceSettings')
|
||||||
|
}}</n8n-heading>
|
||||||
<label>{{ locale.baseText('settings.versionControl.branches') }}</label>
|
<label>{{ locale.baseText('settings.versionControl.branches') }}</label>
|
||||||
<n8n-select
|
<n8n-select
|
||||||
ref="selectElement"
|
:value="versionControlStore.preferences.currentBranch"
|
||||||
:value="versionControlStore.state.currentBranch"
|
class="mb-s"
|
||||||
size="medium"
|
size="medium"
|
||||||
filterable
|
filterable
|
||||||
@input="onSelect"
|
@input="onSelect"
|
||||||
>
|
>
|
||||||
<n8n-option
|
<n8n-option
|
||||||
v-for="b in versionControlStore.state.branches"
|
v-for="b in versionControlStore.preferences.branches"
|
||||||
:key="b"
|
:key="b"
|
||||||
:value="b"
|
:value="b"
|
||||||
:label="b"
|
:label="b"
|
||||||
/>
|
/>
|
||||||
</n8n-select>
|
</n8n-select>
|
||||||
|
<n8n-checkbox
|
||||||
|
v-model="versionControlStore.preferences.branchReadOnly"
|
||||||
|
:class="$style.readOnly"
|
||||||
|
>
|
||||||
|
<i18n path="settings.versionControl.readonly">
|
||||||
|
<template #bold>
|
||||||
|
<strong>{{ locale.baseText('settings.versionControl.readonly.bold') }}</strong>
|
||||||
|
</template>
|
||||||
|
<template #link>
|
||||||
|
<a href="#" target="_blank">
|
||||||
|
{{ locale.baseText('settings.versionControl.readonly.link') }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</i18n>
|
||||||
|
</n8n-checkbox>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.group">
|
||||||
|
<label>{{ locale.baseText('settings.versionControl.color') }}</label>
|
||||||
|
<div>
|
||||||
|
<n8n-color-picker size="small" v-model="versionControlStore.preferences.branchColor" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div :class="[$style.group, 'pt-s']">
|
||||||
|
<n8n-button
|
||||||
|
v-if="
|
||||||
|
versionControlStore.preferences.publicKey &&
|
||||||
|
versionControlStore.preferences.currentBranch
|
||||||
|
"
|
||||||
|
@click="onSave"
|
||||||
|
size="large"
|
||||||
|
>{{ locale.baseText('settings.versionControl.button.save') }}</n8n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<n8n-action-box
|
<n8n-action-box
|
||||||
|
@ -135,7 +187,7 @@ const goToUpgrade = () => {
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.group {
|
.group {
|
||||||
padding: 0 0 var(--spacing-2xs);
|
padding: 0 0 var(--spacing-s);
|
||||||
|
|
||||||
label {
|
label {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -151,6 +203,28 @@ const goToUpgrade = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.readOnly {
|
||||||
|
span {
|
||||||
|
font-size: var(--font-size-s) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.groupFlex {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-left: var(--spacing-2xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.connect {
|
.connect {
|
||||||
margin: calc(var(--spacing-2xs) * -1) 0 var(--spacing-2xs);
|
margin: calc(var(--spacing-2xs) * -1) 0 var(--spacing-2xs);
|
||||||
}
|
}
|
||||||
|
@ -158,4 +232,9 @@ const goToUpgrade = () => {
|
||||||
.actionBox {
|
.actionBox {
|
||||||
margin: var(--spacing-2xl) 0 0;
|
margin: var(--spacing-2xl) 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 0 0 var(--spacing-xl);
|
||||||
|
border: 1px solid var(--color-foreground-light);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue