mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
feat(cli): Enable community nodes based on npm availability (#3871)
* ⚡ Detect npm availability * 📘 Expand interfaces * ⚡ Adjust store * 🎨 Replace button with warning
This commit is contained in:
parent
620525ea85
commit
936264b3c6
|
@ -516,6 +516,7 @@ export interface IN8nUISettings {
|
|||
missingPackages?: boolean;
|
||||
executionMode: 'regular' | 'queue';
|
||||
communityNodesEnabled: boolean;
|
||||
isNpmAvailable: boolean;
|
||||
}
|
||||
|
||||
export interface IPersonalizationSurveyAnswers {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
import express from 'express';
|
||||
import { readFileSync, promises } from 'fs';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { exec as callbackExec } from 'child_process';
|
||||
import _, { cloneDeep } from 'lodash';
|
||||
import { dirname as pathDirname, join as pathJoin, resolve as pathResolve } from 'path';
|
||||
import {
|
||||
|
@ -86,6 +87,7 @@ import jwks from 'jwks-rsa';
|
|||
import timezones from 'google-timezones-json';
|
||||
import parseUrl from 'parseurl';
|
||||
import promClient, { Registry } from 'prom-client';
|
||||
import { promisify } from 'util';
|
||||
import * as Queue from './Queue';
|
||||
import {
|
||||
ActiveExecutions,
|
||||
|
@ -167,6 +169,8 @@ import { loadPublicApiVersions } from './PublicApi';
|
|||
|
||||
require('body-parser-xml')(bodyParser);
|
||||
|
||||
const exec = promisify(callbackExec);
|
||||
|
||||
export const externalHooks: IExternalHooksClass = ExternalHooks();
|
||||
|
||||
class App {
|
||||
|
@ -330,6 +334,7 @@ class App {
|
|||
onboardingCallPromptEnabled: config.getEnv('onboardingCallPrompt.enabled'),
|
||||
executionMode: config.getEnv('executions.mode'),
|
||||
communityNodesEnabled: config.getEnv('nodes.communityPackages.enabled'),
|
||||
isNpmAvailable: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -374,6 +379,10 @@ class App {
|
|||
promClient.collectDefaultMetrics({ register });
|
||||
}
|
||||
|
||||
this.frontendSettings.isNpmAvailable = await exec('npm --version')
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
|
||||
this.versions = await GenericHelpers.getVersions();
|
||||
this.frontendSettings.versionCli = this.versions.cli;
|
||||
|
||||
|
|
|
@ -719,6 +719,7 @@ export interface IN8nUISettings {
|
|||
};
|
||||
executionMode: string;
|
||||
communityNodesEnabled: boolean;
|
||||
isNpmAvailable: boolean;
|
||||
publicApi: {
|
||||
enabled: boolean;
|
||||
latestVersion: number;
|
||||
|
@ -881,6 +882,7 @@ export interface IRootState {
|
|||
sidebarMenuItems: IMenuItem[];
|
||||
instanceId: string;
|
||||
nodeMetadata: {[nodeName: string]: INodeMetadata};
|
||||
isNpmAvailable: boolean;
|
||||
}
|
||||
|
||||
export interface ICommunityPackageMap {
|
||||
|
|
|
@ -63,6 +63,7 @@ export const NPM_PACKAGE_DOCS_BASE_URL = `https://www.npmjs.com/package/`;
|
|||
export const NPM_KEYWORD_SEARCH_URL = `https://www.npmjs.com/search?q=keywords%3An8n-community-node-package`;
|
||||
export const N8N_QUEUE_MODE_DOCS_URL = `https://docs.n8n.io/hosting/scaling/queue-mode/`;
|
||||
export const COMMUNITY_NODES_INSTALLATION_DOCS_URL = `https://docs.n8n.io/integrations/community-nodes/installation/`;
|
||||
export const COMMUNITY_NODES_NPM_INSTALLATION_URL = 'https://docs.npmjs.com/downloading-and-installing-node-js-and-npm';
|
||||
export const COMMUNITY_NODES_RISKS_DOCS_URL = `https://docs.n8n.io/integrations/community-nodes/risks/`;
|
||||
export const COMMUNITY_NODES_BLOCKLIST_DOCS_URL = `https://docs.n8n.io/integrations/community-nodes/blocklist/`;
|
||||
export const CUSTOM_NODES_DOCS_URL = `https://docs.n8n.io/integrations/creating-nodes/code/create-n8n-nodes-module/`;
|
||||
|
|
|
@ -90,6 +90,9 @@ const module: Module<ISettingsState, IRootState> = {
|
|||
isCommunityNodesFeatureEnabled: (state): boolean => {
|
||||
return state.settings.communityNodesEnabled;
|
||||
},
|
||||
isNpmAvailable: (state): boolean => {
|
||||
return state.settings.isNpmAvailable;
|
||||
},
|
||||
isQueueModeEnabled: (state): boolean => {
|
||||
return state.settings.executionMode === 'queue';
|
||||
},
|
||||
|
@ -138,6 +141,7 @@ const module: Module<ISettingsState, IRootState> = {
|
|||
context.commit('setOauthCallbackUrls', settings.oauthCallbackUrls, {root: true});
|
||||
context.commit('setN8nMetadata', settings.n8nMetadata || {}, {root: true});
|
||||
context.commit('setDefaultLocale', settings.defaultLocale, {root: true});
|
||||
context.commit('setIsNpmAvailable', settings.isNpmAvailable, {root: true});
|
||||
context.commit('versions/setVersionNotificationSettings', settings.versionNotifications, {root: true});
|
||||
context.commit('setCommunityNodesFeatureEnabled', settings.communityNodesEnabled === true);
|
||||
},
|
||||
|
|
|
@ -725,6 +725,7 @@
|
|||
"settings.communityNodes.empty.description.no-packages": "Install node packages contributed by our community. <br /><a href=\"{docURL}\" target=\"_blank\" title=\"Read the n8n docs\">More info</a>",
|
||||
"settings.communityNodes.empty.installPackageLabel": "Install a community node",
|
||||
"settings.communityNodes.queueMode.warning": "You need to install community nodes manually because your instance is running in queue mode. <a href=\"{docURL}\" target=\"_blank\" title=\"Read the n8n docs\">More info</a>",
|
||||
"settings.communityNodes.npmUnavailable.warning": "To use this feature, please <a href=\"{npmUrl}\" target=\"_blank\" title=\"How to install npm\">install npm</a> and restart n8n.",
|
||||
"settings.communityNodes.packageNodes.label": "{count} node | {count} nodes",
|
||||
"settings.communityNodes.updateAvailable.tooltip": "A newer version is available",
|
||||
"settings.communityNodes.viewDocsAction.label": "Documentation",
|
||||
|
|
|
@ -84,6 +84,7 @@ const state: IRootState = {
|
|||
selectedNodes: [],
|
||||
sessionId: Math.random().toString(36).substring(2, 15),
|
||||
urlBaseWebhook: 'http://localhost:5678/',
|
||||
isNpmAvailable: false,
|
||||
workflow: {
|
||||
id: PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
||||
name: '',
|
||||
|
@ -600,6 +601,9 @@ export const store = new Vuex.Store({
|
|||
setDefaultLocale(state, locale: string) {
|
||||
Vue.set(state, 'defaultLocale', locale);
|
||||
},
|
||||
setIsNpmAvailable(state, isNpmAvailable: boolean) {
|
||||
Vue.set(state, 'isNpmAvailable', isNpmAvailable);
|
||||
},
|
||||
setActiveNode(state, nodeName: string) {
|
||||
state.activeNode = nodeName;
|
||||
},
|
||||
|
|
|
@ -36,7 +36,11 @@
|
|||
<n8n-action-box
|
||||
:heading="$locale.baseText('settings.communityNodes.empty.title')"
|
||||
:description="getEmptyStateDescription"
|
||||
:buttonText="$locale.baseText('settings.communityNodes.empty.installPackageLabel')"
|
||||
:buttonText="
|
||||
isNpmAvailable
|
||||
? $locale.baseText('settings.communityNodes.empty.installPackageLabel')
|
||||
: ''
|
||||
"
|
||||
:calloutText="actionBoxConfig.calloutText"
|
||||
:calloutTheme="actionBoxConfig.calloutTheme"
|
||||
@click="openInstallModal"
|
||||
|
@ -63,7 +67,11 @@ import SettingsView from './SettingsView.vue';
|
|||
import CommunityPackageCard from '../components/CommunityPackageCard.vue';
|
||||
import { showMessage } from '@/components/mixins/showMessage';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { COMMUNITY_PACKAGE_INSTALL_MODAL_KEY, COMMUNITY_NODES_INSTALLATION_DOCS_URL } from '../constants';
|
||||
import {
|
||||
COMMUNITY_PACKAGE_INSTALL_MODAL_KEY,
|
||||
COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
COMMUNITY_NODES_NPM_INSTALLATION_URL,
|
||||
} from '../constants';
|
||||
import { PublicInstalledPackage } from 'n8n-workflow';
|
||||
|
||||
const PACKAGE_COUNT_THRESHOLD = 31;
|
||||
|
@ -123,7 +131,7 @@ export default mixins(
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('settings', ['isQueueModeEnabled']),
|
||||
...mapGetters('settings', ['isNpmAvailable', 'isQueueModeEnabled']),
|
||||
...mapGetters('communityNodes', ['getInstalledPackages']),
|
||||
getEmptyStateDescription() {
|
||||
const packageCount = this.$store.getters['communityNodes/availablePackageCount'];
|
||||
|
@ -141,13 +149,29 @@ export default mixins(
|
|||
});
|
||||
},
|
||||
actionBoxConfig() {
|
||||
return this.isQueueModeEnabled ? {
|
||||
calloutText: this.$locale.baseText('settings.communityNodes.queueMode.warning', {
|
||||
interpolate: { docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL },
|
||||
}),
|
||||
calloutTheme: 'warning',
|
||||
hideButton: true,
|
||||
} : {
|
||||
if (!this.isNpmAvailable) {
|
||||
return {
|
||||
calloutText: this.$locale.baseText(
|
||||
'settings.communityNodes.npmUnavailable.warning',
|
||||
{ interpolate: { npmUrl: COMMUNITY_NODES_NPM_INSTALLATION_URL } },
|
||||
),
|
||||
calloutTheme: 'warning',
|
||||
hideButton: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.isQueueModeEnabled) {
|
||||
return {
|
||||
calloutText: this.$locale.baseText(
|
||||
'settings.communityNodes.queueMode.warning',
|
||||
{ interpolate: { docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL } },
|
||||
),
|
||||
calloutTheme: 'warning',
|
||||
hideButton: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
calloutText: '',
|
||||
calloutTheme: '',
|
||||
hideButton: false,
|
||||
|
|
Loading…
Reference in a new issue