feature flag support

This commit is contained in:
Martin McKeaveney 2024-09-09 18:07:47 +01:00
parent b4a4f81308
commit 96fbc8fff0
7 changed files with 52 additions and 8 deletions

View File

@ -268,4 +268,5 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
export const flags = new FlagSet({
DEFAULT_VALUES: Flag.boolean(env.isDev()),
SQS: Flag.boolean(env.isDev()),
AI_CUSTOM_CONFIGS: Flag.boolean(env.isDev()),
})

View File

@ -17,6 +17,7 @@ export const usage = (users: number = 0, creators: number = 0): QuotaUsage => {
automations: 0,
dayPasses: 0,
queries: 0,
budibaseAICredits: 0,
triggers: {},
breakdown: {
rowQueries: {
@ -46,12 +47,14 @@ export const usage = (users: number = 0, creators: number = 0): QuotaUsage => {
automations: 0,
dayPasses: 0,
queries: 0,
budibaseAICredits: 0,
triggers: {},
},
current: {
automations: 0,
dayPasses: 0,
queries: 0,
budibaseAICredits: 0,
triggers: {},
},
},
@ -62,6 +65,7 @@ export const usage = (users: number = 0, creators: number = 0): QuotaUsage => {
creators,
userGroups: 0,
rows: 0,
aiCustomConfigs: 0,
triggers: {},
},
}

View File

@ -80,7 +80,9 @@
}
async function deleteConfig(key) {
// Delete a configuration
// We don't store the default BB AI config in the DB
delete fullAIConfig.config.budibase_ai
// Delete the configuration
delete fullAIConfig.config[key]
try {

View File

@ -1,7 +1,9 @@
import { derived } from "svelte/store"
import { admin } from "./admin"
import { auth } from "./auth"
import { isEnabled } from "helpers/featureFlags"
import { sdk } from "@budibase/shared-core"
import { FeatureFlag } from "@budibase/types";
export const menu = derived([admin, auth], ([$admin, $auth]) => {
const user = $auth?.user
@ -45,10 +47,6 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => {
title: "Auth",
href: "/builder/portal/settings/auth",
},
{
title: "AI",
href: "/builder/portal/settings/ai",
},
{
title: "Email",
href: "/builder/portal/settings/email",
@ -66,6 +64,15 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => {
href: "/builder/portal/settings/environment",
},
]
if (isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) {
settingsSubPages.push(
{
title: "AI",
href: "/builder/portal/settings/ai",
}
)
}
if (!cloud) {
settingsSubPages.push({
title: "Version",

View File

@ -1,6 +1,7 @@
export enum FeatureFlag {
PER_CREATOR_PER_USER_PRICE = "PER_CREATOR_PER_USER_PRICE",
PER_CREATOR_PER_USER_PRICE_ALERT = "PER_CREATOR_PER_USER_PRICE_ALERT",
AI_CUSTOM_CONFIGS = "AI_CUSTOM_CONFIGS",
}
export interface TenantFeatureFlags {

View File

@ -135,7 +135,6 @@ const getEventFns = async (config: Config, existing?: Config) => {
}
}
}
return fns
}
@ -344,11 +343,12 @@ async function enrichAIConfig(aiConfig: AIConfig) {
// Return the Budibase AI data source as part of the response if licensing allows
const budibaseAIEnabled = await pro.features.isBudibaseAIEnabled()
const defaultConfigExists = Object.keys(aiConfig.config).some(key => aiConfig.config[key].isDefault)
if (budibaseAIEnabled) {
aiConfig.config["budibase_ai"] = {
provider: "OpenAI",
active: true,
isDefault: true,
isDefault: !defaultConfigExists,
defaultModel: env.BUDIBASE_AI_DEFAULT_MODEL,
name: "Budibase AI",
}

View File

@ -1,4 +1,3 @@
import { expect } from "vitest"
import { configs } from "@budibase/backend-core"
import { UserCtx } from "@budibase/types"
import * as pro from "@budibase/pro"
@ -81,6 +80,35 @@ describe("Global configs controller", () => {
})
})
it("Should not not return the default Budibase AI config when on self host", async () => {
pro.features.isBudibaseAIEnabled = jest.fn(() => false)
configs.getConfig.mockResolvedValue({
config: {
ai: {
apiKey: "abc123APIKey",
baseUrl: "https://api.example.com",
},
},
})
const ctx = {
params: {
type: "ai",
},
throw: jest.fn(),
} as UserCtx
await find(ctx)
expect(ctx.body).toEqual({
config: {
ai: {
apiKey: "--secret-value--",
baseUrl: "https://api.example.com",
},
},
})
})
it("Should not update existing secrets when updating an existing AI Config", async () => {
const newConfig = {
type: "ai",
@ -114,4 +142,5 @@ describe("Global configs controller", () => {
// should be unchanged
expect(newConfig.config.aiconfig.apiKey === "myapikey")
})
})