2022-07-20 07:24:03 -07:00
|
|
|
<template>
|
2022-11-09 00:31:23 -08:00
|
|
|
<div :class="$style.container">
|
|
|
|
<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
|
2022-12-14 01:04:10 -08:00
|
|
|
"
|
2022-11-09 00:31:23 -08:00
|
|
|
:label="$locale.baseText('settings.communityNodes.installModal.installButton.label')"
|
|
|
|
size="large"
|
|
|
|
@click="openInstallModal"
|
|
|
|
/>
|
2022-07-20 07:24:03 -07:00
|
|
|
</div>
|
2022-11-09 00:31:23 -08:00
|
|
|
<div v-if="settingsStore.isQueueModeEnabled" :class="$style.actionBoxContainer">
|
|
|
|
<n8n-action-box
|
|
|
|
:heading="$locale.baseText('settings.communityNodes.empty.title')"
|
|
|
|
:description="getEmptyStateDescription"
|
|
|
|
:calloutText="actionBoxConfig.calloutText"
|
|
|
|
:calloutTheme="actionBoxConfig.calloutTheme"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div :class="$style.cardsContainer" v-else-if="loading">
|
|
|
|
<community-package-card
|
|
|
|
v-for="n in 2"
|
|
|
|
:key="'index-' + n"
|
|
|
|
:loading="true"
|
|
|
|
></community-package-card>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
v-else-if="communityNodesStore.getInstalledPackages.length === 0"
|
|
|
|
:class="$style.actionBoxContainer"
|
|
|
|
>
|
|
|
|
<n8n-action-box
|
|
|
|
:heading="$locale.baseText('settings.communityNodes.empty.title')"
|
|
|
|
:description="getEmptyStateDescription"
|
2023-02-08 01:42:22 -08:00
|
|
|
:buttonText="getEmptyStateButtonText"
|
2022-11-09 00:31:23 -08:00
|
|
|
:calloutText="actionBoxConfig.calloutText"
|
|
|
|
:calloutTheme="actionBoxConfig.calloutTheme"
|
2023-07-28 00:51:07 -07:00
|
|
|
@click:button="onClickEmptyStateButton"
|
2022-11-09 00:31:23 -08:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div :class="$style.cardsContainer" v-else>
|
|
|
|
<community-package-card
|
|
|
|
v-for="communityPackage in communityNodesStore.getInstalledPackages"
|
|
|
|
:key="communityPackage.packageName"
|
|
|
|
:communityPackage="communityPackage"
|
|
|
|
></community-package-card>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-07-20 07:24:03 -07:00
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
2022-08-11 07:39:55 -07:00
|
|
|
import {
|
|
|
|
COMMUNITY_PACKAGE_INSTALL_MODAL_KEY,
|
|
|
|
COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
2023-08-29 08:40:33 -07:00
|
|
|
COMMUNITY_NODES_MANUAL_INSTALLATION_DOCS_URL,
|
2022-08-11 07:39:55 -07:00
|
|
|
COMMUNITY_NODES_NPM_INSTALLATION_URL,
|
2022-11-09 00:31:23 -08:00
|
|
|
} from '@/constants';
|
|
|
|
import CommunityPackageCard from '@/components/CommunityPackageCard.vue';
|
2023-05-15 09:41:13 -07:00
|
|
|
import { useToast } from '@/composables';
|
2023-04-20 03:23:17 -07:00
|
|
|
import { pushConnection } from '@/mixins/pushConnection';
|
2023-04-24 03:18:24 -07:00
|
|
|
import type { PublicInstalledPackage } from 'n8n-workflow';
|
2022-07-20 07:24:03 -07:00
|
|
|
|
2023-05-05 01:41:54 -07:00
|
|
|
import { useCommunityNodesStore } from '@/stores/communityNodes.store';
|
|
|
|
import { useUIStore } from '@/stores/ui.store';
|
2022-11-04 06:04:31 -07:00
|
|
|
import { mapStores } from 'pinia';
|
2023-05-05 01:41:54 -07:00
|
|
|
import { useSettingsStore } from '@/stores/settings.store';
|
2023-05-15 09:41:13 -07:00
|
|
|
import { defineComponent } from 'vue';
|
2022-11-04 06:04:31 -07:00
|
|
|
|
2022-07-20 07:24:03 -07:00
|
|
|
const PACKAGE_COUNT_THRESHOLD = 31;
|
|
|
|
|
2023-05-15 09:41:13 -07:00
|
|
|
export default defineComponent({
|
2022-07-20 07:24:03 -07:00
|
|
|
name: 'SettingsCommunityNodesView',
|
2023-05-15 09:41:13 -07:00
|
|
|
mixins: [pushConnection],
|
2022-07-20 07:24:03 -07:00
|
|
|
components: {
|
|
|
|
CommunityPackageCard,
|
|
|
|
},
|
2023-05-15 09:41:13 -07:00
|
|
|
setup(props) {
|
|
|
|
return {
|
|
|
|
...useToast(),
|
2023-07-28 00:51:07 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
2023-05-15 09:41:13 -07:00
|
|
|
...pushConnection.setup?.(props),
|
|
|
|
};
|
|
|
|
},
|
2022-07-20 07:24:03 -07:00
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
loading: false,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
async mounted() {
|
2023-04-20 03:23:17 -07:00
|
|
|
// The push connection is needed here to receive `reloadNodeType` and `removeNodeType` events when community nodes are installed, updated, or removed.
|
|
|
|
this.pushConnect();
|
|
|
|
|
2022-07-20 07:24:03 -07:00
|
|
|
try {
|
2023-07-28 00:51:07 -07:00
|
|
|
this.loading = true;
|
2022-11-04 06:04:31 -07:00
|
|
|
await this.communityNodesStore.fetchInstalledPackages();
|
2022-07-20 07:24:03 -07:00
|
|
|
|
2022-11-04 06:04:31 -07:00
|
|
|
const installedPackages: PublicInstalledPackage[] =
|
|
|
|
this.communityNodesStore.getInstalledPackages;
|
2022-07-20 07:24:03 -07:00
|
|
|
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) => {
|
|
|
|
return {
|
|
|
|
package_name: p.packageName,
|
|
|
|
package_version: p.installedVersion,
|
|
|
|
package_nodes: p.installedNodes.map((node) => `${node.name}-v${node.latestVersion}`),
|
|
|
|
is_update_available: p.updateAvailable !== undefined,
|
|
|
|
};
|
|
|
|
}),
|
|
|
|
packages_to_update: packagesToUpdate.map((p) => {
|
|
|
|
return {
|
|
|
|
package_name: p.packageName,
|
|
|
|
package_version_current: p.installedVersion,
|
|
|
|
package_version_available: p.updateAvailable,
|
|
|
|
};
|
|
|
|
}),
|
|
|
|
number_of_updates_available: packagesToUpdate.length,
|
|
|
|
});
|
|
|
|
} catch (error) {
|
2023-05-15 09:41:13 -07:00
|
|
|
this.showError(
|
2022-07-20 07:24:03 -07:00
|
|
|
error,
|
|
|
|
this.$locale.baseText('settings.communityNodes.fetchError.title'),
|
|
|
|
this.$locale.baseText('settings.communityNodes.fetchError.message'),
|
|
|
|
);
|
|
|
|
} finally {
|
2023-07-28 00:51:07 -07:00
|
|
|
this.loading = false;
|
2022-07-20 07:24:03 -07:00
|
|
|
}
|
|
|
|
try {
|
2022-11-04 06:04:31 -07:00
|
|
|
await this.communityNodesStore.fetchAvailableCommunityPackageCount();
|
2022-07-20 07:24:03 -07:00
|
|
|
} finally {
|
2023-07-28 00:51:07 -07:00
|
|
|
this.loading = false;
|
2022-07-20 07:24:03 -07:00
|
|
|
}
|
|
|
|
},
|
2023-07-28 00:51:07 -07:00
|
|
|
beforeUnmount() {
|
2023-04-20 03:23:17 -07:00
|
|
|
this.pushDisconnect();
|
|
|
|
},
|
2022-07-20 07:24:03 -07:00
|
|
|
computed: {
|
2022-11-04 06:04:31 -07:00
|
|
|
...mapStores(useCommunityNodesStore, useSettingsStore, useUIStore),
|
2023-02-08 01:42:22 -08:00
|
|
|
getEmptyStateDescription(): string {
|
2022-11-04 06:04:31 -07:00
|
|
|
const packageCount = this.communityNodesStore.availablePackageCount;
|
2023-02-08 01:42:22 -08:00
|
|
|
|
|
|
|
if (this.settingsStore.isDesktopDeployment) {
|
|
|
|
return this.$locale.baseText('contextual.communityNodes.unavailable.description.desktop');
|
|
|
|
}
|
|
|
|
|
2022-07-20 07:24:03 -07:00
|
|
|
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(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
2023-02-08 01:42:22 -08:00
|
|
|
getEmptyStateButtonText(): string {
|
2022-11-04 06:04:31 -07:00
|
|
|
if (this.settingsStore.isDesktopDeployment) {
|
2023-02-08 01:42:22 -08:00
|
|
|
return this.$locale.baseText('contextual.communityNodes.unavailable.button.desktop');
|
2022-10-13 04:42:12 -07:00
|
|
|
}
|
|
|
|
|
2023-02-08 01:42:22 -08:00
|
|
|
return this.shouldShowInstallButton
|
|
|
|
? this.$locale.baseText('settings.communityNodes.empty.installPackageLabel')
|
|
|
|
: '';
|
|
|
|
},
|
|
|
|
shouldShowInstallButton(): boolean {
|
|
|
|
return this.settingsStore.isDesktopDeployment || this.settingsStore.isNpmAvailable;
|
|
|
|
},
|
|
|
|
actionBoxConfig(): {
|
|
|
|
calloutText: string;
|
|
|
|
calloutTheme: 'warning' | string;
|
|
|
|
hideButton: boolean;
|
|
|
|
} {
|
2022-11-04 06:04:31 -07:00
|
|
|
if (!this.settingsStore.isNpmAvailable) {
|
2022-08-11 07:39:55 -07:00
|
|
|
return {
|
|
|
|
calloutText: this.$locale.baseText('settings.communityNodes.npmUnavailable.warning', {
|
|
|
|
interpolate: { npmUrl: COMMUNITY_NODES_NPM_INSTALLATION_URL },
|
|
|
|
}),
|
|
|
|
calloutTheme: 'warning',
|
|
|
|
hideButton: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-11-04 06:04:31 -07:00
|
|
|
if (this.settingsStore.isQueueModeEnabled) {
|
2022-08-11 07:39:55 -07:00
|
|
|
return {
|
|
|
|
calloutText: this.$locale.baseText('settings.communityNodes.queueMode.warning', {
|
2023-08-29 08:40:33 -07:00
|
|
|
interpolate: { docURL: COMMUNITY_NODES_MANUAL_INSTALLATION_DOCS_URL },
|
2022-08-11 07:39:55 -07:00
|
|
|
}),
|
|
|
|
calloutTheme: 'warning',
|
|
|
|
hideButton: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2022-07-20 07:24:03 -07:00
|
|
|
calloutText: '',
|
|
|
|
calloutTheme: '',
|
|
|
|
hideButton: false,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
2023-02-08 01:42:22 -08:00
|
|
|
onClickEmptyStateButton(): void {
|
|
|
|
if (this.settingsStore.isDesktopDeployment) {
|
|
|
|
return this.goToUpgrade();
|
|
|
|
}
|
|
|
|
|
|
|
|
this.openInstallModal();
|
|
|
|
},
|
|
|
|
goToUpgrade(): void {
|
2023-10-06 04:16:27 -07:00
|
|
|
void this.uiStore.goToUpgrade('community-nodes', 'upgrade-community-nodes');
|
2023-02-08 01:42:22 -08:00
|
|
|
},
|
|
|
|
openInstallModal(): void {
|
2022-11-04 06:04:31 -07:00
|
|
|
const telemetryPayload = {
|
|
|
|
is_empty_state: this.communityNodesStore.getInstalledPackages.length === 0,
|
|
|
|
};
|
2022-08-19 06:35:39 -07:00
|
|
|
this.$telemetry.track('user clicked cnr install button', telemetryPayload);
|
2023-05-10 08:10:03 -07:00
|
|
|
|
|
|
|
void this.$externalHooks().run(
|
|
|
|
'settingsCommunityNodesView.openInstallModal',
|
|
|
|
telemetryPayload,
|
|
|
|
);
|
2022-11-04 06:04:31 -07:00
|
|
|
this.uiStore.openModal(COMMUNITY_PACKAGE_INSTALL_MODAL_KEY);
|
2022-07-20 07:24:03 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" module>
|
|
|
|
.container {
|
|
|
|
height: 100%;
|
|
|
|
padding-right: var(--spacing-2xs);
|
|
|
|
> * {
|
|
|
|
margin-bottom: var(--spacing-2xl);
|
|
|
|
}
|
2022-12-14 01:04:10 -08:00
|
|
|
}
|
2022-07-20 07:24:03 -07:00
|
|
|
|
|
|
|
.headingContainer {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
}
|
|
|
|
|
|
|
|
.loadingContainer {
|
|
|
|
display: flex;
|
|
|
|
gap: var(--spacing-xs);
|
|
|
|
}
|
|
|
|
|
|
|
|
.actionBoxContainer {
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
.cardsContainer {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
gap: var(--spacing-2xs);
|
|
|
|
}
|
|
|
|
</style>
|