Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Budi 8677 ai column type v1 #14711

Merged
merged 26 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/backend-core/src/constants/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export enum Config {
OIDC = "oidc",
OIDC_LOGOS = "logos_oidc",
SCIM = "scim",
AI = "AI",
}

export const MIN_VALID_DATE = new Date(-2147483647000)
Expand Down
3 changes: 2 additions & 1 deletion packages/backend-core/src/sql/sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,8 @@ class InternalBuilder {
schema.constraints?.presence === true ||
schema.type === FieldType.FORMULA ||
schema.type === FieldType.AUTO ||
schema.type === FieldType.LINK
schema.type === FieldType.LINK ||
schema.type === FieldType.AI
) {
continue
}
Expand Down
5 changes: 4 additions & 1 deletion packages/backend-core/src/sql/sqlTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import SchemaBuilder = Knex.SchemaBuilder
import CreateTableBuilder = Knex.CreateTableBuilder

function isIgnoredType(type: FieldType) {
const ignored = [FieldType.LINK, FieldType.FORMULA]
const ignored = [FieldType.LINK, FieldType.FORMULA, FieldType.AI]
return ignored.indexOf(type) !== -1
}

Expand Down Expand Up @@ -144,6 +144,9 @@ function generateSchema(
case FieldType.FORMULA:
// This is allowed, but nothing to do on the external datasource
break
case FieldType.AI:
// This is allowed, but nothing to do on the external datasource
break
case FieldType.ATTACHMENTS:
case FieldType.ATTACHMENT_SINGLE:
case FieldType.SIGNATURE_SINGLE:
Expand Down
8 changes: 8 additions & 0 deletions packages/backend-core/tests/core/utilities/mocks/licenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ export const useAppBuilders = () => {
return useFeature(Feature.APP_BUILDERS)
}

export const useBudibaseAI = () => {
return useFeature(Feature.BUDIBASE_AI)
}

export const useAICustomConfigs = () => {
return useFeature(Feature.AI_CUSTOM_CONFIGS)
}

// QUOTAS

export const setAutomationLogsQuota = (value: number) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import { createEventDispatcher, getContext, onMount } from "svelte"
import { cloneDeep } from "lodash/fp"
import { tables, datasources } from "stores/builder"
import { licensing } from "stores/portal"
import { TableNames, UNEDITABLE_USER_FIELDS } from "constants"
import {
FIELDS,
Expand All @@ -35,6 +36,7 @@
} from "constants/backend"
import { getAutoColumnInformation, buildAutoColumn } from "helpers/utils"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import AIFieldConfiguration from "components/common/AIFieldConfiguration.svelte"
import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
import { getBindings } from "components/backend/DataTable/formula"
import JSONSchemaModal from "./JSONSchemaModal.svelte"
Expand Down Expand Up @@ -99,6 +101,8 @@
let optionsValid = true

$: rowGoldenSample = RowUtils.generateGoldenSample($rows)
$: aiEnabled =
$licensing.customAIConfigsEnabled || $licensing.budibaseAIEnabled
$: if (primaryDisplay) {
editableColumn.constraints.presence = { allowEmpty: false }
}
Expand Down Expand Up @@ -447,6 +451,7 @@
FIELDS.BOOLEAN,
FIELDS.DATETIME,
FIELDS.LINK,
...(aiEnabled ? [FIELDS.AI] : []),
FIELDS.LONGFORM,
FIELDS.USER,
FIELDS.USERS,
Expand Down Expand Up @@ -784,6 +789,13 @@
/>
</div>
</div>
{:else if editableColumn.type === FieldType.AI}
<AIFieldConfiguration
aiField={editableColumn}
context={rowGoldenSample}
bindings={getBindings({ table })}
schema={table.schema}
/>
{:else if editableColumn.type === FieldType.JSON}
<Button primary text on:click={openJsonSchemaEditor}>
Open schema editor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { FIELDS } from "constants/backend"

const FORMULA_TYPE = FIELDS.FORMULA.type
const AI_TYPE = FIELDS.AI.type

export let row = {}

Expand Down Expand Up @@ -60,7 +61,7 @@
}}
>
{#each tableSchema as [key, meta]}
{#if !meta.autocolumn && meta.type !== FORMULA_TYPE}
{#if !meta.autocolumn && meta.type !== FORMULA_TYPE && meta.type !== AI_TYPE}
<div>
<RowFieldControl error={errors[key]} {meta} bind:value={row[key]} />
</div>
Expand Down
59 changes: 59 additions & 0 deletions packages/builder/src/components/common/AIFieldConfiguration.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script>
import { Helpers, Multiselect, Select } from "@budibase/bbui"
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
import {
AIOperations,
OperationFields,
OperationFieldTypes,
} from "@budibase/shared-core"

const AIFieldConfigOptions = Object.keys(AIOperations).map(key => ({
label: AIOperations[key].label,
value: AIOperations[key].value,
}))

export let bindings
export let context
export let schema
export let aiField = {}

$: OperationField = OperationFields[aiField.operation]
$: schemaWithoutRelations = Object.keys(schema).filter(
key => schema[key].type !== "link"
)
</script>

<Select
label={"Operation"}
options={AIFieldConfigOptions}
bind:value={aiField.operation}
/>
{#if aiField.operation}
{#each Object.keys(OperationField) as key}
{#if OperationField[key] === OperationFieldTypes.BINDABLE_TEXT}
<ModalBindableInput
label={Helpers.capitalise(key)}
panel={ServerBindingPanel}
title="Prompt"
on:change={e => (aiField[key] = e.detail)}
value={aiField[key]}
{bindings}
allowJS
{context}
/>
{:else if OperationField[key] === OperationFieldTypes.MULTI_COLUMN}
<Multiselect
bind:value={aiField[key]}
label={Helpers.capitalise(key)}
options={schemaWithoutRelations}
/>
{:else if OperationField[key] === OperationFieldTypes.COLUMN}
<Select
bind:value={aiField[key]}
label={Helpers.capitalise(key)}
options={schemaWithoutRelations}
/>
{/if}
{/each}
{/if}
6 changes: 6 additions & 0 deletions packages/builder/src/constants/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ export const FIELDS = {
icon: TypeIconMap[FieldType.FORMULA],
constraints: {},
},
AI: {
name: "AI",
type: FieldType.AI,
icon: TypeIconMap[FieldType.AI],
constraints: {},
},
JSON: {
name: "JSON",
type: FieldType.JSON,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script>
import { viewsV2, rowActions } from "stores/builder"
import { admin, themeStore } from "stores/portal"
import { admin, themeStore, licensing } from "stores/portal"
import { Grid } from "@budibase/frontend-core"
import { API } from "api"
import { notifications } from "@budibase/bbui"
Expand Down Expand Up @@ -49,6 +49,7 @@
{buttons}
allowAddRows
allowDeleteRows
licensing={$licensing}
showAvatars={false}
on:updatedatasource={handleGridViewUpdate}
isCloud={$admin.cloud}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
appStore,
rowActions,
} from "stores/builder"
import { themeStore, admin } from "stores/portal"
import { themeStore, admin, licensing } from "stores/portal"
import { TableNames } from "constants"
import { Grid } from "@budibase/frontend-core"
import { API } from "api"
Expand Down Expand Up @@ -125,6 +125,7 @@
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
showAvatars={false}
isCloud={$admin.cloud}
licensing={$licensing}
{buttons}
buttonsCollapsed
on:updatedatasource={handleGridTableUpdate}
Expand Down
99 changes: 99 additions & 0 deletions packages/frontend-core/src/components/grid/cells/AICell.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<script>
import { onMount } from "svelte"
import { clickOutside } from "@budibase/bbui"
import GridPopover from "../overlays/GridPopover.svelte"

export let value
export let focused = false
export let api

let textarea
let isOpen = false
let anchor

$: {
if (!focused) {
isOpen = false
}
}

const onKeyDown = () => {
return isOpen
}

const open = async () => {
isOpen = true
}

const close = () => {
textarea?.blur()
isOpen = false
}

onMount(() => {
api = {
focus: () => open(),
blur: () => close(),
isActive: () => isOpen,
onKeyDown,
}
})
</script>

<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="long-form-cell" on:click={open} bind:this={anchor}>
<div class="value">
{value || ""}
</div>
</div>

{#if isOpen}
<GridPopover {anchor} on:close={close}>
<textarea
disabled
bind:this={textarea}
value={value || ""}
on:wheel|stopPropagation
spellcheck="false"
use:clickOutside={close}
/>
</GridPopover>
{/if}

<style>
.long-form-cell {
flex: 1 1 auto;
padding: var(--cell-padding);
align-self: stretch;
display: flex;
align-items: flex-start;
overflow: hidden;
}
.value {
display: -webkit-box;
-webkit-line-clamp: var(--content-lines);
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 20px;
}
textarea {
border: none;
width: 320px;
flex: 1 1 auto;
height: var(--max-cell-render-overflow);
padding: var(--cell-padding);
margin: 0;
background: var(--cell-background);
font-size: var(--cell-font-size);
font-family: var(--font-sans);
color: inherit;
z-index: 1;
resize: none;
line-height: 20px;
overflow: auto;
}
textarea:focus {
outline: none;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@
const { type, formulaType } = col.schema
return (
searchableTypes.includes(type) ||
(type === FieldType.FORMULA && formulaType === FormulaType.STATIC)
(type === FieldType.FORMULA && formulaType === FormulaType.STATIC) ||
type === FieldType.AI
)
}

Expand Down
2 changes: 2 additions & 0 deletions packages/frontend-core/src/components/grid/layout/Grid.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
export let darkMode = false
export let isCloud = null
export let rowConditions = null
export let licensing = null

// Unique identifier for DOM nodes inside this instance
const gridID = `grid-${Math.random().toString().slice(2)}`
Expand Down Expand Up @@ -104,6 +105,7 @@
buttonsCollapsedText,
darkMode,
isCloud,
licensing,
rowConditions,
})

Expand Down
2 changes: 2 additions & 0 deletions packages/frontend-core/src/components/grid/lib/renderers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import TextCell from "../cells/TextCell.svelte"
import LongFormCell from "../cells/LongFormCell.svelte"
import BooleanCell from "../cells/BooleanCell.svelte"
import FormulaCell from "../cells/FormulaCell.svelte"
import AICell from "../cells/AICell.svelte"
import JSONCell from "../cells/JSONCell.svelte"
import AttachmentCell from "../cells/AttachmentCell.svelte"
import AttachmentSingleCell from "../cells/AttachmentSingleCell.svelte"
Expand All @@ -30,6 +31,7 @@ const TypeComponentMap = {
[FieldType.ATTACHMENT_SINGLE]: AttachmentSingleCell,
[FieldType.LINK]: RelationshipCell,
[FieldType.FORMULA]: FormulaCell,
[FieldType.AI]: AICell,
[FieldType.JSON]: JSONCell,
[FieldType.BB_REFERENCE]: BBReferenceCell,
[FieldType.BB_REFERENCE_SINGLE]: BBReferenceSingleCell,
Expand Down
Loading
Loading