feat: Expose license feature flags for free AI credits feature to frontend (no-changelog) (#12363)

This commit is contained in:
Ricardo Espinoza 2024-12-27 10:23:20 -05:00 committed by GitHub
parent ac4e042231
commit 7ea6c8b144
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 57 additions and 2 deletions

View file

@ -163,6 +163,10 @@ export interface FrontendSettings {
pruneTime: number;
licensePruneTime: number;
};
aiCredits: {
enabled: boolean;
credits: number;
};
pruning?: {
isEnabled: boolean;
maxAge: number;

View file

@ -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;

View file

@ -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(

View file

@ -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

View file

@ -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');

View file

@ -125,6 +125,10 @@ export const defaultSettings: FrontendSettings = {
aiAssistant: {
enabled: false,
},
aiCredits: {
enabled: false,
credits: 0,
},
betaFeatures: [],
easyAIWorkflowOnboarded: false,
};

View file

@ -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);
}

View file

@ -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';

View file

@ -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,

View file

@ -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,
};
});