mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
fix(editor): Add Set up version control CTA (#6356)
* fix(editor): Add Set up version control CTA * fix(editor): add unit test * fix(editor): extend unit test * fix(editor): update menu sidebar styles * fix(editor): update menu sidebar styles * fix(editor): fixes after conflict * fix(editor): hide branch color when not connected * fix(editor): fix connected collapsed paddings
This commit is contained in:
parent
97295f67f0
commit
e72521d5ec
|
@ -193,9 +193,4 @@ export default defineComponent({
|
|||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.menuPrefix,
|
||||
.menuSuffix {
|
||||
padding: var(--spacing-xs) var(--spacing-l);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
v-if="!isCollapsed && userIsTrialing"
|
||||
/></template>
|
||||
<template #menuSuffix>
|
||||
<div v-if="hasVersionUpdates || versionControlStore.preferences.connected">
|
||||
<div>
|
||||
<div v-if="hasVersionUpdates" :class="$style.updates" @click="openUpdatesPanel">
|
||||
<div :class="$style.giftContainer">
|
||||
<GiftNotificationIcon />
|
||||
|
@ -46,10 +46,7 @@
|
|||
}}
|
||||
</n8n-text>
|
||||
</div>
|
||||
<MainSidebarVersionControl
|
||||
v-if="versionControlStore.preferences.connected"
|
||||
:is-collapsed="isCollapsed"
|
||||
/>
|
||||
<MainSidebarVersionControl :is-collapsed="isCollapsed" />
|
||||
</div>
|
||||
</template>
|
||||
<template #footer v-if="showUserArea">
|
||||
|
@ -115,15 +112,17 @@ import { userHelpers } from '@/mixins/userHelpers';
|
|||
import { debounceHelper } from '@/mixins/debounce';
|
||||
import Vue, { defineComponent } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useRootStore } from '@/stores/n8nRoot.store';
|
||||
import { useVersionsStore } from '@/stores/versions.store';
|
||||
import {
|
||||
useUIStore,
|
||||
useSettingsStore,
|
||||
useUsersStore,
|
||||
useWorkflowsStore,
|
||||
useRootStore,
|
||||
useVersionsStore,
|
||||
useCloudPlanStore,
|
||||
useVersionControlStore,
|
||||
} from '@/stores/';
|
||||
import { isNavigationFailure } from 'vue-router';
|
||||
import { useVersionControlStore } from '@/stores/versionControl.store';
|
||||
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
||||
import ExecutionsUsage from '@/components/ExecutionsUsage.vue';
|
||||
import MainSidebarVersionControl from '@/components/MainSidebarVersionControl.vue';
|
||||
|
||||
|
@ -155,8 +154,8 @@ export default defineComponent({
|
|||
useUsersStore,
|
||||
useVersionsStore,
|
||||
useWorkflowsStore,
|
||||
useVersionControlStore,
|
||||
useCloudPlanStore,
|
||||
useVersionControlStore,
|
||||
),
|
||||
hasVersionUpdates(): boolean {
|
||||
return this.versionsStore.hasVersionUpdates;
|
||||
|
@ -543,8 +542,9 @@ export default defineComponent({
|
|||
.updates {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 26px;
|
||||
cursor: pointer;
|
||||
padding: var(--spacing-2xs) var(--spacing-l);
|
||||
margin: var(--spacing-2xs) 0 0;
|
||||
|
||||
svg {
|
||||
color: var(--color-text-base) !important;
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
<script lang="ts" setup>
|
||||
import { useVersionControlStore } from '@/stores/versionControl.store';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n, useLoadingService, useMessage, useToast } from '@/composables';
|
||||
import { useUIStore } from '@/stores';
|
||||
import { VERSION_CONTROL_PUSH_MODAL_KEY } from '@/constants';
|
||||
import { useRouter } from 'vue-router/composables';
|
||||
import { createEventBus } from 'n8n-design-system/utils';
|
||||
import { useI18n, useLoadingService, useMessage, useToast } from '@/composables';
|
||||
import { useUIStore, useUsersStore, useVersionControlStore } from '@/stores';
|
||||
import { VERSION_CONTROL_PUSH_MODAL_KEY, VIEWS } from '@/constants';
|
||||
|
||||
const props = defineProps<{
|
||||
isCollapsed: boolean;
|
||||
}>();
|
||||
|
||||
const router = useRouter();
|
||||
const loadingService = useLoadingService();
|
||||
const uiStore = useUIStore();
|
||||
const versionControlStore = useVersionControlStore();
|
||||
const usersStore = useUsersStore();
|
||||
const message = useMessage();
|
||||
const toast = useToast();
|
||||
const { i18n } = useI18n();
|
||||
|
@ -24,6 +26,8 @@ const currentBranch = computed(() => {
|
|||
return versionControlStore.preferences.branchName;
|
||||
});
|
||||
|
||||
const setupButtonTooltipPlacement = computed(() => (props.isCollapsed ? 'right' : 'top'));
|
||||
|
||||
async function pushWorkfolder() {
|
||||
loadingService.startLoading();
|
||||
try {
|
||||
|
@ -68,76 +72,127 @@ async function pullWorkfolder() {
|
|||
loadingService.setLoadingText(i18n.baseText('genericHelpers.loading'));
|
||||
}
|
||||
}
|
||||
|
||||
const goToVersionControlSetup = async () => {
|
||||
await router.push({ name: VIEWS.VERSION_CONTROL });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="{ [$style.sync]: true, [$style.collapsed]: isCollapsed }"
|
||||
:class="{
|
||||
[$style.sync]: true,
|
||||
[$style.collapsed]: isCollapsed,
|
||||
[$style.isConnected]:
|
||||
versionControlStore.preferences.connected && versionControlStore.preferences.branchName,
|
||||
}"
|
||||
:style="{ borderLeftColor: versionControlStore.preferences.branchColor }"
|
||||
data-test-id="main-sidebar-version-control"
|
||||
>
|
||||
<span>
|
||||
<n8n-icon icon="code-branch" />
|
||||
{{ currentBranch }}
|
||||
</span>
|
||||
<div :class="{ 'pt-xs': !isCollapsed }">
|
||||
<n8n-tooltip :disabled="!isCollapsed" :open-delay="tooltipOpenDelay" placement="right">
|
||||
<template #content>
|
||||
<div>
|
||||
{{ i18n.baseText('settings.versionControl.button.pull') }}
|
||||
</div>
|
||||
</template>
|
||||
<n8n-button
|
||||
:class="{
|
||||
'mr-2xs': !isCollapsed,
|
||||
'mb-2xs': isCollapsed && !versionControlStore.preferences.branchReadOnly,
|
||||
}"
|
||||
icon="arrow-down"
|
||||
type="tertiary"
|
||||
size="mini"
|
||||
:square="isCollapsed"
|
||||
@click="pullWorkfolder"
|
||||
<div
|
||||
v-if="versionControlStore.preferences.connected && versionControlStore.preferences.branchName"
|
||||
:class="$style.connected"
|
||||
data-test-id="main-sidebar-version-control-connected"
|
||||
>
|
||||
<span>
|
||||
<n8n-icon icon="code-branch" />
|
||||
{{ currentBranch }}
|
||||
</span>
|
||||
<div :class="{ 'pt-xs': !isCollapsed }">
|
||||
<n8n-tooltip :disabled="!isCollapsed" :open-delay="tooltipOpenDelay" placement="right">
|
||||
<template #content>
|
||||
<div>
|
||||
{{ i18n.baseText('settings.versionControl.button.pull') }}
|
||||
</div>
|
||||
</template>
|
||||
<n8n-button
|
||||
:class="{
|
||||
'mr-2xs': !isCollapsed,
|
||||
'mb-2xs': isCollapsed && !versionControlStore.preferences.branchReadOnly,
|
||||
}"
|
||||
icon="arrow-down"
|
||||
type="tertiary"
|
||||
size="mini"
|
||||
:square="isCollapsed"
|
||||
@click="pullWorkfolder"
|
||||
>
|
||||
<span v-if="!isCollapsed">{{
|
||||
i18n.baseText('settings.versionControl.button.pull')
|
||||
}}</span>
|
||||
</n8n-button>
|
||||
</n8n-tooltip>
|
||||
<n8n-tooltip
|
||||
v-if="!versionControlStore.preferences.branchReadOnly"
|
||||
:disabled="!isCollapsed"
|
||||
:open-delay="tooltipOpenDelay"
|
||||
placement="right"
|
||||
>
|
||||
<span v-if="!isCollapsed">{{
|
||||
i18n.baseText('settings.versionControl.button.pull')
|
||||
}}</span>
|
||||
</n8n-button>
|
||||
</n8n-tooltip>
|
||||
<n8n-tooltip
|
||||
v-if="!versionControlStore.preferences.branchReadOnly"
|
||||
:disabled="!isCollapsed"
|
||||
:open-delay="tooltipOpenDelay"
|
||||
placement="right"
|
||||
>
|
||||
<template #content>
|
||||
<div>
|
||||
{{ i18n.baseText('settings.versionControl.button.push') }}
|
||||
</div>
|
||||
</template>
|
||||
<n8n-button
|
||||
:square="isCollapsed"
|
||||
icon="arrow-up"
|
||||
type="tertiary"
|
||||
size="mini"
|
||||
@click="pushWorkfolder"
|
||||
>
|
||||
<span v-if="!isCollapsed">{{
|
||||
i18n.baseText('settings.versionControl.button.push')
|
||||
}}</span>
|
||||
</n8n-button>
|
||||
</n8n-tooltip>
|
||||
<template #content>
|
||||
<div>
|
||||
{{ i18n.baseText('settings.versionControl.button.push') }}
|
||||
</div>
|
||||
</template>
|
||||
<n8n-button
|
||||
:square="isCollapsed"
|
||||
icon="arrow-up"
|
||||
type="tertiary"
|
||||
size="mini"
|
||||
@click="pushWorkfolder"
|
||||
>
|
||||
<span v-if="!isCollapsed">{{
|
||||
i18n.baseText('settings.versionControl.button.push')
|
||||
}}</span>
|
||||
</n8n-button>
|
||||
</n8n-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<n8n-tooltip
|
||||
v-else-if="
|
||||
versionControlStore.isEnterpriseVersionControlEnabled && usersStore.isInstanceOwner
|
||||
"
|
||||
:open-delay="tooltipOpenDelay"
|
||||
:placement="setupButtonTooltipPlacement"
|
||||
data-test-id="main-sidebar-version-control-setup"
|
||||
>
|
||||
<template #content>
|
||||
<div>
|
||||
{{ i18n.baseText('settings.versionControl.button.setup.tooltip') }}
|
||||
</div>
|
||||
</template>
|
||||
<n8n-button
|
||||
icon="code-branch"
|
||||
type="tertiary"
|
||||
size="mini"
|
||||
:square="isCollapsed"
|
||||
@click="goToVersionControlSetup"
|
||||
>
|
||||
<span v-if="!isCollapsed">{{ i18n.baseText('settings.versionControl.button.setup') }}</span>
|
||||
</n8n-button>
|
||||
</n8n-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
.sync {
|
||||
padding: var(--spacing-s) var(--spacing-s) var(--spacing-s) var(--spacing-m);
|
||||
margin: 0 calc(var(--spacing-l) * -1) calc(var(--spacing-m) * -1);
|
||||
padding: var(--spacing-s) var(--spacing-s) var(--spacing-s) var(--spacing-l);
|
||||
margin: var(--spacing-2xs) 0 calc(var(--spacing-2xs) * -1);
|
||||
background: var(--color-background-light);
|
||||
border-top: var(--border-width-base) var(--border-style-base) var(--color-foreground-base);
|
||||
border-left: var(--spacing-3xs) var(--border-style-base) var(--color-foreground-base);
|
||||
font-size: var(--font-size-2xs);
|
||||
|
||||
&.isConnected {
|
||||
padding-left: var(--spacing-m);
|
||||
border-left: var(--spacing-3xs) var(--border-style-base) var(--color-foreground-base);
|
||||
|
||||
&.collapsed {
|
||||
padding-left: var(--spacing-xs);
|
||||
}
|
||||
}
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
span {
|
||||
color: var(--color-text-base);
|
||||
}
|
||||
|
@ -149,10 +204,13 @@ async function pullWorkfolder() {
|
|||
|
||||
.collapsed {
|
||||
text-align: center;
|
||||
padding-left: var(--spacing-xs);
|
||||
padding-left: var(--spacing-s);
|
||||
padding-right: var(--spacing-s);
|
||||
|
||||
> span {
|
||||
display: none;
|
||||
.connected {
|
||||
> span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -246,8 +246,11 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
.versionContainer {
|
||||
padding: var(--spacing-xs) var(--spacing-l);
|
||||
}
|
||||
|
||||
@media screen and (max-height: 420px) {
|
||||
.updatesSubmenu,
|
||||
.versionContainer {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render } from '@testing-library/vue';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { STORES } from '@/constants';
|
||||
import { i18nInstance } from '@/plugins/i18n';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
import MainSidebarVersionControl from '@/components/MainSidebarVersionControl.vue';
|
||||
import { useUsersStore, useVersionControlStore } from '@/stores';
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
let pinia: ReturnType<typeof createTestingPinia>;
|
||||
let versionControlStore: ReturnType<typeof useVersionControlStore>;
|
||||
let usersStore: ReturnType<typeof useUsersStore>;
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) => {
|
||||
return render(
|
||||
MainSidebarVersionControl,
|
||||
{
|
||||
pinia,
|
||||
i18n: i18nInstance,
|
||||
...renderOptions,
|
||||
},
|
||||
(vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
describe('MainSidebarVersionControl', () => {
|
||||
beforeEach(() => {
|
||||
pinia = createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
versionControlStore = useVersionControlStore();
|
||||
usersStore = useUsersStore();
|
||||
});
|
||||
|
||||
it('should render empty content', async () => {
|
||||
const { getByTestId } = renderComponent({ props: { isCollapsed: false } });
|
||||
expect(getByTestId('main-sidebar-version-control')).toBeInTheDocument();
|
||||
expect(getByTestId('main-sidebar-version-control')).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('should render setup content', async () => {
|
||||
vi.spyOn(versionControlStore, 'isEnterpriseVersionControlEnabled', 'get').mockReturnValue(true);
|
||||
vi.spyOn(usersStore, 'isInstanceOwner', 'get').mockReturnValue(true);
|
||||
|
||||
const { getByTestId, queryByTestId } = renderComponent({ props: { isCollapsed: false } });
|
||||
expect(getByTestId('main-sidebar-version-control-setup')).toBeInTheDocument();
|
||||
expect(queryByTestId('main-sidebar-version-control-connected')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render connected content', async () => {
|
||||
vi.spyOn(versionControlStore, 'preferences', 'get').mockReturnValue({
|
||||
branchName: 'main',
|
||||
branches: [],
|
||||
authorName: '',
|
||||
authorEmail: '',
|
||||
repositoryUrl: '',
|
||||
branchReadOnly: false,
|
||||
branchColor: '#F4A6DC',
|
||||
connected: true,
|
||||
publicKey: '',
|
||||
});
|
||||
|
||||
const { getByTestId, queryByTestId } = renderComponent({ props: { isCollapsed: false } });
|
||||
expect(getByTestId('main-sidebar-version-control-connected')).toBeInTheDocument();
|
||||
expect(queryByTestId('main-sidebar-version-control-setup')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -1365,6 +1365,8 @@
|
|||
"settings.versionControl.sync.prompt.error": "Please enter a commit message",
|
||||
"settings.versionControl.button.push": "Push",
|
||||
"settings.versionControl.button.pull": "Pull",
|
||||
"settings.versionControl.button.setup": "Set up version control",
|
||||
"settings.versionControl.button.setup.tooltip": "You have version control enabled. Go to the settings page to connect to your Git repository.",
|
||||
"settings.versionControl.modals.push.title": "Commit and push changes",
|
||||
"settings.versionControl.modals.push.description": "Select the files you want to stage in your commit and add a commit message. ",
|
||||
"settings.versionControl.modals.push.description.workflows": "Since you are on the Workflows page, the modified workflow files have been pre-selected for you.",
|
||||
|
|
Loading…
Reference in a new issue