Merge branch 'master' into fix/user-fetch

This commit is contained in:
Adria Navarro 2025-01-10 16:28:27 +01:00 committed by GitHub
commit da5f49bacc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 276 additions and 206 deletions

View File

@ -1,130 +0,0 @@
import { writable, get, derived } from "svelte/store"
import { datasources } from "./datasources"
import { integrations } from "./integrations"
import { API } from "@/api"
import { duplicateName } from "@/helpers/duplicate"
const sortQueries = queryList => {
queryList.sort((q1, q2) => {
return q1.name.localeCompare(q2.name)
})
}
export function createQueriesStore() {
const store = writable({
list: [],
selectedQueryId: null,
})
const derivedStore = derived(store, $store => ({
...$store,
selected: $store.list?.find(q => q._id === $store.selectedQueryId),
}))
const fetch = async () => {
const queries = await API.getQueries()
sortQueries(queries)
store.update(state => ({
...state,
list: queries,
}))
}
const save = async (datasourceId, query) => {
const _integrations = get(integrations)
const dataSource = get(datasources).list.filter(
ds => ds._id === datasourceId
)
// Check if readable attribute is found
if (dataSource.length !== 0) {
const integration = _integrations[dataSource[0].source]
const readable = integration.query[query.queryVerb].readable
if (readable) {
query.readable = readable
}
}
query.datasourceId = datasourceId
const savedQuery = await API.saveQuery(query)
store.update(state => {
const idx = state.list.findIndex(query => query._id === savedQuery._id)
const queries = state.list
if (idx >= 0) {
queries.splice(idx, 1, savedQuery)
} else {
queries.push(savedQuery)
}
sortQueries(queries)
return {
list: queries,
selectedQueryId: savedQuery._id,
}
})
return savedQuery
}
const importQueries = async ({ data, datasourceId }) => {
return await API.importQueries(datasourceId, data)
}
const select = id => {
store.update(state => ({
...state,
selectedQueryId: id,
}))
}
const preview = async query => {
const result = await API.previewQuery(query)
// Assume all the fields are strings and create a basic schema from the
// unique fields returned by the server
const schema = {}
for (let [field, metadata] of Object.entries(result.schema)) {
schema[field] = metadata || { type: "string" }
}
return { ...result, schema, rows: result.rows || [] }
}
const deleteQuery = async query => {
await API.deleteQuery(query._id, query._rev)
store.update(state => {
state.list = state.list.filter(existing => existing._id !== query._id)
return state
})
}
const duplicate = async query => {
let list = get(store).list
const newQuery = { ...query }
const datasourceId = query.datasourceId
delete newQuery._id
delete newQuery._rev
newQuery.name = duplicateName(
query.name,
list.map(q => q.name)
)
return await save(datasourceId, newQuery)
}
const removeDatasourceQueries = datasourceId => {
store.update(state => ({
...state,
list: state.list.filter(table => table.datasourceId !== datasourceId),
}))
}
return {
subscribe: derivedStore.subscribe,
fetch,
init: fetch,
select,
save,
import: importQueries,
delete: deleteQuery,
preview,
duplicate,
removeDatasourceQueries,
}
}
export const queries = createQueriesStore()

View File

@ -0,0 +1,156 @@
import { derived, get, Writable } from "svelte/store"
import { datasources } from "./datasources"
import { integrations } from "./integrations"
import { API } from "@/api"
import { duplicateName } from "@/helpers/duplicate"
import { DerivedBudiStore } from "@/stores/BudiStore"
import {
Query,
QueryPreview,
PreviewQueryResponse,
SaveQueryRequest,
ImportRestQueryRequest,
QuerySchema,
} from "@budibase/types"
const sortQueries = (queryList: Query[]) => {
queryList.sort((q1, q2) => {
return q1.name.localeCompare(q2.name)
})
}
interface BuilderQueryStore {
list: Query[]
selectedQueryId: string | null
}
interface DerivedQueryStore extends BuilderQueryStore {
selected?: Query
}
export class QueryStore extends DerivedBudiStore<
BuilderQueryStore,
DerivedQueryStore
> {
constructor() {
const makeDerivedStore = (store: Writable<BuilderQueryStore>) => {
return derived(store, ($store): DerivedQueryStore => {
return {
list: $store.list,
selectedQueryId: $store.selectedQueryId,
selected: $store.list?.find(q => q._id === $store.selectedQueryId),
}
})
}
super(
{
list: [],
selectedQueryId: null,
},
makeDerivedStore
)
this.select = this.select.bind(this)
}
async fetch() {
const queries = await API.getQueries()
sortQueries(queries)
this.store.update(state => ({
...state,
list: queries,
}))
}
async save(datasourceId: string, query: SaveQueryRequest) {
const _integrations = get(integrations)
const dataSource = get(datasources).list.filter(
ds => ds._id === datasourceId
)
// Check if readable attribute is found
if (dataSource.length !== 0) {
const integration = _integrations[dataSource[0].source]
const readable = integration.query[query.queryVerb].readable
if (readable) {
query.readable = readable
}
}
query.datasourceId = datasourceId
const savedQuery = await API.saveQuery(query)
this.store.update(state => {
const idx = state.list.findIndex(query => query._id === savedQuery._id)
const queries = state.list
if (idx >= 0) {
queries.splice(idx, 1, savedQuery)
} else {
queries.push(savedQuery)
}
sortQueries(queries)
return {
list: queries,
selectedQueryId: savedQuery._id || null,
}
})
return savedQuery
}
async importQueries(data: ImportRestQueryRequest) {
return await API.importQueries(data)
}
select(id: string | null) {
this.store.update(state => ({
...state,
selectedQueryId: id,
}))
}
async preview(query: QueryPreview): Promise<PreviewQueryResponse> {
const result = await API.previewQuery(query)
// Assume all the fields are strings and create a basic schema from the
// unique fields returned by the server
const schema: Record<string, QuerySchema> = {}
for (let [field, metadata] of Object.entries(result.schema)) {
schema[field] = (metadata as QuerySchema) || { type: "string" }
}
return { ...result, schema, rows: result.rows || [] }
}
async delete(query: Query) {
if (!query._id || !query._rev) {
throw new Error("Query ID or Revision is missing")
}
await API.deleteQuery(query._id, query._rev)
this.store.update(state => ({
...state,
list: state.list.filter(existing => existing._id !== query._id),
}))
}
async duplicate(query: Query) {
let list = get(this.store).list
const newQuery = { ...query }
const datasourceId = query.datasourceId
delete newQuery._id
delete newQuery._rev
newQuery.name = duplicateName(
query.name,
list.map(q => q.name)
)
return await this.save(datasourceId, newQuery)
}
removeDatasourceQueries(datasourceId: string) {
this.store.update(state => ({
...state,
list: state.list.filter(table => table.datasourceId !== datasourceId),
}))
}
init = this.fetch
}
export const queries = new QueryStore()

View File

@ -29,7 +29,7 @@ import { ActionTypes } from "./constants"
import { import {
fetchDatasourceSchema, fetchDatasourceSchema,
fetchDatasourceDefinition, fetchDatasourceDefinition,
} from "./utils/schema.js" } from "./utils/schema"
import { getAPIKey } from "./utils/api.js" import { getAPIKey } from "./utils/api.js"
import { enrichButtonActions } from "./utils/buttonActions.js" import { enrichButtonActions } from "./utils/buttonActions.js"
import { processStringSync, makePropSafe } from "@budibase/string-templates" import { processStringSync, makePropSafe } from "@budibase/string-templates"

View File

@ -1,13 +1,5 @@
import { API } from "api" import { API } from "api"
import TableFetch from "@budibase/frontend-core/src/fetch/TableFetch" import { DataFetchMap, DataFetchType } from "@budibase/frontend-core"
import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch"
import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch"
import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch"
import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch"
import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch"
import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch"
import ViewV2Fetch from "@budibase/frontend-core/src/fetch/ViewV2Fetch"
import QueryArrayFetch from "@budibase/frontend-core/src/fetch/QueryArrayFetch"
/** /**
* Constructs a fetch instance for a given datasource. * Constructs a fetch instance for a given datasource.
@ -16,22 +8,20 @@ import QueryArrayFetch from "@budibase/frontend-core/src/fetch/QueryArrayFetch"
* @param datasource the datasource * @param datasource the datasource
* @returns * @returns
*/ */
const getDatasourceFetchInstance = datasource => { const getDatasourceFetchInstance = <
const handler = { TDatasource extends { type: DataFetchType }
table: TableFetch, >(
view: ViewFetch, datasource: TDatasource
viewV2: ViewV2Fetch, ) => {
query: QueryFetch, const handler = DataFetchMap[datasource?.type]
link: RelationshipFetch,
provider: NestedProviderFetch,
field: FieldFetch,
jsonarray: JSONArrayFetch,
queryarray: QueryArrayFetch,
}[datasource?.type]
if (!handler) { if (!handler) {
return null return null
} }
return new handler({ API, datasource }) return new handler({
API,
datasource: datasource as never,
query: null as any,
})
} }
/** /**
@ -39,21 +29,23 @@ const getDatasourceFetchInstance = datasource => {
* @param datasource the datasource to fetch the schema for * @param datasource the datasource to fetch the schema for
* @param options options for enriching the schema * @param options options for enriching the schema
*/ */
export const fetchDatasourceSchema = async ( export const fetchDatasourceSchema = async <
datasource, TDatasource extends { type: DataFetchType }
>(
datasource: TDatasource,
options = { enrichRelationships: false, formSchema: false } options = { enrichRelationships: false, formSchema: false }
) => { ) => {
const instance = getDatasourceFetchInstance(datasource) const instance = getDatasourceFetchInstance(datasource)
const definition = await instance?.getDefinition(datasource) const definition = await instance?.getDefinition()
if (!definition) { if (!instance || !definition) {
return null return null
} }
// Get the normal schema as long as we aren't wanting a form schema // Get the normal schema as long as we aren't wanting a form schema
let schema let schema: any
if (datasource?.type !== "query" || !options?.formSchema) { if (datasource?.type !== "query" || !options?.formSchema) {
schema = instance.getSchema(definition) schema = instance.getSchema(definition as any)
} else if (definition.parameters?.length) { } else if ("parameters" in definition && definition.parameters?.length) {
schema = {} schema = {}
definition.parameters.forEach(param => { definition.parameters.forEach(param => {
schema[param.name] = { ...param, type: "string" } schema[param.name] = { ...param, type: "string" }
@ -73,7 +65,12 @@ export const fetchDatasourceSchema = async (
} }
// Enrich schema with relationships if required // Enrich schema with relationships if required
if (definition?.sql && options?.enrichRelationships) { if (
definition &&
"sql" in definition &&
definition.sql &&
options?.enrichRelationships
) {
const relationshipAdditions = await getRelationshipSchemaAdditions(schema) const relationshipAdditions = await getRelationshipSchemaAdditions(schema)
schema = { schema = {
...schema, ...schema,
@ -89,20 +86,26 @@ export const fetchDatasourceSchema = async (
* Fetches the definition of any kind of datasource. * Fetches the definition of any kind of datasource.
* @param datasource the datasource to fetch the schema for * @param datasource the datasource to fetch the schema for
*/ */
export const fetchDatasourceDefinition = async datasource => { export const fetchDatasourceDefinition = async <
TDatasource extends { type: DataFetchType }
>(
datasource: TDatasource
) => {
const instance = getDatasourceFetchInstance(datasource) const instance = getDatasourceFetchInstance(datasource)
return await instance?.getDefinition(datasource) return await instance?.getDefinition()
} }
/** /**
* Fetches the schema of relationship fields for a SQL table schema * Fetches the schema of relationship fields for a SQL table schema
* @param schema the schema to enrich * @param schema the schema to enrich
*/ */
export const getRelationshipSchemaAdditions = async schema => { export const getRelationshipSchemaAdditions = async (
schema: Record<string, any>
) => {
if (!schema) { if (!schema) {
return null return null
} }
let relationshipAdditions = {} let relationshipAdditions: Record<string, any> = {}
for (let fieldKey of Object.keys(schema)) { for (let fieldKey of Object.keys(schema)) {
const fieldSchema = schema[fieldKey] const fieldSchema = schema[fieldKey]
if (fieldSchema?.type === "link") { if (fieldSchema?.type === "link") {
@ -110,7 +113,10 @@ export const getRelationshipSchemaAdditions = async schema => {
type: "table", type: "table",
tableId: fieldSchema?.tableId, tableId: fieldSchema?.tableId,
}) })
Object.keys(linkSchema || {}).forEach(linkKey => { if (!linkSchema) {
continue
}
Object.keys(linkSchema).forEach(linkKey => {
relationshipAdditions[`${fieldKey}.${linkKey}`] = { relationshipAdditions[`${fieldKey}.${linkKey}`] = {
type: linkSchema[linkKey].type, type: linkSchema[linkKey].type,
externalType: linkSchema[linkKey].externalType, externalType: linkSchema[linkKey].externalType,

View File

@ -1,6 +1,7 @@
import DataFetch from "./DataFetch" import DataFetch from "./DataFetch"
interface CustomDatasource { interface CustomDatasource {
type: "custom"
data: any data: any
} }

View File

@ -13,6 +13,7 @@ import {
UISearchFilter, UISearchFilter,
} from "@budibase/types" } from "@budibase/types"
import { APIClient } from "../api/types" import { APIClient } from "../api/types"
import { DataFetchType } from "."
const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils
@ -59,7 +60,7 @@ export interface DataFetchParams<
* For other types of datasource, this class is overridden and extended. * For other types of datasource, this class is overridden and extended.
*/ */
export default abstract class DataFetch< export default abstract class DataFetch<
TDatasource extends {}, TDatasource extends { type: DataFetchType },
TDefinition extends { TDefinition extends {
schema?: Record<string, any> | null schema?: Record<string, any> | null
primaryDisplay?: string primaryDisplay?: string
@ -368,7 +369,7 @@ export default abstract class DataFetch<
* @param schema the datasource schema * @param schema the datasource schema
* @return {object} the enriched datasource schema * @return {object} the enriched datasource schema
*/ */
private enrichSchema(schema: TableSchema): TableSchema { enrichSchema(schema: TableSchema): TableSchema {
// Check for any JSON fields so we can add any top level properties // Check for any JSON fields so we can add any top level properties
let jsonAdditions: Record<string, { type: string; nestedJSON: true }> = {} let jsonAdditions: Record<string, { type: string; nestedJSON: true }> = {}
for (const fieldKey of Object.keys(schema)) { for (const fieldKey of Object.keys(schema)) {

View File

@ -1,7 +1,10 @@
import { Row } from "@budibase/types" import { Row } from "@budibase/types"
import DataFetch from "./DataFetch" import DataFetch from "./DataFetch"
export interface FieldDatasource { type Types = "field" | "queryarray" | "jsonarray"
export interface FieldDatasource<TType extends Types> {
type: TType
tableId: string tableId: string
fieldType: "attachment" | "array" fieldType: "attachment" | "array"
value: string[] | Row[] value: string[] | Row[]
@ -15,8 +18,8 @@ function isArrayOfStrings(value: string[] | Row[]): value is string[] {
return Array.isArray(value) && !!value[0] && typeof value[0] !== "object" return Array.isArray(value) && !!value[0] && typeof value[0] !== "object"
} }
export default class FieldFetch extends DataFetch< export default class FieldFetch<TType extends Types> extends DataFetch<
FieldDatasource, FieldDatasource<TType>,
FieldDefinition FieldDefinition
> { > {
async getDefinition(): Promise<FieldDefinition | null> { async getDefinition(): Promise<FieldDefinition | null> {

View File

@ -8,6 +8,7 @@ interface GroupUserQuery {
} }
interface GroupUserDatasource { interface GroupUserDatasource {
type: "groupUser"
tableId: TableNames.USERS tableId: TableNames.USERS
} }
@ -20,6 +21,7 @@ export default class GroupUserFetch extends DataFetch<
super({ super({
...opts, ...opts,
datasource: { datasource: {
type: "groupUser",
tableId: TableNames.USERS, tableId: TableNames.USERS,
}, },
}) })

View File

@ -1,7 +1,7 @@
import FieldFetch from "./FieldFetch" import FieldFetch from "./FieldFetch"
import { getJSONArrayDatasourceSchema } from "../utils/json" import { getJSONArrayDatasourceSchema } from "../utils/json"
export default class JSONArrayFetch extends FieldFetch { export default class JSONArrayFetch extends FieldFetch<"jsonarray"> {
async getDefinition() { async getDefinition() {
const { datasource } = this.options const { datasource } = this.options

View File

@ -2,6 +2,7 @@ import { Row, TableSchema } from "@budibase/types"
import DataFetch from "./DataFetch" import DataFetch from "./DataFetch"
interface NestedProviderDatasource { interface NestedProviderDatasource {
type: "provider"
value?: { value?: {
schema: TableSchema schema: TableSchema
primaryDisplay: string primaryDisplay: string

View File

@ -4,7 +4,7 @@ import {
generateQueryArraySchemas, generateQueryArraySchemas,
} from "../utils/json" } from "../utils/json"
export default class QueryArrayFetch extends FieldFetch { export default class QueryArrayFetch extends FieldFetch<"queryarray"> {
async getDefinition() { async getDefinition() {
const { datasource } = this.options const { datasource } = this.options

View File

@ -4,6 +4,7 @@ import { ExecuteQueryRequest, Query } from "@budibase/types"
import { get } from "svelte/store" import { get } from "svelte/store"
interface QueryDatasource { interface QueryDatasource {
type: "query"
_id: string _id: string
fields: Record<string, any> & { fields: Record<string, any> & {
pagination?: { pagination?: {

View File

@ -2,6 +2,7 @@ import { Table } from "@budibase/types"
import DataFetch from "./DataFetch" import DataFetch from "./DataFetch"
interface RelationshipDatasource { interface RelationshipDatasource {
type: "link"
tableId: string tableId: string
rowId: string rowId: string
rowTableId: string rowTableId: string

View File

@ -1,8 +1,13 @@
import { get } from "svelte/store" import { get } from "svelte/store"
import DataFetch from "./DataFetch" import DataFetch from "./DataFetch"
import { SortOrder, Table, UITable } from "@budibase/types" import { SortOrder, Table } from "@budibase/types"
export default class TableFetch extends DataFetch<UITable, Table> { interface TableDatasource {
type: "table"
tableId: string
}
export default class TableFetch extends DataFetch<TableDatasource, Table> {
async determineFeatureFlags() { async determineFeatureFlags() {
return { return {
supportsSearch: true, supportsSearch: true,

View File

@ -14,18 +14,22 @@ interface UserFetchQuery {
} }
interface UserDatasource { interface UserDatasource {
tableId: string type: "user"
tableId: TableNames.USERS
} }
interface UserDefinition {}
export default class UserFetch extends DataFetch< export default class UserFetch extends DataFetch<
UserDatasource, UserDatasource,
{}, UserDefinition,
UserFetchQuery UserFetchQuery
> { > {
constructor(opts: DataFetchParams<UserDatasource, UserFetchQuery>) { constructor(opts: DataFetchParams<UserDatasource, UserFetchQuery>) {
super({ super({
...opts, ...opts,
datasource: { datasource: {
type: "user",
tableId: TableNames.USERS, tableId: TableNames.USERS,
}, },
}) })

View File

@ -1,9 +1,16 @@
import { Table, View } from "@budibase/types" import { Table } from "@budibase/types"
import DataFetch from "./DataFetch" import DataFetch from "./DataFetch"
type ViewV1 = View & { name: string } type ViewV1Datasource = {
type: "view"
name: string
tableId: string
calculation: string
field: string
groupBy: string
}
export default class ViewFetch extends DataFetch<ViewV1, Table> { export default class ViewFetch extends DataFetch<ViewV1Datasource, Table> {
async getDefinition() { async getDefinition() {
const { datasource } = this.options const { datasource } = this.options

View File

@ -1,9 +1,17 @@
import { SortOrder, UIView, ViewV2, ViewV2Type } from "@budibase/types" import { SortOrder, ViewV2Enriched, ViewV2Type } from "@budibase/types"
import DataFetch from "./DataFetch" import DataFetch from "./DataFetch"
import { get } from "svelte/store" import { get } from "svelte/store"
import { helpers } from "@budibase/shared-core" import { helpers } from "@budibase/shared-core"
export default class ViewV2Fetch extends DataFetch<UIView, ViewV2> { interface ViewDatasource {
type: "viewV2"
id: string
}
export default class ViewV2Fetch extends DataFetch<
ViewDatasource,
ViewV2Enriched
> {
async determineFeatureFlags() { async determineFeatureFlags() {
return { return {
supportsSearch: true, supportsSearch: true,

View File

@ -1,18 +1,20 @@
import TableFetch from "./TableFetch.js" import TableFetch from "./TableFetch"
import ViewFetch from "./ViewFetch.js" import ViewFetch from "./ViewFetch"
import ViewV2Fetch from "./ViewV2Fetch.js" import ViewV2Fetch from "./ViewV2Fetch"
import QueryFetch from "./QueryFetch" import QueryFetch from "./QueryFetch"
import RelationshipFetch from "./RelationshipFetch" import RelationshipFetch from "./RelationshipFetch"
import NestedProviderFetch from "./NestedProviderFetch" import NestedProviderFetch from "./NestedProviderFetch"
import FieldFetch from "./FieldFetch" import FieldFetch from "./FieldFetch"
import JSONArrayFetch from "./JSONArrayFetch" import JSONArrayFetch from "./JSONArrayFetch"
import UserFetch from "./UserFetch.js" import UserFetch from "./UserFetch"
import GroupUserFetch from "./GroupUserFetch" import GroupUserFetch from "./GroupUserFetch"
import CustomFetch from "./CustomFetch" import CustomFetch from "./CustomFetch"
import QueryArrayFetch from "./QueryArrayFetch.js" import QueryArrayFetch from "./QueryArrayFetch"
import { APIClient } from "../api/types.js" import { APIClient } from "../api/types"
const DataFetchMap = { export type DataFetchType = keyof typeof DataFetchMap
export const DataFetchMap = {
table: TableFetch, table: TableFetch,
view: ViewFetch, view: ViewFetch,
viewV2: ViewV2Fetch, viewV2: ViewV2Fetch,
@ -24,15 +26,14 @@ const DataFetchMap = {
// Client specific datasource types // Client specific datasource types
provider: NestedProviderFetch, provider: NestedProviderFetch,
field: FieldFetch, field: FieldFetch<"field">,
jsonarray: JSONArrayFetch, jsonarray: JSONArrayFetch,
queryarray: QueryArrayFetch, queryarray: QueryArrayFetch,
} }
// Constructs a new fetch model for a certain datasource // Constructs a new fetch model for a certain datasource
export const fetchData = ({ API, datasource, options }: any) => { export const fetchData = ({ API, datasource, options }: any) => {
const Fetch = const Fetch = DataFetchMap[datasource?.type as DataFetchType] || TableFetch
DataFetchMap[datasource?.type as keyof typeof DataFetchMap] || TableFetch
const fetch = new Fetch({ API, datasource, ...options }) const fetch = new Fetch({ API, datasource, ...options })
// Initially fetch data but don't bother waiting for the result // Initially fetch data but don't bother waiting for the result
@ -43,29 +44,27 @@ export const fetchData = ({ API, datasource, options }: any) => {
// Creates an empty fetch instance with no datasource configured, so no data // Creates an empty fetch instance with no datasource configured, so no data
// will initially be loaded // will initially be loaded
const createEmptyFetchInstance = < const createEmptyFetchInstance = <TDatasource extends { type: DataFetchType }>({
TDatasource extends {
type: keyof typeof DataFetchMap
}
>({
API, API,
datasource, datasource,
}: { }: {
API: APIClient API: APIClient
datasource: TDatasource datasource: TDatasource
}) => { }) => {
const handler = DataFetchMap[datasource?.type as keyof typeof DataFetchMap] const handler = DataFetchMap[datasource?.type as DataFetchType]
if (!handler) { if (!handler) {
return null return null
} }
return new handler({ API, datasource: null as any, query: null as any }) return new handler({
API,
datasource: null as never,
query: null as any,
})
} }
// Fetches the definition of any type of datasource // Fetches the definition of any type of datasource
export const getDatasourceDefinition = async < export const getDatasourceDefinition = async <
TDatasource extends { TDatasource extends { type: DataFetchType }
type: keyof typeof DataFetchMap
}
>({ >({
API, API,
datasource, datasource,
@ -79,9 +78,7 @@ export const getDatasourceDefinition = async <
// Fetches the schema of any type of datasource // Fetches the schema of any type of datasource
export const getDatasourceSchema = < export const getDatasourceSchema = <
TDatasource extends { TDatasource extends { type: DataFetchType }
type: keyof typeof DataFetchMap
}
>({ >({
API, API,
datasource, datasource,

View File

@ -1,5 +1,6 @@
export { createAPIClient } from "./api" export { createAPIClient } from "./api"
export { fetchData } from "./fetch" export { fetchData, DataFetchMap } from "./fetch"
export type { DataFetchType } from "./fetch"
export * as Constants from "./constants" export * as Constants from "./constants"
export * from "./stores" export * from "./stores"
export * from "./utils" export * from "./utils"

View File

@ -1,9 +1,15 @@
export enum FeatureFlag { export enum FeatureFlag {
USE_ZOD_VALIDATOR = "USE_ZOD_VALIDATOR", USE_ZOD_VALIDATOR = "USE_ZOD_VALIDATOR",
// Account-portal
DIRECT_LOGIN_TO_ACCOUNT_PORTAL = "DIRECT_LOGIN_TO_ACCOUNT_PORTAL",
} }
export const FeatureFlagDefaults = { export const FeatureFlagDefaults = {
[FeatureFlag.USE_ZOD_VALIDATOR]: false, [FeatureFlag.USE_ZOD_VALIDATOR]: false,
// Account-portal
[FeatureFlag.DIRECT_LOGIN_TO_ACCOUNT_PORTAL]: false,
} }
export type FeatureFlags = typeof FeatureFlagDefaults export type FeatureFlags = typeof FeatureFlagDefaults