refactor(editor): Apply Prettier (no-changelog) (#4920)
* ⚡ Adjust `format` script * 🔥 Remove exemption for `editor-ui` * 🎨 Prettify * 👕 Fix lint
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div :class="$style.container">
|
||||
<div :class="$style.logoContainer">
|
||||
<Logo />
|
||||
<Logo />
|
||||
</div>
|
||||
<div v-if="subtitle" :class="$style.textContainer">
|
||||
<n8n-text size="large">{{subtitle}}</n8n-text>
|
||||
<n8n-text size="large">{{ subtitle }}</n8n-text>
|
||||
</div>
|
||||
<div :class="$style.formContainer">
|
||||
<n8n-form-box
|
||||
@@ -30,8 +30,7 @@ export default Vue.extend({
|
||||
Logo,
|
||||
},
|
||||
props: {
|
||||
form: {
|
||||
},
|
||||
form: {},
|
||||
formLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -41,10 +40,10 @@ export default Vue.extend({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onInput(e: {name: string, value: string}) {
|
||||
onInput(e: { name: string; value: string }) {
|
||||
this.$emit('input', e);
|
||||
},
|
||||
onSubmit(values: {[key: string]: string}) {
|
||||
onSubmit(values: { [key: string]: string }) {
|
||||
this.$emit('submit', values);
|
||||
},
|
||||
onSecondaryClick() {
|
||||
@@ -86,9 +85,7 @@ body {
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.el-checkbox__label span {
|
||||
font-size: var(--font-size-2xs) !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
<template>
|
||||
<div :class="$style.container" :style="containerCssVars" ref="container" data-test-id="canvas-add-button">
|
||||
<n8n-tooltip placement="top" :value="showTooltip" manual :disabled="nodeCreatorStore.showScrim" :popper-class="$style.tooltip" :open-delay="700">
|
||||
<div
|
||||
:class="$style.container"
|
||||
:style="containerCssVars"
|
||||
ref="container"
|
||||
data-test-id="canvas-add-button"
|
||||
>
|
||||
<n8n-tooltip
|
||||
placement="top"
|
||||
:value="showTooltip"
|
||||
manual
|
||||
:disabled="nodeCreatorStore.showScrim"
|
||||
:popper-class="$style.tooltip"
|
||||
:open-delay="700"
|
||||
>
|
||||
<button :class="$style.button" @click="$emit('click')" data-test-id="canvas-plus-button">
|
||||
<font-awesome-icon icon="plus" size="lg" />
|
||||
</button>
|
||||
@@ -47,7 +59,7 @@ const containerCssVars = computed(() => ({
|
||||
z-index: 101;
|
||||
|
||||
&:hover .button svg path {
|
||||
fill: var(--color-primary)
|
||||
fill: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +77,7 @@ const containerCssVars = computed(() => ({
|
||||
width: 26px !important;
|
||||
height: 40px;
|
||||
path {
|
||||
fill: var(--color-foreground-xdark)
|
||||
fill: var(--color-foreground-xdark);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +90,7 @@ const containerCssVars = computed(() => ({
|
||||
width: max-content;
|
||||
font-weight: var(--font-weight-bold);
|
||||
font-size: var(--font-size-m);
|
||||
line-height: var(--font-line-height-xloose );
|
||||
line-height: var(--font-line-height-xloose);
|
||||
color: var(--color-text-dark);
|
||||
margin-top: var(--spacing-2xs);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ import { VIEWS } from '@/constants';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'ChangePasswordView',
|
||||
components: {
|
||||
AuthView,
|
||||
@@ -48,7 +46,7 @@ export default mixins(
|
||||
label: this.$locale.baseText('auth.newPassword'),
|
||||
type: 'password',
|
||||
required: true,
|
||||
validationRules: [{name: 'DEFAULT_PASSWORD_RULES'}],
|
||||
validationRules: [{ name: 'DEFAULT_PASSWORD_RULES' }],
|
||||
infoText: this.$locale.baseText('auth.defaultPasswordRequirements'),
|
||||
autocomplete: 'new-password',
|
||||
capitalize: true,
|
||||
@@ -65,15 +63,21 @@ export default mixins(
|
||||
validate: this.passwordsMatch,
|
||||
},
|
||||
},
|
||||
validationRules: [{name: 'TWO_PASSWORDS_MATCH'}],
|
||||
validationRules: [{ name: 'TWO_PASSWORDS_MATCH' }],
|
||||
autocomplete: 'new-password',
|
||||
capitalize: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const token = (!this.$route.query.token || typeof this.$route.query.token !== 'string') ? null : this.$route.query.token;
|
||||
const userId = (!this.$route.query.userId || typeof this.$route.query.userId !== 'string') ? null : this.$route.query.userId;
|
||||
const token =
|
||||
!this.$route.query.token || typeof this.$route.query.token !== 'string'
|
||||
? null
|
||||
: this.$route.query.token;
|
||||
const userId =
|
||||
!this.$route.query.userId || typeof this.$route.query.userId !== 'string'
|
||||
? null
|
||||
: this.$route.query.userId;
|
||||
try {
|
||||
if (!token) {
|
||||
throw new Error(this.$locale.baseText('auth.changePassword.missingTokenError'));
|
||||
@@ -84,7 +88,10 @@ export default mixins(
|
||||
|
||||
await this.usersStore.validatePasswordToken({ token, userId });
|
||||
} catch (e) {
|
||||
this.$showMessage({title: this.$locale.baseText('auth.changePassword.tokenValidationError'), type: 'error'});
|
||||
this.$showMessage({
|
||||
title: this.$locale.baseText('auth.changePassword.tokenValidationError'),
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -101,7 +108,7 @@ export default mixins(
|
||||
|
||||
return false;
|
||||
},
|
||||
onInput(e: {name: string, value: string}) {
|
||||
onInput(e: { name: string; value: string }) {
|
||||
if (e.name === 'password') {
|
||||
this.password = e.value;
|
||||
}
|
||||
@@ -109,11 +116,17 @@ export default mixins(
|
||||
async onSubmit() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const token = (!this.$route.query.token || typeof this.$route.query.token !== 'string') ? null : this.$route.query.token;
|
||||
const userId = (!this.$route.query.userId || typeof this.$route.query.userId !== 'string') ? null : this.$route.query.userId;
|
||||
const token =
|
||||
!this.$route.query.token || typeof this.$route.query.token !== 'string'
|
||||
? null
|
||||
: this.$route.query.token;
|
||||
const userId =
|
||||
!this.$route.query.userId || typeof this.$route.query.userId !== 'string'
|
||||
? null
|
||||
: this.$route.query.userId;
|
||||
|
||||
if (token && userId) {
|
||||
await this.usersStore.changePassword({token, userId, password: this.password});
|
||||
await this.usersStore.changePassword({ token, userId, password: this.password });
|
||||
|
||||
this.$showMessage({
|
||||
type: 'success',
|
||||
@@ -123,7 +136,10 @@ export default mixins(
|
||||
|
||||
await this.$router.push({ name: VIEWS.SIGNIN });
|
||||
} else {
|
||||
this.$showError(new Error(this.$locale.baseText('auth.validation.missingParameters')), this.$locale.baseText('auth.changePassword.error'));
|
||||
this.$showError(
|
||||
new Error(this.$locale.baseText('auth.validation.missingParameters')),
|
||||
this.$locale.baseText('auth.changePassword.error'),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('auth.changePassword.error'));
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
@update:filters="filters = $event"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<credential-card :data="data"/>
|
||||
<credential-card :data="data" />
|
||||
</template>
|
||||
<template #filters="{ setKeyValue }">
|
||||
<div class="mb-s">
|
||||
@@ -43,22 +43,22 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {showMessage} from '@/mixins/showMessage';
|
||||
import {ICredentialsResponse, ICredentialTypeMap, IUser} from '@/Interface';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import { ICredentialsResponse, ICredentialTypeMap, IUser } from '@/Interface';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
|
||||
import SettingsView from './SettingsView.vue';
|
||||
import ResourcesListLayout from "@/components/layouts/ResourcesListLayout.vue";
|
||||
import PageViewLayout from "@/components/layouts/PageViewLayout.vue";
|
||||
import PageViewLayoutList from "@/components/layouts/PageViewLayoutList.vue";
|
||||
import CredentialCard from "@/components/CredentialCard.vue";
|
||||
import {ICredentialType} from "n8n-workflow";
|
||||
import TemplateCard from "@/components/TemplateCard.vue";
|
||||
import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue';
|
||||
import PageViewLayout from '@/components/layouts/PageViewLayout.vue';
|
||||
import PageViewLayoutList from '@/components/layouts/PageViewLayoutList.vue';
|
||||
import CredentialCard from '@/components/CredentialCard.vue';
|
||||
import { ICredentialType } from 'n8n-workflow';
|
||||
import TemplateCard from '@/components/TemplateCard.vue';
|
||||
import { debounceHelper } from '@/mixins/debounce';
|
||||
import ResourceOwnershipSelect from "@/components/forms/ResourceOwnershipSelect.ee.vue";
|
||||
import ResourceFiltersDropdown from "@/components/forms/ResourceFiltersDropdown.vue";
|
||||
import {CREDENTIAL_SELECT_MODAL_KEY} from '@/constants';
|
||||
import Vue from "vue";
|
||||
import ResourceOwnershipSelect from '@/components/forms/ResourceOwnershipSelect.ee.vue';
|
||||
import ResourceFiltersDropdown from '@/components/forms/ResourceFiltersDropdown.vue';
|
||||
import { CREDENTIAL_SELECT_MODAL_KEY } from '@/constants';
|
||||
import Vue from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
@@ -67,10 +67,7 @@ import { useCredentialsStore } from '@/stores/credentials';
|
||||
|
||||
type IResourcesListLayoutInstance = Vue & { sendFiltersTelemetry: (source: string) => void };
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
debounceHelper,
|
||||
).extend({
|
||||
export default mixins(showMessage, debounceHelper).extend({
|
||||
name: 'SettingsPersonalView',
|
||||
components: {
|
||||
ResourcesListLayout,
|
||||
@@ -93,12 +90,7 @@ export default mixins(
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useCredentialsStore,
|
||||
useNodeTypesStore,
|
||||
useUIStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useCredentialsStore, useNodeTypesStore, useUIStore, useUsersStore),
|
||||
allCredentials(): ICredentialsResponse[] {
|
||||
return this.credentialsStore.allCredentials;
|
||||
},
|
||||
@@ -118,7 +110,6 @@ export default mixins(
|
||||
});
|
||||
},
|
||||
async initialize() {
|
||||
|
||||
const loadPromises = [
|
||||
this.credentialsStore.fetchAllCredentials(),
|
||||
this.credentialsStore.fetchCredentialTypes(false),
|
||||
@@ -132,7 +123,11 @@ export default mixins(
|
||||
|
||||
this.usersStore.fetchUsers(); // Can be loaded in the background, used for filtering
|
||||
},
|
||||
onFilter(resource: ICredentialsResponse, filters: { type: string[]; search: string; }, matches: boolean): boolean {
|
||||
onFilter(
|
||||
resource: ICredentialsResponse,
|
||||
filters: { type: string[]; search: string },
|
||||
matches: boolean,
|
||||
): boolean {
|
||||
if (filters.type.length > 0) {
|
||||
matches = matches && filters.type.includes(resource.type);
|
||||
}
|
||||
@@ -140,9 +135,12 @@ export default mixins(
|
||||
if (filters.search) {
|
||||
const searchString = filters.search.toLowerCase();
|
||||
|
||||
matches = matches || (
|
||||
this.credentialTypesById[resource.type] && this.credentialTypesById[resource.type].displayName.toLowerCase().includes(searchString)
|
||||
);
|
||||
matches =
|
||||
matches ||
|
||||
(this.credentialTypesById[resource.type] &&
|
||||
this.credentialTypesById[resource.type].displayName
|
||||
.toLowerCase()
|
||||
.includes(searchString));
|
||||
}
|
||||
|
||||
return matches;
|
||||
@@ -168,4 +166,3 @@ export default mixins(
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -9,14 +9,11 @@
|
||||
</div>
|
||||
<div>
|
||||
<n8n-text size="large" v-if="errorCode">
|
||||
{{errorCode}} {{ $locale.baseText('error') }}
|
||||
{{ errorCode }} {{ $locale.baseText('error') }}
|
||||
</n8n-text>
|
||||
</div>
|
||||
</div>
|
||||
<n8n-button
|
||||
:label="$locale.baseText(redirectTextKey)"
|
||||
@click="onButtonClick"
|
||||
/>
|
||||
<n8n-button :label="$locale.baseText(redirectTextKey)" @click="onButtonClick" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<AuthView
|
||||
:form="formConfig"
|
||||
:formLoading="loading"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
<AuthView :form="formConfig" :formLoading="loading" @submit="onSubmit" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -16,9 +12,7 @@ import { mapStores } from 'pinia';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'ForgotMyPasswordView',
|
||||
components: {
|
||||
AuthView,
|
||||
@@ -29,10 +23,7 @@ export default mixins(
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useSettingsStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useSettingsStore, useUsersStore),
|
||||
formConfig(): IFormBoxConfig {
|
||||
const EMAIL_INPUTS: IFormBoxConfig['inputs'] = [
|
||||
{
|
||||
@@ -41,7 +32,7 @@ export default mixins(
|
||||
label: this.$locale.baseText('auth.email'),
|
||||
type: 'email',
|
||||
required: true,
|
||||
validationRules: [{name: 'VALID_EMAIL'}],
|
||||
validationRules: [{ name: 'VALID_EMAIL' }],
|
||||
autocomplete: 'email',
|
||||
capitalize: true,
|
||||
},
|
||||
@@ -86,10 +77,9 @@ export default mixins(
|
||||
this.$showMessage({
|
||||
type: 'success',
|
||||
title: this.$locale.baseText('forgotPassword.recoveryEmailSent'),
|
||||
message: this.$locale.baseText(
|
||||
'forgotPassword.emailSentIfExists',
|
||||
{ interpolate: { email: values.email }},
|
||||
),
|
||||
message: this.$locale.baseText('forgotPassword.emailSentIfExists', {
|
||||
interpolate: { email: values.email },
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
this.$showMessage({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="$style.wrapper" data-test-id="node-view-loader">
|
||||
<div :class="$style.wrapper" data-test-id="node-view-loader">
|
||||
<div :class="$style.spinner">
|
||||
<n8n-spinner />
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
<div :class="$style.header">
|
||||
<n8n-heading size="2xlarge">
|
||||
{{ $locale.baseText('settings.api') }}
|
||||
<span :style="{ fontSize: 'var(--font-size-s)', color: 'var(--color-text-light)', }">
|
||||
<span :style="{ fontSize: 'var(--font-size-s)', color: 'var(--color-text-light)' }">
|
||||
({{ $locale.baseText('beta') }})
|
||||
</span>
|
||||
</n8n-heading>
|
||||
@@ -57,7 +57,11 @@
|
||||
</div>
|
||||
<n8n-action-box
|
||||
v-else-if="mounted"
|
||||
:buttonText="$locale.baseText(loading ? 'settings.api.create.button.loading' : 'settings.api.create.button')"
|
||||
:buttonText="
|
||||
$locale.baseText(
|
||||
loading ? 'settings.api.create.button.loading' : 'settings.api.create.button',
|
||||
)
|
||||
"
|
||||
:description="$locale.baseText('settings.api.create.description')"
|
||||
@click="createApiKey"
|
||||
/>
|
||||
@@ -75,9 +79,7 @@ import { useSettingsStore } from '@/stores/settings';
|
||||
import { useRootStore } from '@/stores/n8nRootStore';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'SettingsPersonalView',
|
||||
components: {
|
||||
CopyInput,
|
||||
@@ -98,11 +100,7 @@ export default mixins(
|
||||
this.apiPlaygroundPath = `${baseUrl}${apiPath}/v${latestVersion}/docs`;
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useRootStore,
|
||||
useSettingsStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useRootStore, useSettingsStore, useUsersStore),
|
||||
currentUser(): IUser | null {
|
||||
return this.usersStore.currentUser;
|
||||
},
|
||||
@@ -122,7 +120,7 @@ export default mixins(
|
||||
},
|
||||
async getApiKey() {
|
||||
try {
|
||||
this.apiKey = await this.settingsStore.getApiKey() || '';
|
||||
this.apiKey = (await this.settingsStore.getApiKey()) || '';
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('settings.api.view.error'));
|
||||
} finally {
|
||||
@@ -133,7 +131,7 @@ export default mixins(
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
this.apiKey = await this.settingsStore.createApiKey() || '';
|
||||
this.apiKey = (await this.settingsStore.createApiKey()) || '';
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('settings.api.create.error'));
|
||||
} finally {
|
||||
@@ -144,7 +142,10 @@ export default mixins(
|
||||
async deleteApiKey() {
|
||||
try {
|
||||
await this.settingsStore.deleteApiKey();
|
||||
this.$showMessage({ title: this.$locale.baseText("settings.api.delete.toast"), type: 'success' });
|
||||
this.$showMessage({
|
||||
title: this.$locale.baseText('settings.api.delete.toast'),
|
||||
type: 'success',
|
||||
});
|
||||
this.apiKey = '';
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('settings.api.delete.error'));
|
||||
@@ -191,4 +192,3 @@ export default mixins(
|
||||
color: var(--color-text-light);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
<div :class="$style.headingContainer">
|
||||
<n8n-heading size="2xlarge">{{ $locale.baseText('settings.communityNodes') }}</n8n-heading>
|
||||
<n8n-button
|
||||
v-if="!settingsStore.isQueueModeEnabled && communityNodesStore.getInstalledPackages.length > 0 && !loading"
|
||||
v-if="
|
||||
!settingsStore.isQueueModeEnabled &&
|
||||
communityNodesStore.getInstalledPackages.length > 0 &&
|
||||
!loading
|
||||
"
|
||||
:label="$locale.baseText('settings.communityNodes.installModal.installButton.label')"
|
||||
size="large"
|
||||
@click="openInstallModal"
|
||||
@@ -17,10 +21,7 @@
|
||||
:calloutTheme="actionBoxConfig.calloutTheme"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
:class="$style.cardsContainer"
|
||||
v-else-if="loading"
|
||||
>
|
||||
<div :class="$style.cardsContainer" v-else-if="loading">
|
||||
<community-package-card
|
||||
v-for="n in 2"
|
||||
:key="'index-' + n"
|
||||
@@ -44,10 +45,7 @@
|
||||
@click="openInstallModal"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
:class="$style.cardsContainer"
|
||||
v-else
|
||||
>
|
||||
<div :class="$style.cardsContainer" v-else>
|
||||
<community-package-card
|
||||
v-for="communityPackage in communityNodesStore.getInstalledPackages"
|
||||
:key="communityPackage.packageName"
|
||||
@@ -75,14 +73,12 @@ import { useSettingsStore } from '@/stores/settings';
|
||||
|
||||
const PACKAGE_COUNT_THRESHOLD = 31;
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'SettingsCommunityNodesView',
|
||||
components: {
|
||||
CommunityPackageCard,
|
||||
},
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
};
|
||||
@@ -92,19 +88,22 @@ export default mixins(
|
||||
this.$data.loading = true;
|
||||
await this.communityNodesStore.fetchInstalledPackages();
|
||||
|
||||
const installedPackages: PublicInstalledPackage[] = this.communityNodesStore.getInstalledPackages;
|
||||
const packagesToUpdate: PublicInstalledPackage[] = installedPackages.filter(p => p.updateAvailable );
|
||||
const installedPackages: PublicInstalledPackage[] =
|
||||
this.communityNodesStore.getInstalledPackages;
|
||||
const packagesToUpdate: PublicInstalledPackage[] = installedPackages.filter(
|
||||
(p) => p.updateAvailable,
|
||||
);
|
||||
this.$telemetry.track('user viewed cnr settings page', {
|
||||
num_of_packages_installed: installedPackages.length,
|
||||
installed_packages: installedPackages.map(p => {
|
||||
installed_packages: installedPackages.map((p) => {
|
||||
return {
|
||||
package_name: p.packageName,
|
||||
package_version: p.installedVersion,
|
||||
package_nodes: p.installedNodes.map(node => `${node.name}-v${node.latestVersion}`),
|
||||
package_nodes: p.installedNodes.map((node) => `${node.name}-v${node.latestVersion}`),
|
||||
is_update_available: p.updateAvailable !== undefined,
|
||||
};
|
||||
}),
|
||||
packages_to_update: packagesToUpdate.map(p => {
|
||||
packages_to_update: packagesToUpdate.map((p) => {
|
||||
return {
|
||||
package_name: p.packageName,
|
||||
package_version_current: p.installedVersion,
|
||||
@@ -129,25 +128,21 @@ export default mixins(
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useCommunityNodesStore,
|
||||
useSettingsStore,
|
||||
useUIStore,
|
||||
),
|
||||
...mapStores(useCommunityNodesStore, useSettingsStore, useUIStore),
|
||||
getEmptyStateDescription() {
|
||||
const packageCount = this.communityNodesStore.availablePackageCount;
|
||||
return packageCount < PACKAGE_COUNT_THRESHOLD ?
|
||||
this.$locale.baseText('settings.communityNodes.empty.description.no-packages', {
|
||||
interpolate: {
|
||||
docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
},
|
||||
}) :
|
||||
this.$locale.baseText('settings.communityNodes.empty.description', {
|
||||
interpolate: {
|
||||
docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
count: (Math.floor(packageCount / 10) * 10).toString(),
|
||||
},
|
||||
});
|
||||
return packageCount < PACKAGE_COUNT_THRESHOLD
|
||||
? this.$locale.baseText('settings.communityNodes.empty.description.no-packages', {
|
||||
interpolate: {
|
||||
docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
},
|
||||
})
|
||||
: this.$locale.baseText('settings.communityNodes.empty.description', {
|
||||
interpolate: {
|
||||
docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
count: (Math.floor(packageCount / 10) * 10).toString(),
|
||||
},
|
||||
});
|
||||
},
|
||||
shouldShowInstallButton() {
|
||||
return !this.settingsStore.isDesktopDeployment && this.settingsStore.isNpmAvailable;
|
||||
@@ -163,10 +158,9 @@ export default mixins(
|
||||
|
||||
if (!this.settingsStore.isNpmAvailable) {
|
||||
return {
|
||||
calloutText: this.$locale.baseText(
|
||||
'settings.communityNodes.npmUnavailable.warning',
|
||||
{ interpolate: { npmUrl: COMMUNITY_NODES_NPM_INSTALLATION_URL } },
|
||||
),
|
||||
calloutText: this.$locale.baseText('settings.communityNodes.npmUnavailable.warning', {
|
||||
interpolate: { npmUrl: COMMUNITY_NODES_NPM_INSTALLATION_URL },
|
||||
}),
|
||||
calloutTheme: 'warning',
|
||||
hideButton: true,
|
||||
};
|
||||
@@ -174,10 +168,9 @@ export default mixins(
|
||||
|
||||
if (this.settingsStore.isQueueModeEnabled) {
|
||||
return {
|
||||
calloutText: this.$locale.baseText(
|
||||
'settings.communityNodes.queueMode.warning',
|
||||
{ interpolate: { docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL } },
|
||||
),
|
||||
calloutText: this.$locale.baseText('settings.communityNodes.queueMode.warning', {
|
||||
interpolate: { docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL },
|
||||
}),
|
||||
calloutTheme: 'warning',
|
||||
hideButton: true,
|
||||
};
|
||||
@@ -192,7 +185,9 @@ export default mixins(
|
||||
},
|
||||
methods: {
|
||||
openInstallModal(event: MouseEvent) {
|
||||
const telemetryPayload = { is_empty_state: this.communityNodesStore.getInstalledPackages.length === 0 };
|
||||
const telemetryPayload = {
|
||||
is_empty_state: this.communityNodesStore.getInstalledPackages.length === 0,
|
||||
};
|
||||
this.$telemetry.track('user clicked cnr install button', telemetryPayload);
|
||||
this.$externalHooks().run('settingsCommunityNodesView.openInstallModal', telemetryPayload);
|
||||
this.uiStore.openModal(COMMUNITY_PACKAGE_INSTALL_MODAL_KEY);
|
||||
@@ -202,31 +197,31 @@ export default mixins(
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.container {
|
||||
height: 100%;
|
||||
padding-right: var(--spacing-2xs);
|
||||
> * {
|
||||
margin-bottom: var(--spacing-2xl);
|
||||
}
|
||||
.container {
|
||||
height: 100%;
|
||||
padding-right: var(--spacing-2xs);
|
||||
> * {
|
||||
margin-bottom: var(--spacing-2xl);
|
||||
}
|
||||
}
|
||||
|
||||
.headingContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.headingContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.loadingContainer {
|
||||
display: flex;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
.loadingContainer {
|
||||
display: flex;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.actionBoxContainer {
|
||||
text-align: center;
|
||||
}
|
||||
.actionBoxContainer {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cardsContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-2xs);
|
||||
}
|
||||
.cardsContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-2xs);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default Vue.extend({
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useUIStore),
|
||||
featureInfo(): IFakeDoor|undefined {
|
||||
featureInfo(): IFakeDoor | undefined {
|
||||
return this.uiStore.getFakeDoorById(this.featureId);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<template>
|
||||
<div :class="$style.container">
|
||||
<div :class="$style.header">
|
||||
<n8n-heading size="2xlarge">{{ $locale.baseText('settings.personal.personalSettings') }}</n8n-heading>
|
||||
<n8n-heading size="2xlarge">{{
|
||||
$locale.baseText('settings.personal.personalSettings')
|
||||
}}</n8n-heading>
|
||||
<div class="ph-no-capture" :class="$style.user">
|
||||
<span :class="$style.username">
|
||||
<n8n-text color="text-light">{{currentUser.fullName}}</n8n-text>
|
||||
<n8n-text color="text-light">{{ currentUser.fullName }}</n8n-text>
|
||||
</span>
|
||||
<n8n-avatar :firstName="currentUser.firstName" :lastName="currentUser.lastName" size="large" />
|
||||
<n8n-avatar
|
||||
:firstName="currentUser.firstName"
|
||||
:lastName="currentUser.lastName"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div :class="$style.sectionHeader">
|
||||
<n8n-heading size="large">{{ $locale.baseText('settings.personal.basicInformation') }}</n8n-heading>
|
||||
<n8n-heading size="large">{{
|
||||
$locale.baseText('settings.personal.basicInformation')
|
||||
}}</n8n-heading>
|
||||
</div>
|
||||
<div>
|
||||
<n8n-form-inputs
|
||||
@@ -30,15 +38,22 @@
|
||||
</div>
|
||||
<div>
|
||||
<n8n-input-label :label="$locale.baseText('auth.password')">
|
||||
<n8n-link @click="openPasswordModal">{{ $locale.baseText('auth.changePassword') }}</n8n-link>
|
||||
<n8n-link @click="openPasswordModal">{{
|
||||
$locale.baseText('auth.changePassword')
|
||||
}}</n8n-link>
|
||||
</n8n-input-label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<n8n-button float="right" :label="$locale.baseText('settings.personal.save')" size="large" :disabled="!hasAnyChanges || !readyToSubmit" @click="onSaveClick" />
|
||||
<n8n-button
|
||||
float="right"
|
||||
:label="$locale.baseText('settings.personal.save')"
|
||||
size="large"
|
||||
:disabled="!hasAnyChanges || !readyToSubmit"
|
||||
@click="onSaveClick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -51,9 +66,7 @@ import { mapStores } from 'pinia';
|
||||
import Vue from 'vue';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'SettingsPersonalView',
|
||||
data() {
|
||||
return {
|
||||
@@ -94,7 +107,7 @@ export default mixins(
|
||||
label: this.$locale.baseText('auth.email'),
|
||||
type: 'email',
|
||||
required: true,
|
||||
validationRules: [{name: 'VALID_EMAIL'}],
|
||||
validationRules: [{ name: 'VALID_EMAIL' }],
|
||||
autocomplete: 'email',
|
||||
capitalize: true,
|
||||
},
|
||||
@@ -102,10 +115,7 @@ export default mixins(
|
||||
];
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useUIStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useUIStore, useUsersStore),
|
||||
currentUser(): IUser | null {
|
||||
return this.usersStore.currentUser;
|
||||
},
|
||||
@@ -117,7 +127,7 @@ export default mixins(
|
||||
onReadyToSubmit(ready: boolean) {
|
||||
this.readyToSubmit = ready;
|
||||
},
|
||||
async onSubmit(form: {firstName: string, lastName: string, email: string}) {
|
||||
async onSubmit(form: { firstName: string; lastName: string; email: string }) {
|
||||
if (!this.hasAnyChanges || !this.usersStore.currentUserId) {
|
||||
return;
|
||||
}
|
||||
@@ -134,8 +144,7 @@ export default mixins(
|
||||
type: 'success',
|
||||
});
|
||||
this.hasAnyChanges = false;
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
this.$showError(e, this.$locale.baseText('settings.personal.personalSettingsUpdatedError'));
|
||||
}
|
||||
},
|
||||
@@ -176,7 +185,6 @@ export default mixins(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.username {
|
||||
margin-right: var(--spacing-s);
|
||||
text-align: right;
|
||||
@@ -192,4 +200,3 @@ export default mixins(
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -3,22 +3,27 @@
|
||||
<div>
|
||||
<n8n-heading size="2xlarge">{{ $locale.baseText('settings.users') }}</n8n-heading>
|
||||
<div :class="$style.buttonContainer" v-if="!usersStore.showUMSetupWarning">
|
||||
<n8n-tooltip :disabled="settingsStore.isSmtpSetup" placement="bottom">
|
||||
<template #content>
|
||||
<i18n path="settings.users.setupSMTPToInviteUsers" tag="span">
|
||||
<template #action>
|
||||
<a
|
||||
href="https://docs.n8n.io/reference/user-management.html#step-one-smtp"
|
||||
target="_blank"
|
||||
v-text="$locale.baseText('settings.users.setupSMTPToInviteUsers.instructions')"
|
||||
/>
|
||||
</template>
|
||||
</i18n>
|
||||
</template>
|
||||
<div>
|
||||
<n8n-button :label="$locale.baseText('settings.users.invite')" @click="onInvite" size="large" :disabled="!settingsStore.isSmtpSetup" />
|
||||
</div>
|
||||
</n8n-tooltip>
|
||||
<n8n-tooltip :disabled="settingsStore.isSmtpSetup" placement="bottom">
|
||||
<template #content>
|
||||
<i18n path="settings.users.setupSMTPToInviteUsers" tag="span">
|
||||
<template #action>
|
||||
<a
|
||||
href="https://docs.n8n.io/reference/user-management.html#step-one-smtp"
|
||||
target="_blank"
|
||||
v-text="$locale.baseText('settings.users.setupSMTPToInviteUsers.instructions')"
|
||||
/>
|
||||
</template>
|
||||
</i18n>
|
||||
</template>
|
||||
<div>
|
||||
<n8n-button
|
||||
:label="$locale.baseText('settings.users.invite')"
|
||||
@click="onInvite"
|
||||
size="large"
|
||||
:disabled="!settingsStore.isSmtpSetup"
|
||||
/>
|
||||
</div>
|
||||
</n8n-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="usersStore.showUMSetupWarning" :class="$style.setupInfoContainer">
|
||||
@@ -35,7 +40,12 @@
|
||||
:message="$locale.baseText('settings.users.smtpToAddUsersWarning')"
|
||||
:popupClass="$style.alert"
|
||||
/>
|
||||
<n8n-users-list :users="usersStore.allUsers" :currentUserId="usersStore.currentUserId" @delete="onDelete" @reinvite="onReinvite" />
|
||||
<n8n-users-list
|
||||
:users="usersStore.allUsers"
|
||||
:currentUserId="usersStore.currentUserId"
|
||||
@delete="onDelete"
|
||||
@reinvite="onReinvite"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -63,15 +73,11 @@ export default mixins(showMessage).extend({
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useSettingsStore,
|
||||
useUIStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useSettingsStore, useUIStore, useUsersStore),
|
||||
},
|
||||
methods: {
|
||||
redirectToSetup() {
|
||||
this.$router.push({name: VIEWS.SETUP});
|
||||
this.$router.push({ name: VIEWS.SETUP });
|
||||
},
|
||||
onInvite() {
|
||||
this.uiStore.openModal(INVITE_USER_MODAL_KEY);
|
||||
@@ -91,10 +97,9 @@ export default mixins(showMessage).extend({
|
||||
this.$showToast({
|
||||
type: 'success',
|
||||
title: this.$locale.baseText('settings.users.inviteResent'),
|
||||
message: this.$locale.baseText(
|
||||
'settings.users.emailSentTo',
|
||||
{ interpolate: { email: user.email || '' } },
|
||||
),
|
||||
message: this.$locale.baseText('settings.users.emailSentTo', {
|
||||
interpolate: { email: user.email || '' },
|
||||
}),
|
||||
});
|
||||
} catch (e) {
|
||||
this.$showError(e, this.$locale.baseText('settings.users.userReinviteError'));
|
||||
@@ -136,5 +141,4 @@ export default mixins(showMessage).extend({
|
||||
.alert {
|
||||
left: calc(50% + 100px);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -26,7 +26,7 @@ const SettingsView = defineComponent({
|
||||
SettingsSidebar,
|
||||
},
|
||||
beforeRouteEnter(to, from, next) {
|
||||
next(vm => {
|
||||
next((vm) => {
|
||||
(vm as unknown as InstanceType<typeof SettingsView>).previousRoute = from;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -22,11 +22,7 @@ import { useSettingsStore } from '@/stores/settings';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
import { useCredentialsStore } from '@/stores/credentials';
|
||||
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
restApi,
|
||||
).extend({
|
||||
export default mixins(showMessage, restApi).extend({
|
||||
name: 'SetupView',
|
||||
components: {
|
||||
AuthView,
|
||||
@@ -103,12 +99,7 @@ export default mixins(
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useCredentialsStore,
|
||||
useSettingsStore,
|
||||
useUIStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useCredentialsStore, useSettingsStore, useUIStore, useUsersStore),
|
||||
},
|
||||
methods: {
|
||||
async getAllCredentials() {
|
||||
@@ -124,21 +115,26 @@ export default mixins(
|
||||
return true;
|
||||
}
|
||||
|
||||
const workflows = this.workflowsCount > 0
|
||||
? this.$locale.baseText(
|
||||
'auth.setup.setupConfirmation.existingWorkflows',
|
||||
{ adjustToNumber: this.workflowsCount },
|
||||
)
|
||||
: '';
|
||||
const workflows =
|
||||
this.workflowsCount > 0
|
||||
? this.$locale.baseText('auth.setup.setupConfirmation.existingWorkflows', {
|
||||
adjustToNumber: this.workflowsCount,
|
||||
})
|
||||
: '';
|
||||
|
||||
const credentials = this.credentialsCount > 0
|
||||
? this.$locale.baseText(
|
||||
'auth.setup.setupConfirmation.credentials',
|
||||
{ adjustToNumber: this.credentialsCount },
|
||||
)
|
||||
: '';
|
||||
const credentials =
|
||||
this.credentialsCount > 0
|
||||
? this.$locale.baseText('auth.setup.setupConfirmation.credentials', {
|
||||
adjustToNumber: this.credentialsCount,
|
||||
})
|
||||
: '';
|
||||
|
||||
const entities = workflows && credentials ? this.$locale.baseText('auth.setup.setupConfirmation.concatEntities', {interpolate: { workflows, credentials }}) : (workflows || credentials);
|
||||
const entities =
|
||||
workflows && credentials
|
||||
? this.$locale.baseText('auth.setup.setupConfirmation.concatEntities', {
|
||||
interpolate: { workflows, credentials },
|
||||
})
|
||||
: workflows || credentials;
|
||||
return await this.confirmMessage(
|
||||
this.$locale.baseText('auth.setup.confirmOwnerSetupMessage', {
|
||||
interpolate: {
|
||||
@@ -151,7 +147,7 @@ export default mixins(
|
||||
this.$locale.baseText('auth.setup.goBack'),
|
||||
);
|
||||
},
|
||||
async onSubmit(values: {[key: string]: string | boolean}) {
|
||||
async onSubmit(values: { [key: string]: string | boolean }) {
|
||||
try {
|
||||
const confirmSetup = await this.confirmSetupOrGoBack();
|
||||
if (!confirmSetup) {
|
||||
@@ -160,21 +156,21 @@ export default mixins(
|
||||
|
||||
const forceRedirectedHere = this.settingsStore.showSetupPage;
|
||||
this.loading = true;
|
||||
await this.usersStore.createOwner(values as { firstName: string; lastName: string; email: string; password: string;});
|
||||
await this.usersStore.createOwner(
|
||||
values as { firstName: string; lastName: string; email: string; password: string },
|
||||
);
|
||||
|
||||
if (values.agree === true) {
|
||||
try {
|
||||
await this.uiStore.submitContactEmail(values.email.toString(), values.agree);
|
||||
} catch { }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (forceRedirectedHere) {
|
||||
await this.$router.push({ name: VIEWS.HOMEPAGE });
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
await this.$router.push({ name: VIEWS.USERS_SETTINGS });
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
this.$showError(error, this.$locale.baseText('auth.setup.settingUpOwnerError'));
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ import { VIEWS } from '@/constants';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'SigninView',
|
||||
components: {
|
||||
AuthView,
|
||||
@@ -68,16 +66,17 @@ export default mixins(
|
||||
...mapStores(useUsersStore),
|
||||
},
|
||||
methods: {
|
||||
async onSubmit(values: {[key: string]: string}) {
|
||||
async onSubmit(values: { [key: string]: string }) {
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.usersStore.loginWithCreds(values as {email: string, password: string});
|
||||
await this.usersStore.loginWithCreds(values as { email: string; password: string });
|
||||
this.clearAllStickyNotifications();
|
||||
this.loading = false;
|
||||
|
||||
if (typeof this.$route.query.redirect === 'string') {
|
||||
const redirect = decodeURIComponent(this.$route.query.redirect);
|
||||
if (redirect.startsWith('/')) { // protect against phishing
|
||||
if (redirect.startsWith('/')) {
|
||||
// protect against phishing
|
||||
this.$router.push(redirect);
|
||||
|
||||
return;
|
||||
|
||||
@@ -18,9 +18,7 @@ import { mapStores } from 'pinia';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
).extend({
|
||||
export default mixins(showMessage).extend({
|
||||
name: 'SignupView',
|
||||
components: {
|
||||
AuthView,
|
||||
@@ -74,14 +72,20 @@ export default mixins(
|
||||
return {
|
||||
FORM_CONFIG,
|
||||
loading: false,
|
||||
inviter: null as null | {firstName: string, lastName: string},
|
||||
inviter: null as null | { firstName: string; lastName: string },
|
||||
inviterId: null as string | null,
|
||||
inviteeId: null as string | null,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
const inviterId = (!this.$route.query.inviterId || typeof this.$route.query.inviterId !== 'string') ? null : this.$route.query.inviterId;
|
||||
const inviteeId = (!this.$route.query.inviteeId || typeof this.$route.query.inviteeId !== 'string') ? null : this.$route.query.inviteeId;
|
||||
const inviterId =
|
||||
!this.$route.query.inviterId || typeof this.$route.query.inviterId !== 'string'
|
||||
? null
|
||||
: this.$route.query.inviterId;
|
||||
const inviteeId =
|
||||
!this.$route.query.inviteeId || typeof this.$route.query.inviteeId !== 'string'
|
||||
? null
|
||||
: this.$route.query.inviteeId;
|
||||
try {
|
||||
if (!inviterId || !inviteeId) {
|
||||
throw new Error(this.$locale.baseText('auth.signup.missingTokenError'));
|
||||
@@ -90,43 +94,52 @@ export default mixins(
|
||||
this.inviteeId = inviteeId;
|
||||
|
||||
const invite = await this.usersStore.validateSignupToken({ inviteeId, inviterId });
|
||||
this.inviter = invite.inviter as {firstName: string, lastName: string};
|
||||
this.inviter = invite.inviter as { firstName: string; lastName: string };
|
||||
} catch (e) {
|
||||
this.$showError(e, this.$locale.baseText('auth.signup.tokenValidationError'));
|
||||
this.$router.replace({name: VIEWS.SIGNIN});
|
||||
this.$router.replace({ name: VIEWS.SIGNIN });
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useUIStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useUIStore, useUsersStore),
|
||||
inviteMessage(): null | string {
|
||||
if (!this.inviter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.$locale.baseText(
|
||||
'settings.signup.signUpInviterInfo',
|
||||
{ interpolate: { firstName: this.inviter.firstName, lastName: this.inviter.lastName }},
|
||||
);
|
||||
return this.$locale.baseText('settings.signup.signUpInviterInfo', {
|
||||
interpolate: { firstName: this.inviter.firstName, lastName: this.inviter.lastName },
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async onSubmit(values: {[key: string]: string | boolean}) {
|
||||
async onSubmit(values: { [key: string]: string | boolean }) {
|
||||
if (!this.inviterId || !this.inviteeId) {
|
||||
this.$showError(new Error(this.$locale.baseText('auth.changePassword.tokenValidationError')), this.$locale.baseText('auth.signup.setupYourAccountError'));
|
||||
this.$showError(
|
||||
new Error(this.$locale.baseText('auth.changePassword.tokenValidationError')),
|
||||
this.$locale.baseText('auth.signup.setupYourAccountError'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.usersStore.signup({...values, inviterId: this.inviterId, inviteeId: this.inviteeId} as { inviteeId: string; inviterId: string; firstName: string; lastName: string; password: string;});
|
||||
await this.usersStore.signup({
|
||||
...values,
|
||||
inviterId: this.inviterId,
|
||||
inviteeId: this.inviteeId,
|
||||
} as {
|
||||
inviteeId: string;
|
||||
inviterId: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
password: string;
|
||||
});
|
||||
|
||||
if (values.agree === true) {
|
||||
try {
|
||||
await this.uiStore.submitContactEmail(values.email.toString(), values.agree);
|
||||
} catch { }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
await this.$router.push({ name: VIEWS.HOMEPAGE });
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div :class="$style.notFound" v-else>
|
||||
<n8n-text color="text-base">{{ $locale.baseText('templates.collectionsNotFound') }}</n8n-text>
|
||||
<n8n-text color="text-base">{{
|
||||
$locale.baseText('templates.collectionsNotFound')
|
||||
}}</n8n-text>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="!notFoundError" #content>
|
||||
@@ -74,9 +76,7 @@ export default mixins(workflowHelpers).extend({
|
||||
TemplatesView,
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useTemplatesStore,
|
||||
),
|
||||
...mapStores(useTemplatesStore),
|
||||
collection(): null | ITemplatesCollectionFull {
|
||||
return this.templatesStore.getCollectionById(this.collectionId);
|
||||
},
|
||||
@@ -110,10 +110,10 @@ export default mixins(workflowHelpers).extend({
|
||||
}
|
||||
}, 50);
|
||||
},
|
||||
onOpenTemplate({event, id}: {event: MouseEvent, id: string}) {
|
||||
onOpenTemplate({ event, id }: { event: MouseEvent; id: string }) {
|
||||
this.navigateTo(event, VIEWS.TEMPLATE, id);
|
||||
},
|
||||
onUseWorkflow({event, id}: {event: MouseEvent, id: string}) {
|
||||
onUseWorkflow({ event, id }: { event: MouseEvent; id: string }) {
|
||||
const telemetryPayload = {
|
||||
template_id: id,
|
||||
wf_template_repo_session_id: this.workflowsStore.currentSessionId,
|
||||
@@ -138,8 +138,7 @@ export default mixins(workflowHelpers).extend({
|
||||
collection(collection: ITemplatesCollection) {
|
||||
if (collection) {
|
||||
setPageTitle(`n8n - Template collection: ${collection.name}`);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setPageTitle(`n8n - Templates`);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -81,7 +81,12 @@ import TemplateList from '@/components/TemplateList.vue';
|
||||
import TemplatesView from './TemplatesView.vue';
|
||||
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { ITemplatesCollection, ITemplatesWorkflow, ITemplatesQuery, ITemplatesCategory } from '@/Interface';
|
||||
import {
|
||||
ITemplatesCollection,
|
||||
ITemplatesWorkflow,
|
||||
ITemplatesQuery,
|
||||
ITemplatesCategory,
|
||||
} from '@/Interface';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { IDataObject } from 'n8n-workflow';
|
||||
import { setPageTitle } from '@/utils';
|
||||
@@ -123,12 +128,7 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useSettingsStore,
|
||||
useTemplatesStore,
|
||||
useUIStore,
|
||||
useUsersStore,
|
||||
),
|
||||
...mapStores(useSettingsStore, useTemplatesStore, useUIStore, useUsersStore),
|
||||
totalWorkflows(): number {
|
||||
return this.templatesStore.getSearchedWorkflowsTotal(this.query);
|
||||
},
|
||||
@@ -145,7 +145,11 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
if (this.workflows.length && this.workflows.length >= this.totalWorkflows) {
|
||||
return this.$locale.baseText('templates.endResult');
|
||||
}
|
||||
if (!this.loadingCollections && this.workflows.length === 0 && this.collections.length === 0) {
|
||||
if (
|
||||
!this.loadingCollections &&
|
||||
this.workflows.length === 0 &&
|
||||
this.collections.length === 0
|
||||
) {
|
||||
if (!this.settingsStore.isTemplatesEndpointReachable && this.errorLoadingWorkflows) {
|
||||
return this.$locale.baseText('templates.connectionWarning');
|
||||
}
|
||||
@@ -170,10 +174,10 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onOpenCollection({event, id}: {event: MouseEvent, id: string}) {
|
||||
onOpenCollection({ event, id }: { event: MouseEvent; id: string }) {
|
||||
this.navigateTo(event, VIEWS.COLLECTION, id);
|
||||
},
|
||||
onOpenTemplate({event, id}: {event: MouseEvent, id: string}) {
|
||||
onOpenTemplate({ event, id }: { event: MouseEvent; id: string }) {
|
||||
this.navigateTo(event, VIEWS.TEMPLATE, id);
|
||||
},
|
||||
navigateTo(e: MouseEvent, page: string, id: string) {
|
||||
@@ -209,7 +213,10 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
},
|
||||
trackSearch() {
|
||||
if (this.searchEventToTrack) {
|
||||
this.$telemetry.track('User searched workflow templates', this.searchEventToTrack as unknown as IDataObject);
|
||||
this.$telemetry.track(
|
||||
'User searched workflow templates',
|
||||
this.searchEventToTrack as unknown as IDataObject,
|
||||
);
|
||||
this.searchEventToTrack = null;
|
||||
}
|
||||
},
|
||||
@@ -292,7 +299,7 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
async loadCategories() {
|
||||
try {
|
||||
await this.templatesStore.getCategories();
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
this.loadingCategories = false;
|
||||
},
|
||||
async loadCollections() {
|
||||
@@ -302,8 +309,7 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
categories: this.categories,
|
||||
search: this.search,
|
||||
});
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
this.loadingCollections = false;
|
||||
},
|
||||
@@ -352,7 +358,11 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
const contentArea = document.getElementById('content');
|
||||
if (contentArea) {
|
||||
// When leaving this page, store current scroll position in route data
|
||||
if (this.$route.meta && this.$route.meta.setScrollPosition && typeof this.$route.meta.setScrollPosition === 'function') {
|
||||
if (
|
||||
this.$route.meta &&
|
||||
this.$route.meta.setScrollPosition &&
|
||||
typeof this.$route.meta.setScrollPosition === 'function'
|
||||
) {
|
||||
this.$route.meta.setScrollPosition(contentArea.scrollTop);
|
||||
}
|
||||
}
|
||||
@@ -379,7 +389,9 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
}
|
||||
|
||||
if (typeof this.$route.query.categories === 'string' && this.$route.query.categories.length) {
|
||||
this.categories = this.$route.query.categories.split(',').map((categoryId) => parseInt(categoryId, 10));
|
||||
this.categories = this.$route.query.categories
|
||||
.split(',')
|
||||
.map((categoryId) => parseInt(categoryId, 10));
|
||||
this.areCategoriesPrepopulated = true;
|
||||
}
|
||||
},
|
||||
@@ -422,5 +434,4 @@ export default mixins(genericHelpers, debounceHelper).extend({
|
||||
.header {
|
||||
margin-bottom: var(--spacing-2xs);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -75,9 +75,7 @@ export default mixins(workflowHelpers).extend({
|
||||
WorkflowPreview,
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useTemplatesStore,
|
||||
),
|
||||
...mapStores(useTemplatesStore),
|
||||
template(): ITemplatesWorkflow | ITemplatesWorkflowFull {
|
||||
return this.templatesStore.getTemplateById(this.templateId);
|
||||
},
|
||||
@@ -128,8 +126,7 @@ export default mixins(workflowHelpers).extend({
|
||||
template(template: ITemplatesWorkflowFull) {
|
||||
if (template) {
|
||||
setPageTitle(`n8n - Template template: ${template.name}`);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setPageTitle(`n8n - Templates`);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -17,20 +17,37 @@
|
||||
<template #empty>
|
||||
<div class="text-center mt-s">
|
||||
<n8n-heading tag="h2" size="xlarge" class="mb-2xs">
|
||||
{{ $locale.baseText(currentUser.firstName ? 'workflows.empty.heading' : 'workflows.empty.heading.userNotSetup', { interpolate: { name: currentUser.firstName } }) }}
|
||||
{{
|
||||
$locale.baseText(
|
||||
currentUser.firstName
|
||||
? 'workflows.empty.heading'
|
||||
: 'workflows.empty.heading.userNotSetup',
|
||||
{ interpolate: { name: currentUser.firstName } },
|
||||
)
|
||||
}}
|
||||
</n8n-heading>
|
||||
<n8n-text size="large" color="text-base">
|
||||
{{ $locale.baseText('workflows.empty.description') }}
|
||||
</n8n-text>
|
||||
</div>
|
||||
<div class="text-center mt-2xl">
|
||||
<n8n-card :class="[$style.emptyStateCard, 'mr-s']" hoverable @click="addWorkflow" data-test-id="new-workflow-card">
|
||||
<n8n-card
|
||||
:class="[$style.emptyStateCard, 'mr-s']"
|
||||
hoverable
|
||||
@click="addWorkflow"
|
||||
data-test-id="new-workflow-card"
|
||||
>
|
||||
<n8n-icon :class="$style.emptyStateCardIcon" icon="file" />
|
||||
<n8n-text size="large" class="mt-xs" color="text-base">
|
||||
{{ $locale.baseText('workflows.empty.startFromScratch') }}
|
||||
</n8n-text>
|
||||
</n8n-card>
|
||||
<n8n-card :class="$style.emptyStateCard" hoverable @click="goToTemplates" data-test-id="new-workflow-template-card">
|
||||
<n8n-card
|
||||
:class="$style.emptyStateCard"
|
||||
hoverable
|
||||
@click="goToTemplates"
|
||||
data-test-id="new-workflow-template-card"
|
||||
>
|
||||
<n8n-icon :class="$style.emptyStateCardIcon" icon="box-open" />
|
||||
<n8n-text size="large" class="mt-xs" color="text-base">
|
||||
{{ $locale.baseText('workflows.empty.browseTemplates') }}
|
||||
@@ -67,7 +84,8 @@
|
||||
v-for="option in statusFilterOptions"
|
||||
:key="option.label"
|
||||
:label="option.label"
|
||||
:value="option.value">
|
||||
:value="option.value"
|
||||
>
|
||||
</n8n-option>
|
||||
</n8n-select>
|
||||
</div>
|
||||
@@ -76,20 +94,20 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {showMessage} from '@/mixins/showMessage';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
|
||||
import SettingsView from './SettingsView.vue';
|
||||
import ResourcesListLayout from "@/components/layouts/ResourcesListLayout.vue";
|
||||
import PageViewLayout from "@/components/layouts/PageViewLayout.vue";
|
||||
import PageViewLayoutList from "@/components/layouts/PageViewLayoutList.vue";
|
||||
import WorkflowCard from "@/components/WorkflowCard.vue";
|
||||
import TemplateCard from "@/components/TemplateCard.vue";
|
||||
import {EnterpriseEditionFeature, VIEWS} from '@/constants';
|
||||
import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue';
|
||||
import PageViewLayout from '@/components/layouts/PageViewLayout.vue';
|
||||
import PageViewLayoutList from '@/components/layouts/PageViewLayoutList.vue';
|
||||
import WorkflowCard from '@/components/WorkflowCard.vue';
|
||||
import TemplateCard from '@/components/TemplateCard.vue';
|
||||
import { EnterpriseEditionFeature, VIEWS } from '@/constants';
|
||||
import { debounceHelper } from '@/mixins/debounce';
|
||||
import Vue from "vue";
|
||||
import {ITag, IUser, IWorkflowDb} from "@/Interface";
|
||||
import TagsDropdown from "@/components/TagsDropdown.vue";
|
||||
import Vue from 'vue';
|
||||
import { ITag, IUser, IWorkflowDb } from '@/Interface';
|
||||
import TagsDropdown from '@/components/TagsDropdown.vue';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
@@ -104,10 +122,7 @@ const StatusFilter = {
|
||||
ALL: '',
|
||||
};
|
||||
|
||||
export default mixins(
|
||||
showMessage,
|
||||
debounceHelper,
|
||||
).extend({
|
||||
export default mixins(showMessage, debounceHelper).extend({
|
||||
name: 'WorkflowsView',
|
||||
components: {
|
||||
ResourcesListLayout,
|
||||
@@ -130,22 +145,19 @@ export default mixins(
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useSettingsStore,
|
||||
useUIStore,
|
||||
useUsersStore,
|
||||
useWorkflowsStore,
|
||||
),
|
||||
...mapStores(useSettingsStore, useUIStore, useUsersStore, useWorkflowsStore),
|
||||
currentUser(): IUser {
|
||||
return this.usersStore.currentUser || {} as IUser;
|
||||
return this.usersStore.currentUser || ({} as IUser);
|
||||
},
|
||||
allWorkflows(): IWorkflowDb[] {
|
||||
return this.workflowsStore.allWorkflows;
|
||||
},
|
||||
isShareable(): boolean {
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.WorkflowSharing);
|
||||
return this.settingsStore.isEnterpriseFeatureEnabled(
|
||||
EnterpriseEditionFeature.WorkflowSharing,
|
||||
);
|
||||
},
|
||||
statusFilterOptions(): Array<{ label: string, value: string | boolean }> {
|
||||
statusFilterOptions(): Array<{ label: string; value: string | boolean }> {
|
||||
return [
|
||||
{
|
||||
label: this.$locale.baseText('workflows.filters.status.all'),
|
||||
@@ -187,11 +199,21 @@ export default mixins(
|
||||
this.filters.tags.push(tagId);
|
||||
}
|
||||
},
|
||||
onFilter(resource: IWorkflowDb, filters: { tags: string[]; search: string; status: string | boolean }, matches: boolean): boolean {
|
||||
onFilter(
|
||||
resource: IWorkflowDb,
|
||||
filters: { tags: string[]; search: string; status: string | boolean },
|
||||
matches: boolean,
|
||||
): boolean {
|
||||
if (this.settingsStore.areTagsEnabled && filters.tags.length > 0) {
|
||||
matches = matches && filters.tags.every(
|
||||
(tag) => (resource.tags as ITag[])?.find((resourceTag) => typeof resourceTag === 'object' ? `${resourceTag.id}` === `${tag}` : `${resourceTag}` === `${tag}`),
|
||||
);
|
||||
matches =
|
||||
matches &&
|
||||
filters.tags.every((tag) =>
|
||||
(resource.tags as ITag[])?.find((resourceTag) =>
|
||||
typeof resourceTag === 'object'
|
||||
? `${resourceTag.id}` === `${tag}`
|
||||
: `${resourceTag}` === `${tag}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.status !== '') {
|
||||
@@ -233,10 +255,9 @@ export default mixins(
|
||||
font-size: 48px;
|
||||
|
||||
svg {
|
||||
width: 48px!important;
|
||||
width: 48px !important;
|
||||
color: var(--color-foreground-dark);
|
||||
transition: color 0.3s ease;}
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user