mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
feat: Expose license feature flags for free AI credits feature to frontend (no-changelog) (#12363)
This commit is contained in:
parent
ac4e042231
commit
7ea6c8b144
|
@ -163,6 +163,10 @@ export interface FrontendSettings {
|
|||
pruneTime: number;
|
||||
licensePruneTime: number;
|
||||
};
|
||||
aiCredits: {
|
||||
enabled: boolean;
|
||||
credits: number;
|
||||
};
|
||||
pruning?: {
|
||||
isEnabled: boolean;
|
||||
maxAge: number;
|
||||
|
|
|
@ -93,6 +93,7 @@ export const LICENSE_FEATURES = {
|
|||
AI_ASSISTANT: 'feat:aiAssistant',
|
||||
ASK_AI: 'feat:askAi',
|
||||
COMMUNITY_NODES_CUSTOM_REGISTRY: 'feat:communityNodes:customRegistry',
|
||||
AI_CREDITS: 'feat:aiCredits',
|
||||
} as const;
|
||||
|
||||
export const LICENSE_QUOTAS = {
|
||||
|
@ -101,6 +102,7 @@ export const LICENSE_QUOTAS = {
|
|||
USERS_LIMIT: 'quota:users',
|
||||
WORKFLOW_HISTORY_PRUNE_LIMIT: 'quota:workflowHistoryPrune',
|
||||
TEAM_PROJECT_LIMIT: 'quota:maxTeamProjects',
|
||||
AI_CREDITS: 'quota:aiCredits',
|
||||
} as const;
|
||||
export const UNLIMITED_LICENSE_QUOTA = -1;
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ export class E2EController {
|
|||
[LICENSE_FEATURES.AI_ASSISTANT]: false,
|
||||
[LICENSE_FEATURES.COMMUNITY_NODES_CUSTOM_REGISTRY]: false,
|
||||
[LICENSE_FEATURES.ASK_AI]: false,
|
||||
[LICENSE_FEATURES.AI_CREDITS]: false,
|
||||
};
|
||||
|
||||
private numericFeatures: Record<NumericLicenseFeature, number> = {
|
||||
|
@ -108,6 +109,7 @@ export class E2EController {
|
|||
[LICENSE_QUOTAS.USERS_LIMIT]: -1,
|
||||
[LICENSE_QUOTAS.WORKFLOW_HISTORY_PRUNE_LIMIT]: -1,
|
||||
[LICENSE_QUOTAS.TEAM_PROJECT_LIMIT]: 0,
|
||||
[LICENSE_QUOTAS.AI_CREDITS]: 0,
|
||||
};
|
||||
|
||||
constructor(
|
||||
|
|
|
@ -255,6 +255,10 @@ export class License {
|
|||
return this.isFeatureEnabled(LICENSE_FEATURES.ASK_AI);
|
||||
}
|
||||
|
||||
isAiCreditsEnabled() {
|
||||
return this.isFeatureEnabled(LICENSE_FEATURES.AI_CREDITS);
|
||||
}
|
||||
|
||||
isAdvancedExecutionFiltersEnabled() {
|
||||
return this.isFeatureEnabled(LICENSE_FEATURES.ADVANCED_EXECUTION_FILTERS);
|
||||
}
|
||||
|
@ -365,6 +369,10 @@ export class License {
|
|||
return this.getFeatureValue(LICENSE_QUOTAS.VARIABLES_LIMIT) ?? UNLIMITED_LICENSE_QUOTA;
|
||||
}
|
||||
|
||||
getAiCredits() {
|
||||
return this.getFeatureValue(LICENSE_QUOTAS.AI_CREDITS) ?? 0;
|
||||
}
|
||||
|
||||
getWorkflowHistoryPruneLimit() {
|
||||
return (
|
||||
this.getFeatureValue(LICENSE_QUOTAS.WORKFLOW_HISTORY_PRUNE_LIMIT) ?? UNLIMITED_LICENSE_QUOTA
|
||||
|
|
|
@ -216,6 +216,10 @@ export class FrontendService {
|
|||
askAi: {
|
||||
enabled: false,
|
||||
},
|
||||
aiCredits: {
|
||||
enabled: false,
|
||||
credits: 0,
|
||||
},
|
||||
workflowHistory: {
|
||||
pruneTime: -1,
|
||||
licensePruneTime: -1,
|
||||
|
@ -283,6 +287,7 @@ export class FrontendService {
|
|||
const isS3Licensed = this.license.isBinaryDataS3Licensed();
|
||||
const isAiAssistantEnabled = this.license.isAiAssistantEnabled();
|
||||
const isAskAiEnabled = this.license.isAskAiEnabled();
|
||||
const isAiCreditsEnabled = this.license.isAiCreditsEnabled();
|
||||
|
||||
this.settings.license.planName = this.license.getPlanName();
|
||||
this.settings.license.consumerId = this.license.getConsumerId();
|
||||
|
@ -343,6 +348,11 @@ export class FrontendService {
|
|||
this.settings.askAi.enabled = isAskAiEnabled;
|
||||
}
|
||||
|
||||
if (isAiCreditsEnabled) {
|
||||
this.settings.aiCredits.enabled = isAiCreditsEnabled;
|
||||
this.settings.aiCredits.credits = this.license.getAiCredits();
|
||||
}
|
||||
|
||||
this.settings.mfa.enabled = config.get('mfa.enabled');
|
||||
|
||||
this.settings.executionMode = config.getEnv('executions.mode');
|
||||
|
|
|
@ -125,6 +125,10 @@ export const defaultSettings: FrontendSettings = {
|
|||
aiAssistant: {
|
||||
enabled: false,
|
||||
},
|
||||
aiCredits: {
|
||||
enabled: false,
|
||||
credits: 0,
|
||||
},
|
||||
betaFeatures: [],
|
||||
easyAIWorkflowOnboarded: false,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { IRestApiContext } from '@/Interface';
|
||||
import type { ICredentialsResponse, IRestApiContext } from '@/Interface';
|
||||
import type { AskAiRequest, ChatRequest, ReplaceCodeRequest } from '@/types/assistant.types';
|
||||
import { makeRestApiRequest, streamRequest } from '@/utils/apiUtils';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
|
@ -42,3 +42,12 @@ export async function generateCodeForPrompt(
|
|||
forNode,
|
||||
} as IDataObject);
|
||||
}
|
||||
|
||||
export async function claimFreeAiCredits(
|
||||
ctx: IRestApiContext,
|
||||
{ projectId }: { projectId?: string },
|
||||
): Promise<ICredentialsResponse> {
|
||||
return await makeRestApiRequest(ctx, 'POST', '/ai/free-credits', {
|
||||
projectId,
|
||||
} as IDataObject);
|
||||
}
|
||||
|
|
|
@ -706,12 +706,19 @@ export const EASY_AI_WORKFLOW_EXPERIMENT = {
|
|||
variant: 'variant',
|
||||
};
|
||||
|
||||
export const AI_CREDITS_EXPERIMENT = {
|
||||
name: '027_free_openai_calls',
|
||||
control: 'control',
|
||||
variant: 'variant',
|
||||
};
|
||||
|
||||
export const EXPERIMENTS_TO_TRACK = [
|
||||
TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT,
|
||||
CANVAS_AUTO_ADD_MANUAL_TRIGGER_EXPERIMENT.name,
|
||||
AI_ASSISTANT_EXPERIMENT.name,
|
||||
CREDENTIAL_DOCS_EXPERIMENT.name,
|
||||
EASY_AI_WORKFLOW_EXPERIMENT.name,
|
||||
AI_CREDITS_EXPERIMENT.name,
|
||||
];
|
||||
|
||||
export const WORKFLOW_EVALUATION_EXPERIMENT = '025_workflow_evaluation';
|
||||
|
|
|
@ -98,6 +98,10 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
|||
|
||||
const isCloudDeployment = computed(() => settings.value.deployment?.type === 'cloud');
|
||||
|
||||
const isAiCreditsEnabled = computed(() => settings.value.aiCredits?.enabled);
|
||||
|
||||
const aiCreditsQuota = computed(() => settings.value.aiCredits?.credits);
|
||||
|
||||
const isSmtpSetup = computed(() => userManagement.value.smtpSetup);
|
||||
|
||||
const isPersonalizationSurveyEnabled = computed(
|
||||
|
@ -425,6 +429,8 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
|||
isCommunityPlan,
|
||||
isAskAiEnabled,
|
||||
isCanvasV2Enabled,
|
||||
isAiCreditsEnabled,
|
||||
aiCreditsQuota,
|
||||
reset,
|
||||
testLdapConnection,
|
||||
getLdapConfig,
|
||||
|
|
|
@ -74,6 +74,8 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
|
||||
const globalRoleName = computed(() => currentUser.value?.role ?? 'default');
|
||||
|
||||
const userClaimedAiCredits = computed(() => currentUser.value?.settings?.userClaimedAiCredits);
|
||||
|
||||
const isEasyAIWorkflowOnboardingDone = computed(() =>
|
||||
Boolean(currentUser.value?.settings?.easyAIWorkflowOnboarded),
|
||||
);
|
||||
|
@ -388,6 +390,8 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
mfaEnabled,
|
||||
globalRoleName,
|
||||
personalizedNodeTypes,
|
||||
userClaimedAiCredits,
|
||||
isEasyAIWorkflowOnboardingDone,
|
||||
addUsers,
|
||||
loginWithCookie,
|
||||
initialize,
|
||||
|
@ -420,7 +424,6 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
sendConfirmationEmail,
|
||||
updateGlobalRole,
|
||||
reset,
|
||||
isEasyAIWorkflowOnboardingDone,
|
||||
setEasyAIWorkflowOnboardingDone,
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue