Merge branch 'master' into default-app-design

This commit is contained in:
Andrew Kingston 2025-03-13 11:16:26 +00:00 committed by GitHub
commit 99403c29e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 241 additions and 33 deletions

View File

@ -56,7 +56,10 @@
memo,
fetchData,
} from "@budibase/frontend-core"
import { getSchemaForDatasourcePlus } from "@/dataBinding"
import {
getSchemaForDatasourcePlus,
readableToRuntimeBinding,
} from "@/dataBinding"
import { TriggerStepID, ActionStepID } from "@/constants/backend/automations"
import { onMount, createEventDispatcher } from "svelte"
import { writable } from "svelte/store"
@ -1034,7 +1037,10 @@
{bindings}
{schema}
panel={AutomationBindingPanel}
on:change={e => onChange({ [key]: e.detail })}
on:change={e =>
onChange({
[key]: readableToRuntimeBinding(bindings, e.detail),
})}
context={$memoContext}
value={inputData[key]}
/>

View File

@ -37,7 +37,7 @@ const { ContextScopes } = Constants
// Regex to match all instances of template strings
const CAPTURE_VAR_INSIDE_TEMPLATE = /{{([^}]+)}}/g
const CAPTURE_VAR_INSIDE_JS = /\$\("([^")]+)"\)/g
const CAPTURE_VAR_INSIDE_JS = /\$\((["'`])([^"'`]+)\1\)/g
const CAPTURE_HBS_TEMPLATE = /{{[\S\s]*?}}/g
const UpdateReferenceAction = {

View File

@ -0,0 +1,28 @@
import {
CreateOAuth2ConfigRequest,
Ctx,
FetchOAuth2ConfigsResponse,
OAuth2Config,
RequiredKeys,
} from "@budibase/types"
import sdk from "../../sdk"
export async function fetch(ctx: Ctx<void, FetchOAuth2ConfigsResponse>) {
const configs = await sdk.oauth2.fetch()
const response: FetchOAuth2ConfigsResponse = {
configs: (configs || []).map(c => ({
name: c.name,
})),
}
ctx.body = response
}
export async function create(ctx: Ctx<CreateOAuth2ConfigRequest, void>) {
const newConfig: RequiredKeys<OAuth2Config> = {
name: ctx.request.body.name,
}
await sdk.oauth2.create(newConfig)
ctx.status = 201
}

View File

@ -29,6 +29,7 @@ import debugRoutes from "./debug"
import Router from "@koa/router"
import { api as pro } from "@budibase/pro"
import rowActionRoutes from "./rowAction"
import oauth2Routes from "./oauth2"
export { default as staticRoutes } from "./static"
export { default as publicRoutes } from "./public"
@ -69,6 +70,7 @@ export const mainRoutes: Router[] = [
environmentVariableRoutes,
rowActionRoutes,
proAiRoutes,
oauth2Routes,
// these need to be handled last as they still use /api/:tableId
// this could be breaking as koa may recognise other routes as this
tableRoutes,

View File

@ -0,0 +1,16 @@
import Router from "@koa/router"
import { PermissionType } from "@budibase/types"
import authorized from "../../middleware/authorized"
import * as controller from "../controllers/oauth2"
const router: Router = new Router()
router.get("/api/oauth2", authorized(PermissionType.BUILDER), controller.fetch)
router.post(
"/api/oauth2",
authorized(PermissionType.BUILDER),
controller.create
)
export default router

View File

@ -0,0 +1,79 @@
import { CreateOAuth2ConfigRequest } from "@budibase/types"
import * as setup from "./utilities"
import { generator } from "@budibase/backend-core/tests"
describe("/oauth2", () => {
let config = setup.getConfig()
function makeOAuth2Config(): CreateOAuth2ConfigRequest {
return {
name: generator.guid(),
}
}
beforeAll(async () => await config.init())
beforeEach(async () => await config.newTenant())
describe("fetch", () => {
it("returns empty when no oauth are created", async () => {
const response = await config.api.oauth2.fetch()
expect(response).toEqual({
configs: [],
})
})
})
describe("create", () => {
it("can create a new configuration", async () => {
const oauth2Config = makeOAuth2Config()
await config.api.oauth2.create(oauth2Config, { status: 201 })
const response = await config.api.oauth2.fetch()
expect(response).toEqual({
configs: [
{
name: oauth2Config.name,
},
],
})
})
it("can create multiple configurations", async () => {
const oauth2Config = makeOAuth2Config()
const oauth2Config2 = makeOAuth2Config()
await config.api.oauth2.create(oauth2Config, { status: 201 })
await config.api.oauth2.create(oauth2Config2, { status: 201 })
const response = await config.api.oauth2.fetch()
expect(response.configs).toEqual([
{
name: oauth2Config.name,
},
{
name: oauth2Config2.name,
},
])
})
it("cannot create configurations with already existing names", async () => {
const oauth2Config = makeOAuth2Config()
const oauth2Config2 = { ...makeOAuth2Config(), name: oauth2Config.name }
await config.api.oauth2.create(oauth2Config, { status: 201 })
await config.api.oauth2.create(oauth2Config2, {
status: 400,
body: {
message: "Name already used",
status: 400,
},
})
const response = await config.api.oauth2.fetch()
expect(response.configs).toEqual([
{
name: oauth2Config.name,
},
])
})
})
})

View File

@ -0,0 +1,28 @@
import { context, HTTPError } from "@budibase/backend-core"
import { DocumentType, OAuth2Config, OAuth2Configs } from "@budibase/types"
export async function fetch(): Promise<OAuth2Config[]> {
const db = context.getAppDB()
const result = await db.tryGet<OAuth2Configs>(DocumentType.OAUTH2_CONFIG)
if (!result) {
return []
}
return Object.values(result.configs)
}
export async function create(config: OAuth2Config) {
const db = context.getAppDB()
const doc: OAuth2Configs = (await db.tryGet<OAuth2Configs>(
DocumentType.OAUTH2_CONFIG
)) ?? {
_id: DocumentType.OAUTH2_CONFIG,
configs: {},
}
if (doc.configs[config.name]) {
throw new HTTPError("Name already used", 400)
}
doc.configs[config.name] = config
await db.put(doc)
}

View File

@ -13,6 +13,7 @@ import * as permissions from "./app/permissions"
import * as rowActions from "./app/rowActions"
import * as screens from "./app/screens"
import * as common from "./app/common"
import * as oauth2 from "./app/oauth2"
const sdk = {
backups,
@ -30,6 +31,7 @@ const sdk = {
links,
rowActions,
common,
oauth2,
}
// default export for TS

View File

@ -20,6 +20,7 @@ import { WebhookAPI } from "./webhook"
import { EnvironmentAPI } from "./environment"
import { UserPublicAPI } from "./public/user"
import { MiscAPI } from "./misc"
import { OAuth2API } from "./oauth2"
export default class API {
application: ApplicationAPI
@ -30,6 +31,7 @@ export default class API {
environment: EnvironmentAPI
legacyView: LegacyViewAPI
misc: MiscAPI
oauth2: OAuth2API
permission: PermissionAPI
plugin: PluginAPI
query: QueryAPI
@ -56,6 +58,7 @@ export default class API {
this.environment = new EnvironmentAPI(config)
this.legacyView = new LegacyViewAPI(config)
this.misc = new MiscAPI(config)
this.oauth2 = new OAuth2API(config)
this.permission = new PermissionAPI(config)
this.plugin = new PluginAPI(config)
this.query = new QueryAPI(config)

View File

@ -0,0 +1,23 @@
import {
CreateOAuth2ConfigRequest,
FetchOAuth2ConfigsResponse,
} from "@budibase/types"
import { Expectations, TestAPI } from "./base"
export class OAuth2API extends TestAPI {
fetch = async (expectations?: Expectations) => {
return await this._get<FetchOAuth2ConfigsResponse>("/api/oauth2", {
expectations,
})
}
create = async (
body: CreateOAuth2ConfigRequest,
expectations?: Expectations
) => {
return await this._post<CreateOAuth2ConfigRequest>("/api/oauth2", {
body,
expectations,
})
}
}

View File

@ -1,21 +1,22 @@
export * from "./backup"
export * from "./datasource"
export * from "./view"
export * from "./rows"
export * from "./table"
export * from "./permission"
export * from "./attachment"
export * from "./user"
export * from "./rowAction"
export * from "./automation"
export * from "./component"
export * from "./integration"
export * from "./metadata"
export * from "./query"
export * from "./screen"
export * from "./application"
export * from "./layout"
export * from "./attachment"
export * from "./automation"
export * from "./backup"
export * from "./component"
export * from "./datasource"
export * from "./deployment"
export * from "./integration"
export * from "./layout"
export * from "./metadata"
export * from "./oauth2"
export * from "./permission"
export * from "./query"
export * from "./role"
export * from "./webhook"
export * from "./rowAction"
export * from "./rows"
export * from "./screen"
export * from "./static"
export * from "./table"
export * from "./user"
export * from "./view"
export * from "./webhook"

View File

@ -0,0 +1,9 @@
interface OAuth2Config {
name: string
}
export interface FetchOAuth2ConfigsResponse {
configs: OAuth2Config[]
}
export interface CreateOAuth2ConfigRequest extends OAuth2Config {}

View File

@ -1,22 +1,23 @@
export * from "../document"
export * from "./app"
export * from "./automation"
export * from "./backup"
export * from "./component"
export * from "./datasource"
export * from "./deployment"
export * from "./layout"
export * from "./links"
export * from "./metadata"
export * from "./oauth2"
export * from "./query"
export * from "./role"
export * from "./table"
export * from "./screen"
export * from "./view"
export * from "../document"
export * from "./row"
export * from "./user"
export * from "./backup"
export * from "./webhook"
export * from "./links"
export * from "./component"
export * from "./sqlite"
export * from "./snippet"
export * from "./rowAction"
export * from "./screen"
export * from "./snippet"
export * from "./sqlite"
export * from "./table"
export * from "./theme"
export * from "./deployment"
export * from "./metadata"
export * from "./user"
export * from "./view"
export * from "./webhook"

View File

@ -0,0 +1,9 @@
import { Document } from "../document"
export interface OAuth2Config {
name: string
}
export interface OAuth2Configs extends Document {
configs: Record<string, OAuth2Config>
}

View File

@ -40,6 +40,7 @@ export enum DocumentType {
APP_MIGRATION_METADATA = "_design/migrations",
SCIM_LOG = "scimlog",
ROW_ACTIONS = "ra",
OAUTH2_CONFIG = "oauth2",
}
// Because DocumentTypes can overlap, we need to make sure that we search