From 594551e1b550368609f1e998f356e2dd28b354f3 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 12 Sep 2024 14:05:32 +0100 Subject: [PATCH 01/11] tests for filter steps --- .../tests/scenarios/scenarios.spec.ts | 167 +++++++++++++++++- .../tests/utilities/AutomationTestBuilder.ts | 9 + 2 files changed, 175 insertions(+), 1 deletion(-) diff --git a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts index 40d6094525..62a1b9db8f 100644 --- a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts +++ b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts @@ -1,8 +1,9 @@ import * as automation from "../../index" import * as setup from "../utilities" -import { LoopStepType, FieldType } from "@budibase/types" +import { LoopStepType, FieldType, Table } from "@budibase/types" import { createAutomationBuilder } from "../utilities/AutomationTestBuilder" import { DatabaseName } from "../../../integrations/tests/utils" +import { FilterConditions } from "../../../automations/steps/filter" describe("Automation Scenarios", () => { let config = setup.getConfig() @@ -196,4 +197,168 @@ describe("Automation Scenarios", () => { ) }) }) + describe.only("Automations with filter", () => { + let table: Table + + beforeEach(async () => { + table = await config.createTable({ + name: "TestTable", + type: "table", + schema: { + name: { + name: "name", + type: FieldType.STRING, + constraints: { + presence: true, + }, + }, + value: { + name: "value", + type: FieldType.NUMBER, + constraints: { + presence: true, + }, + }, + }, + }) + }) + + it("should stop an automation if the condition is not met", async () => { + const builder = createAutomationBuilder({ + name: "Test Equal", + }) + + const results = await builder + .appAction({ fields: {} }) + .createRow({ + row: { + name: "Equal Test", + value: 10, + tableId: table._id, + }, + }) + .queryRows({ + tableId: table._id!, + }) + .filter({ + field: "{{ steps.2.rows.0.value }}", + condition: FilterConditions.EQUAL, + value: 20, + }) + .serverLog({ text: "Equal condition met" }) + .run() + + expect(results.steps[2].outputs.success).toBeTrue() + expect(results.steps[2].outputs.result).toBeFalse() + expect(results.steps[3]).toBeUndefined() + }) + + it("should continue the automation if the condition is met", async () => { + const builder = createAutomationBuilder({ + name: "Test Not Equal", + }) + + const results = await builder + .appAction({ fields: {} }) + .createRow({ + row: { + name: "Not Equal Test", + value: 10, + tableId: table._id, + }, + }) + .queryRows({ + tableId: table._id!, + }) + .filter({ + field: "{{ steps.2.rows.0.value }}", + condition: FilterConditions.NOT_EQUAL, + value: 20, + }) + .serverLog({ text: "Not Equal condition met" }) + .run() + + expect(results.steps[2].outputs.success).toBeTrue() + expect(results.steps[2].outputs.result).toBeTrue() + expect(results.steps[3].outputs.success).toBeTrue() + }) + + const testCases = [ + { + condition: FilterConditions.EQUAL, + value: 10, + rowValue: 10, + expectPass: true, + }, + { + condition: FilterConditions.NOT_EQUAL, + value: 10, + rowValue: 20, + expectPass: true, + }, + { + condition: FilterConditions.GREATER_THAN, + value: 10, + rowValue: 15, + expectPass: true, + }, + { + condition: FilterConditions.LESS_THAN, + value: 10, + rowValue: 5, + expectPass: true, + }, + { + condition: FilterConditions.GREATER_THAN, + value: 10, + rowValue: 5, + expectPass: false, + }, + { + condition: FilterConditions.LESS_THAN, + value: 10, + rowValue: 15, + expectPass: false, + }, + ] + + testCases.forEach(({ condition, value, rowValue, expectPass }) => { + it(`should ${ + expectPass ? "pass" : "fail" + } the filter when condition is "${condition}" and value is ${value}`, async () => { + const builder = createAutomationBuilder({ + name: `Test ${condition}`, + }) + + const results = await builder + .appAction({ fields: {} }) + .createRow({ + row: { + name: `${condition} Test`, + value: rowValue, + tableId: table._id, + }, + }) + .queryRows({ + tableId: table._id!, + }) + .filter({ + field: "{{ steps.2.rows.0.value }}", + condition, + value, + }) + .serverLog({ + text: `${condition} condition ${expectPass ? "passed" : "failed"}`, + }) + .run() + + expect(results.steps[2].outputs.result).toBe(expectPass) + if (expectPass) { + expect(results.steps[3].outputs.success).toBeTrue() + } else { + expect(results.steps[3]).toBeUndefined() + } + }) + }) + }) }) diff --git a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts index f477efabe4..6c89bd1f60 100644 --- a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts +++ b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts @@ -33,6 +33,7 @@ import { BranchStepInputs, SearchFilters, Branch, + FilterStepInputs, } from "@budibase/types" import TestConfiguration from "../../../tests/utilities/TestConfiguration" import * as setup from "../utilities" @@ -161,6 +162,14 @@ class BaseStepBuilder { input ) } + + filter(input: FilterStepInputs): this { + return this.step( + AutomationActionStepId.FILTER, + BUILTIN_ACTION_DEFINITIONS.FILTER, + input + ) + } } class StepBuilder extends BaseStepBuilder { build(): AutomationStep[] { From 980615b37b5b83b109278a012093ee06e9bc0e19 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 24 Sep 2024 11:08:44 +0100 Subject: [PATCH 02/11] looping query rows --- .../tests/scenarios/looping.spec.ts | 146 ++++++++++++++++++ .../tests/scenarios/scenarios.spec.ts | 2 +- 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/packages/server/src/automations/tests/scenarios/looping.spec.ts b/packages/server/src/automations/tests/scenarios/looping.spec.ts index 9bc382a187..9f7ff04156 100644 --- a/packages/server/src/automations/tests/scenarios/looping.spec.ts +++ b/packages/server/src/automations/tests/scenarios/looping.spec.ts @@ -5,6 +5,7 @@ import { LoopStepType, CreateRowStepOutputs, ServerLogStepOutputs, + FieldType, } from "@budibase/types" import { createAutomationBuilder } from "../utilities/AutomationTestBuilder" @@ -242,4 +243,149 @@ describe("Loop automations", () => { expect(results.steps[1].outputs.message).toContain("- 3") expect(results.steps[3].outputs.message).toContain("- 3") }) + + it("should run an automation with a loop and update row step", async () => { + const table = await config.createTable({ + name: "TestTable", + type: "table", + schema: { + name: { + name: "name", + type: FieldType.STRING, + constraints: { + presence: true, + }, + }, + value: { + name: "value", + type: FieldType.NUMBER, + constraints: { + presence: true, + }, + }, + }, + }) + + const rows = [ + { name: "Row 1", value: 1, tableId: table._id }, + { name: "Row 2", value: 2, tableId: table._id }, + { name: "Row 3", value: 3, tableId: table._id }, + ] + + for (const row of rows) { + await config.createRow(row) + } + + const builder = createAutomationBuilder({ + name: "Test Loop and Update Row", + }) + + const results = await builder + .appAction({ fields: {} }) + .queryRows({ + tableId: table._id!, + }) + .loop({ + option: LoopStepType.ARRAY, + binding: "{{ steps.1.rows }}", + }) + .updateRow({ + rowId: "{{ loop.currentItem._id }}", + row: { + name: "Updated {{ loop.currentItem.name }}", + value: "{{ loop.currentItem.value }}", + tableId: table._id, + }, + meta: {}, + }) + .queryRows({ + tableId: table._id!, + }) + .run() + + const expectedRows = [ + { name: "Updated Row 1", value: 1 }, + { name: "Updated Row 2", value: 2 }, + { name: "Updated Row 3", value: 3 }, + ] + + expect(results.steps[1].outputs.items).toEqual( + expect.arrayContaining( + expectedRows.map(row => + expect.objectContaining({ + success: true, + row: expect.objectContaining(row), + }) + ) + ) + ) + + expect(results.steps[2].outputs.rows).toEqual( + expect.arrayContaining( + expectedRows.map(row => expect.objectContaining(row)) + ) + ) + + expect(results.steps[1].outputs.items).toHaveLength(expectedRows.length) + expect(results.steps[2].outputs.rows).toHaveLength(expectedRows.length) + }) + + it("should run an automation with a loop and delete row step", async () => { + const table = await config.createTable({ + name: "TestTable", + type: "table", + schema: { + name: { + name: "name", + type: FieldType.STRING, + constraints: { + presence: true, + }, + }, + value: { + name: "value", + type: FieldType.NUMBER, + constraints: { + presence: true, + }, + }, + }, + }) + + const rows = [ + { name: "Row 1", value: 1, tableId: table._id }, + { name: "Row 2", value: 2, tableId: table._id }, + { name: "Row 3", value: 3, tableId: table._id }, + ] + + for (const row of rows) { + await config.createRow(row) + } + + const builder = createAutomationBuilder({ + name: "Test Loop and Delete Row", + }) + + const results = await builder + .appAction({ fields: {} }) + .queryRows({ + tableId: table._id!, + }) + .loop({ + option: LoopStepType.ARRAY, + binding: "{{ steps.1.rows }}", + }) + .deleteRow({ + tableId: table._id!, + id: "{{ loop.currentItem._id }}", + }) + .queryRows({ + tableId: table._id!, + }) + .run() + + expect(results.steps).toHaveLength(3) + + expect(results.steps[2].outputs.rows).toHaveLength(0) + }) }) diff --git a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts index 62a1b9db8f..12b8392ffc 100644 --- a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts +++ b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts @@ -197,7 +197,7 @@ describe("Automation Scenarios", () => { ) }) }) - describe.only("Automations with filter", () => { + describe("Automations with filter", () => { let table: Table beforeEach(async () => { From 0c6946af62fae3a1f17926fd7f4c2cbed72486c4 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 24 Sep 2024 15:01:05 +0100 Subject: [PATCH 03/11] more automation tests --- .../tests/scenarios/scenarios.spec.ts | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts index b54b7c0e0e..4e9340992d 100644 --- a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts +++ b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts @@ -196,6 +196,91 @@ describe("Automation Scenarios", () => { ) }) }) + + it("should trigger an automation which creates and then updates a row", async () => { + const table = await config.createTable({ + name: "TestTable", + type: "table", + schema: { + name: { + name: "name", + type: FieldType.STRING, + constraints: { + presence: true, + }, + }, + value: { + name: "value", + type: FieldType.NUMBER, + constraints: { + presence: true, + }, + }, + }, + }) + + const builder = createAutomationBuilder({ + name: "Test Create and Update Row", + }) + + const results = await builder + .appAction({ fields: {} }) + .createRow( + { + row: { + name: "Initial Row", + value: 1, + tableId: table._id, + }, + }, + { stepName: "CreateRowStep" } + ) + .updateRow( + { + rowId: "{{ steps.CreateRowStep.row._id }}", + row: { + name: "Updated Row", + value: 2, + tableId: table._id, + }, + meta: {}, + }, + { stepName: "UpdateRowStep" } + ) + .queryRows( + { + tableId: table._id!, + }, + { stepName: "QueryRowsStep" } + ) + .run() + + expect(results.steps).toHaveLength(3) + + expect(results.steps[0].outputs).toMatchObject({ + success: true, + row: { + name: "Initial Row", + value: 1, + }, + }) + + expect(results.steps[1].outputs).toMatchObject({ + success: true, + row: { + name: "Updated Row", + value: 2, + }, + }) + + const expectedRows = [{ name: "Updated Row", value: 2 }] + + expect(results.steps[2].outputs.rows).toEqual( + expect.arrayContaining( + expectedRows.map(row => expect.objectContaining(row)) + ) + ) + }) }) describe("Name Based Automations", () => { From 4a55021844c163c82d98c087a4ddf1fa2dea33db Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 24 Sep 2024 16:15:07 +0100 Subject: [PATCH 04/11] refs --- packages/account-portal | 2 +- packages/pro | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/account-portal b/packages/account-portal index 7899d07904..26903524ff 160000 --- a/packages/account-portal +++ b/packages/account-portal @@ -1 +1 @@ -Subproject commit 7899d07904d89d48954dd500da7b5dec32b781dd +Subproject commit 26903524ffb6e8f2d99b667ce7a84f09ea238073 diff --git a/packages/pro b/packages/pro index ec1d2bda75..e2fe0f9cc8 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit ec1d2bda756f02c6b4efdee086e4c59b0c2a1b0c +Subproject commit e2fe0f9cc856b4ee1a97df96d623b2d87d4e8733 From c89cebbecebfe52319a4b5f6ef0266b247d05a58 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 25 Sep 2024 16:39:49 +0100 Subject: [PATCH 05/11] ref --- packages/account-portal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account-portal b/packages/account-portal index 26903524ff..558a32dfd1 160000 --- a/packages/account-portal +++ b/packages/account-portal @@ -1 +1 @@ -Subproject commit 26903524ffb6e8f2d99b667ce7a84f09ea238073 +Subproject commit 558a32dfd1f55bd894804a503e7e1090937df88c From 44702bbfb6edda26ffa9af56434e2c38eb558512 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 26 Sep 2024 10:22:16 +0100 Subject: [PATCH 06/11] pr comments --- .../tests/scenarios/looping.spec.ts | 8 +- .../tests/scenarios/scenarios.spec.ts | 79 ++++++++++--------- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/packages/server/src/automations/tests/scenarios/looping.spec.ts b/packages/server/src/automations/tests/scenarios/looping.spec.ts index 05d82ad7ba..379927342a 100644 --- a/packages/server/src/automations/tests/scenarios/looping.spec.ts +++ b/packages/server/src/automations/tests/scenarios/looping.spec.ts @@ -299,9 +299,7 @@ describe("Loop automations", () => { { name: "Row 3", value: 3, tableId: table._id }, ] - for (const row of rows) { - await config.createRow(row) - } + await config.api.row.bulkImport(table._id!, { rows }) const builder = createAutomationBuilder({ name: "Test Loop and Update Row", @@ -385,9 +383,7 @@ describe("Loop automations", () => { { name: "Row 3", value: 3, tableId: table._id }, ] - for (const row of rows) { - await config.createRow(row) - } + await config.api.row.bulkImport(table._id!, { rows }) const builder = createAutomationBuilder({ name: "Test Loop and Delete Row", diff --git a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts index 4e9340992d..e0e2ef1cc9 100644 --- a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts +++ b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts @@ -444,43 +444,48 @@ describe("Automation Scenarios", () => { }, ] - testCases.forEach(({ condition, value, rowValue, expectPass }) => { - it(`should ${ - expectPass ? "pass" : "fail" - } the filter when condition is "${condition}" and value is ${value}`, async () => { - const builder = createAutomationBuilder({ - name: `Test ${condition}`, + it.each(testCases)( + "should pass the filter when condition is %s", + async ({ condition, value, rowValue, expectPass }) => { + it(`should ${ + expectPass ? "pass" : "fail" + } the filter when condition is "${condition}" and value is ${value}`, async () => { + const builder = createAutomationBuilder({ + name: `Test ${condition}`, + }) + + const results = await builder + .appAction({ fields: {} }) + .createRow({ + row: { + name: `${condition} Test`, + value: rowValue, + tableId: table._id, + }, + }) + .queryRows({ + tableId: table._id!, + }) + .filter({ + field: "{{ steps.2.rows.0.value }}", + condition, + value, + }) + .serverLog({ + text: `${condition} condition ${ + expectPass ? "passed" : "failed" + }`, + }) + .run() + + expect(results.steps[2].outputs.result).toBe(expectPass) + if (expectPass) { + expect(results.steps[3].outputs.success).toBeTrue() + } else { + expect(results.steps[3]).toBeUndefined() + } }) - - const results = await builder - .appAction({ fields: {} }) - .createRow({ - row: { - name: `${condition} Test`, - value: rowValue, - tableId: table._id, - }, - }) - .queryRows({ - tableId: table._id!, - }) - .filter({ - field: "{{ steps.2.rows.0.value }}", - condition, - value, - }) - .serverLog({ - text: `${condition} condition ${expectPass ? "passed" : "failed"}`, - }) - .run() - - expect(results.steps[2].outputs.result).toBe(expectPass) - if (expectPass) { - expect(results.steps[3].outputs.success).toBeTrue() - } else { - expect(results.steps[3]).toBeUndefined() - } - }) - }) + } + ) }) }) From 4bc30a018739f8e00c071783334920d1caf54e2e Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 26 Sep 2024 11:50:03 +0100 Subject: [PATCH 07/11] pr comment --- .../tests/scenarios/scenarios.spec.ts | 70 +++++++++---------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts index e0e2ef1cc9..850a04a95a 100644 --- a/packages/server/src/automations/tests/scenarios/scenarios.spec.ts +++ b/packages/server/src/automations/tests/scenarios/scenarios.spec.ts @@ -445,46 +445,40 @@ describe("Automation Scenarios", () => { ] it.each(testCases)( - "should pass the filter when condition is %s", + "should pass the filter when condition is $condition", async ({ condition, value, rowValue, expectPass }) => { - it(`should ${ - expectPass ? "pass" : "fail" - } the filter when condition is "${condition}" and value is ${value}`, async () => { - const builder = createAutomationBuilder({ - name: `Test ${condition}`, - }) - - const results = await builder - .appAction({ fields: {} }) - .createRow({ - row: { - name: `${condition} Test`, - value: rowValue, - tableId: table._id, - }, - }) - .queryRows({ - tableId: table._id!, - }) - .filter({ - field: "{{ steps.2.rows.0.value }}", - condition, - value, - }) - .serverLog({ - text: `${condition} condition ${ - expectPass ? "passed" : "failed" - }`, - }) - .run() - - expect(results.steps[2].outputs.result).toBe(expectPass) - if (expectPass) { - expect(results.steps[3].outputs.success).toBeTrue() - } else { - expect(results.steps[3]).toBeUndefined() - } + const builder = createAutomationBuilder({ + name: `Test ${condition}`, }) + + const results = await builder + .appAction({ fields: {} }) + .createRow({ + row: { + name: `${condition} Test`, + value: rowValue, + tableId: table._id, + }, + }) + .queryRows({ + tableId: table._id!, + }) + .filter({ + field: "{{ steps.2.rows.0.value }}", + condition, + value, + }) + .serverLog({ + text: `${condition} condition ${expectPass ? "passed" : "failed"}`, + }) + .run() + + expect(results.steps[2].outputs.result).toBe(expectPass) + if (expectPass) { + expect(results.steps[3].outputs.success).toBeTrue() + } else { + expect(results.steps[3]).toBeUndefined() + } } ) }) From fd3cedbccf951441d658244b7236369710443302 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 26 Sep 2024 15:06:14 +0100 Subject: [PATCH 08/11] move premium badge to top of AI config, add AzureOpenAI logo --- .../builder/portal/settings/ai/index.svelte | 27 ++++++++++--------- .../settings/ai/logos/AzureOpenAI.svelte | 1 + .../builder/portal/settings/index.svelte | 7 ++++- 3 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 packages/builder/src/pages/builder/portal/settings/ai/logos/AzureOpenAI.svelte diff --git a/packages/builder/src/pages/builder/portal/settings/ai/index.svelte b/packages/builder/src/pages/builder/portal/settings/ai/index.svelte index b60ea24dbc..f5fe106daa 100644 --- a/packages/builder/src/pages/builder/portal/settings/ai/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/ai/index.svelte @@ -127,18 +127,8 @@ - AI - {#if isCloud && !budibaseAIEnabled} - - Premium - - {/if} - Configure your AI settings within this section: - - - -
- AI Configurations +
+ AI {#if !isCloud && !customAIConfigsEnabled} Premium @@ -151,6 +141,13 @@ {/if}
+ Configure your AI settings within this section: + + + +
+ AI Configurations +
Use the following interface to select your preferred AI configuration. @@ -173,4 +170,10 @@ justify-content: space-between; align-items: center; } + + .header { + display: flex; + align-items: center; + gap: 12px; + } diff --git a/packages/builder/src/pages/builder/portal/settings/ai/logos/AzureOpenAI.svelte b/packages/builder/src/pages/builder/portal/settings/ai/logos/AzureOpenAI.svelte new file mode 100644 index 0000000000..ca727c2ed1 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/settings/ai/logos/AzureOpenAI.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/builder/src/pages/builder/portal/settings/index.svelte b/packages/builder/src/pages/builder/portal/settings/index.svelte index 09ead3e410..1448b43ec4 100644 --- a/packages/builder/src/pages/builder/portal/settings/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/index.svelte @@ -1,5 +1,10 @@ From e65a9157ccfe2abf51c4d1609a2c4b3be0b9f1a5 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 26 Sep 2024 17:14:20 +0100 Subject: [PATCH 09/11] opacity/custom config updates, fix tests --- .../portal/settings/ai/AIConfigTile.svelte | 6 +- .../portal/settings/ai/AISettings.spec.js | 38 ++++++----- .../portal/settings/ai/ConfigModal.svelte | 6 +- .../builder/portal/settings/ai/constants.js | 2 +- .../builder/portal/settings/ai/index.svelte | 53 +++++++++------ .../settings/ai/logos/AzureOpenAI.svelte | 65 ++++++++++++++++++- 6 files changed, 127 insertions(+), 43 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/settings/ai/AIConfigTile.svelte b/packages/builder/src/pages/builder/portal/settings/ai/AIConfigTile.svelte index 2907919ce7..a95d14b273 100644 --- a/packages/builder/src/pages/builder/portal/settings/ai/AIConfigTile.svelte +++ b/packages/builder/src/pages/builder/portal/settings/ai/AIConfigTile.svelte @@ -4,6 +4,7 @@ import OpenAILogo from "./logos/OpenAI.svelte" import AnthropicLogo from "./logos/Anthropic.svelte" import TogetherAILogo from "./logos/TogetherAI.svelte" + import AzureOpenAILogo from "./logos/AzureOpenAI.svelte" import { Providers } from "./constants" const logos = { @@ -11,6 +12,7 @@ [Providers.OpenAI.name]: OpenAILogo, [Providers.Anthropic.name]: AnthropicLogo, [Providers.TogetherAI.name]: TogetherAILogo, + [Providers.AzureOpenAI.name]: AzureOpenAILogo, } export let config @@ -26,8 +28,8 @@
diff --git a/packages/builder/src/pages/builder/portal/settings/ai/AISettings.spec.js b/packages/builder/src/pages/builder/portal/settings/ai/AISettings.spec.js index fafead1ebf..300d5d5369 100644 --- a/packages/builder/src/pages/builder/portal/settings/ai/AISettings.spec.js +++ b/packages/builder/src/pages/builder/portal/settings/ai/AISettings.spec.js @@ -1,6 +1,6 @@ import { it, expect, describe, vi } from "vitest" import AISettings from "./index.svelte" -import { render } from "@testing-library/svelte" +import { render, fireEvent } from "@testing-library/svelte" import { admin, licensing } from "stores/portal" import { notifications } from "@budibase/bbui" @@ -55,39 +55,43 @@ describe("AISettings", () => { expect(enterpriseTag).toBeInTheDocument() }) - it("should show the premium label on cloud when Budibase AI isn't enabled", async () => { - setupEnv(Hosting.Cloud) - instance = render(AISettings, {}) - const premiumTag = instance.queryByText("Premium") - expect(premiumTag).toBeInTheDocument() - }) - - it("should not show the add configuration button if the user doesn't have the correct license on cloud", async () => { + it("the add configuration button should not do anything the user doesn't have the correct license on cloud", async () => { let addConfigurationButton + let configModal setupEnv(Hosting.Cloud) instance = render(AISettings) addConfigurationButton = instance.queryByText("Add configuration") - expect(addConfigurationButton).not.toBeInTheDocument() + expect(addConfigurationButton).toBeInTheDocument() + await fireEvent.click(addConfigurationButton) + configModal = instance.queryByText("Custom AI Configuration") + expect(configModal).not.toBeInTheDocument() + }) + + it("the add configuration button should open the config modal if the user has the correct license on cloud", async () => { + let addConfigurationButton + let configModal setupEnv(Hosting.Cloud, { customAIConfigsEnabled: true }) instance = render(AISettings) addConfigurationButton = instance.queryByText("Add configuration") expect(addConfigurationButton).toBeInTheDocument() + await fireEvent.click(addConfigurationButton) + configModal = instance.queryByText("Custom AI Configuration") + expect(configModal).toBeInTheDocument() }) - it("should not show the add configuration button if the user doesn't have the correct license on self host", async () => { + it("the add configuration button should open the config modal if the user has the correct license on self host", async () => { let addConfigurationButton - - setupEnv(Hosting.Self) - instance = render(AISettings) - addConfigurationButton = instance.queryByText("Add configuration") - expect(addConfigurationButton).not.toBeInTheDocument() + let configModal setupEnv(Hosting.Self, { customAIConfigsEnabled: true }) - instance = render(AISettings, {}) + instance = render(AISettings) addConfigurationButton = instance.queryByText("Add configuration") expect(addConfigurationButton).toBeInTheDocument() + await fireEvent.click(addConfigurationButton) + configModal = instance.queryByText("Custom AI Configuration") + expect(configModal).toBeInTheDocument() }) }) }) diff --git a/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte b/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte index d480689028..26e7a1606c 100644 --- a/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte +++ b/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte @@ -84,8 +84,10 @@
- - +
+ + +