Merge branch 'master' into ts/util-schema
This commit is contained in:
commit
441e0fb46c
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
"version": "3.2.37",
|
"version": "3.2.38",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"concurrency": 20,
|
"concurrency": 20,
|
||||||
"command": {
|
"command": {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { createAPIClient } from "@budibase/frontend-core"
|
import { createAPIClient } from "@budibase/frontend-core"
|
||||||
import { authStore } from "../stores/auth.js"
|
import { authStore } from "../stores/auth"
|
||||||
import { notificationStore, devToolsEnabled, devToolsStore } from "../stores/"
|
import {
|
||||||
|
notificationStore,
|
||||||
|
devToolsEnabled,
|
||||||
|
devToolsStore,
|
||||||
|
} from "../stores/index"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
|
|
||||||
export const API = createAPIClient({
|
export const API = createAPIClient({
|
|
@ -1,5 +1,5 @@
|
||||||
import { API } from "./api.js"
|
import { API } from "./api"
|
||||||
import { patchAPI } from "./patches.js"
|
import { patchAPI } from "./patches"
|
||||||
|
|
||||||
// Certain endpoints which return rows need patched so that they transform
|
// Certain endpoints which return rows need patched so that they transform
|
||||||
// and enrich the row docs, so that they can be correctly handled by the
|
// and enrich the row docs, so that they can be correctly handled by the
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface Window {
|
||||||
|
"##BUDIBASE_APP_ID##": string
|
||||||
|
"##BUDIBASE_IN_BUILDER##": string
|
||||||
|
MIGRATING_APP: boolean
|
||||||
|
}
|
|
@ -2,7 +2,9 @@ import { API } from "api"
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
|
|
||||||
const createAuthStore = () => {
|
const createAuthStore = () => {
|
||||||
const store = writable(null)
|
const store = writable<{
|
||||||
|
csrfToken?: string
|
||||||
|
} | null>(null)
|
||||||
|
|
||||||
// Fetches the user object if someone is logged in and has reloaded the page
|
// Fetches the user object if someone is logged in and has reloaded the page
|
||||||
const fetchUser = async () => {
|
const fetchUser = async () => {
|
|
@ -1,7 +1,7 @@
|
||||||
import { derived } from "svelte/store"
|
import { derived } from "svelte/store"
|
||||||
import { Constants } from "@budibase/frontend-core"
|
import { Constants } from "@budibase/frontend-core"
|
||||||
import { devToolsStore } from "../devTools.js"
|
import { devToolsStore } from "../devTools.js"
|
||||||
import { authStore } from "../auth.js"
|
import { authStore } from "../auth"
|
||||||
import { devToolsEnabled } from "./devToolsEnabled.js"
|
import { devToolsEnabled } from "./devToolsEnabled.js"
|
||||||
|
|
||||||
// Derive the current role of the logged-in user
|
// Derive the current role of the logged-in user
|
||||||
|
|
|
@ -6,7 +6,7 @@ const DEFAULT_NOTIFICATION_TIMEOUT = 3000
|
||||||
const createNotificationStore = () => {
|
const createNotificationStore = () => {
|
||||||
let block = false
|
let block = false
|
||||||
|
|
||||||
const store = writable([])
|
const store = writable<{ id: string; message: string; count: number }[]>([])
|
||||||
|
|
||||||
const blockNotifications = (timeout = 1000) => {
|
const blockNotifications = (timeout = 1000) => {
|
||||||
block = true
|
block = true
|
||||||
|
@ -14,11 +14,11 @@ const createNotificationStore = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const send = (
|
const send = (
|
||||||
message,
|
message: string,
|
||||||
type = "info",
|
type = "info",
|
||||||
icon,
|
icon: string,
|
||||||
autoDismiss = true,
|
autoDismiss = true,
|
||||||
duration,
|
duration?: number,
|
||||||
count = 1
|
count = 1
|
||||||
) => {
|
) => {
|
||||||
if (block) {
|
if (block) {
|
||||||
|
@ -66,7 +66,7 @@ const createNotificationStore = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dismiss = id => {
|
const dismiss = (id: string) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
return state.filter(n => n.id !== id)
|
return state.filter(n => n.id !== id)
|
||||||
})
|
})
|
||||||
|
@ -76,13 +76,13 @@ const createNotificationStore = () => {
|
||||||
subscribe: store.subscribe,
|
subscribe: store.subscribe,
|
||||||
actions: {
|
actions: {
|
||||||
send,
|
send,
|
||||||
info: (msg, autoDismiss, duration) =>
|
info: (msg: string, autoDismiss?: boolean, duration?: number) =>
|
||||||
send(msg, "info", "Info", autoDismiss ?? true, duration),
|
send(msg, "info", "Info", autoDismiss ?? true, duration),
|
||||||
success: (msg, autoDismiss, duration) =>
|
success: (msg: string, autoDismiss?: boolean, duration?: number) =>
|
||||||
send(msg, "success", "CheckmarkCircle", autoDismiss ?? true, duration),
|
send(msg, "success", "CheckmarkCircle", autoDismiss ?? true, duration),
|
||||||
warning: (msg, autoDismiss, duration) =>
|
warning: (msg: string, autoDismiss?: boolean, duration?: number) =>
|
||||||
send(msg, "warning", "Alert", autoDismiss ?? true, duration),
|
send(msg, "warning", "Alert", autoDismiss ?? true, duration),
|
||||||
error: (msg, autoDismiss, duration) =>
|
error: (msg: string, autoDismiss?: boolean, duration?: number) =>
|
||||||
send(msg, "error", "Alert", autoDismiss ?? false, duration),
|
send(msg, "error", "Alert", autoDismiss ?? false, duration),
|
||||||
blockNotifications,
|
blockNotifications,
|
||||||
dismiss,
|
dismiss,
|
|
@ -4,8 +4,24 @@ import { API } from "api"
|
||||||
import { peekStore } from "./peek"
|
import { peekStore } from "./peek"
|
||||||
import { builderStore } from "./builder"
|
import { builderStore } from "./builder"
|
||||||
|
|
||||||
|
interface Route {
|
||||||
|
path: string
|
||||||
|
screenId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StoreType {
|
||||||
|
routes: Route[]
|
||||||
|
routeParams: {}
|
||||||
|
activeRoute?: Route | null
|
||||||
|
routeSessionId: number
|
||||||
|
routerLoaded: boolean
|
||||||
|
queryParams?: {
|
||||||
|
peek?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const createRouteStore = () => {
|
const createRouteStore = () => {
|
||||||
const initialState = {
|
const initialState: StoreType = {
|
||||||
routes: [],
|
routes: [],
|
||||||
routeParams: {},
|
routeParams: {},
|
||||||
activeRoute: null,
|
activeRoute: null,
|
||||||
|
@ -22,7 +38,7 @@ const createRouteStore = () => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
routeConfig = null
|
routeConfig = null
|
||||||
}
|
}
|
||||||
let routes = []
|
const routes: Route[] = []
|
||||||
Object.values(routeConfig?.routes || {}).forEach(route => {
|
Object.values(routeConfig?.routes || {}).forEach(route => {
|
||||||
Object.entries(route.subpaths || {}).forEach(([path, config]) => {
|
Object.entries(route.subpaths || {}).forEach(([path, config]) => {
|
||||||
routes.push({
|
routes.push({
|
||||||
|
@ -43,13 +59,13 @@ const createRouteStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const setRouteParams = routeParams => {
|
const setRouteParams = (routeParams: StoreType["routeParams"]) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.routeParams = routeParams
|
state.routeParams = routeParams
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const setQueryParams = queryParams => {
|
const setQueryParams = (queryParams: { peek?: boolean }) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.queryParams = {
|
state.queryParams = {
|
||||||
...queryParams,
|
...queryParams,
|
||||||
|
@ -60,13 +76,13 @@ const createRouteStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const setActiveRoute = route => {
|
const setActiveRoute = (route: string) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.activeRoute = state.routes.find(x => x.path === route)
|
state.activeRoute = state.routes.find(x => x.path === route)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const navigate = (url, peek, externalNewTab) => {
|
const navigate = (url: string, peek: boolean, externalNewTab: boolean) => {
|
||||||
if (get(builderStore).inBuilder) {
|
if (get(builderStore).inBuilder) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -93,7 +109,7 @@ const createRouteStore = () => {
|
||||||
const setRouterLoaded = () => {
|
const setRouterLoaded = () => {
|
||||||
store.update(state => ({ ...state, routerLoaded: true }))
|
store.update(state => ({ ...state, routerLoaded: true }))
|
||||||
}
|
}
|
||||||
const createFullURL = relativeURL => {
|
const createFullURL = (relativeURL: string) => {
|
||||||
if (!relativeURL?.startsWith("/")) {
|
if (!relativeURL?.startsWith("/")) {
|
||||||
return relativeURL
|
return relativeURL
|
||||||
}
|
}
|
|
@ -68,13 +68,13 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
|
||||||
): Promise<APIError> => {
|
): Promise<APIError> => {
|
||||||
// Try to read a message from the error
|
// Try to read a message from the error
|
||||||
let message = response.statusText
|
let message = response.statusText
|
||||||
let json: any = null
|
let json = null
|
||||||
try {
|
try {
|
||||||
json = await response.json()
|
json = await response.json()
|
||||||
if (json?.message) {
|
if (json?.message) {
|
||||||
message = json.message
|
message = json.message
|
||||||
} else if (json?.error) {
|
} else if (json?.error) {
|
||||||
message = json.error
|
message = JSON.stringify(json.error)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -93,7 +93,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
|
||||||
// Generates an error object from a string
|
// Generates an error object from a string
|
||||||
const makeError = (
|
const makeError = (
|
||||||
message: string,
|
message: string,
|
||||||
url?: string,
|
url: string,
|
||||||
method?: HTTPMethod
|
method?: HTTPMethod
|
||||||
): APIError => {
|
): APIError => {
|
||||||
return {
|
return {
|
||||||
|
@ -226,7 +226,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
|
||||||
return await handler(callConfig)
|
return await handler(callConfig)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (config?.onError) {
|
if (config?.onError) {
|
||||||
config.onError(error)
|
config.onError(error as APIError)
|
||||||
}
|
}
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -239,13 +239,9 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
|
||||||
patch: requestApiCall(HTTPMethod.PATCH),
|
patch: requestApiCall(HTTPMethod.PATCH),
|
||||||
delete: requestApiCall(HTTPMethod.DELETE),
|
delete: requestApiCall(HTTPMethod.DELETE),
|
||||||
put: requestApiCall(HTTPMethod.PUT),
|
put: requestApiCall(HTTPMethod.PUT),
|
||||||
error: (message: string) => {
|
|
||||||
throw makeError(message)
|
|
||||||
},
|
|
||||||
invalidateCache: () => {
|
invalidateCache: () => {
|
||||||
cache = {}
|
cache = {}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Generic utility to extract the current app ID. Assumes that any client
|
// Generic utility to extract the current app ID. Assumes that any client
|
||||||
// that exists in an app context will be attaching our app ID header.
|
// that exists in an app context will be attaching our app ID header.
|
||||||
getAppID: (): string => {
|
getAppID: (): string => {
|
||||||
|
|
|
@ -46,7 +46,7 @@ export type Headers = Record<string, string>
|
||||||
export type APIClientConfig = {
|
export type APIClientConfig = {
|
||||||
enableCaching?: boolean
|
enableCaching?: boolean
|
||||||
attachHeaders?: (headers: Headers) => void
|
attachHeaders?: (headers: Headers) => void
|
||||||
onError?: (error: any) => void
|
onError?: (error: APIError) => void
|
||||||
onMigrationDetected?: (migration: string) => void
|
onMigrationDetected?: (migration: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,14 +86,13 @@ export type BaseAPIClient = {
|
||||||
patch: <RequestT = null, ResponseT = void>(
|
patch: <RequestT = null, ResponseT = void>(
|
||||||
params: APICallParams<RequestT, ResponseT>
|
params: APICallParams<RequestT, ResponseT>
|
||||||
) => Promise<ResponseT>
|
) => Promise<ResponseT>
|
||||||
error: (message: string) => void
|
|
||||||
invalidateCache: () => void
|
invalidateCache: () => void
|
||||||
getAppID: () => string
|
getAppID: () => string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type APIError = {
|
export type APIError = {
|
||||||
message?: string
|
message?: string
|
||||||
url?: string
|
url: string
|
||||||
method?: HTTPMethod
|
method?: HTTPMethod
|
||||||
json: any
|
json: any
|
||||||
status: number
|
status: number
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { FieldType } from "@budibase/types"
|
import { FieldType, UIColumn } from "@budibase/types"
|
||||||
|
|
||||||
import OptionsCell from "../cells/OptionsCell.svelte"
|
import OptionsCell from "../cells/OptionsCell.svelte"
|
||||||
import DateCell from "../cells/DateCell.svelte"
|
import DateCell from "../cells/DateCell.svelte"
|
||||||
|
@ -40,13 +40,23 @@ const TypeComponentMap = {
|
||||||
// Custom types for UI only
|
// Custom types for UI only
|
||||||
role: RoleCell,
|
role: RoleCell,
|
||||||
}
|
}
|
||||||
export const getCellRenderer = column => {
|
|
||||||
|
function getCellRendererByType(type: FieldType | "role" | undefined) {
|
||||||
|
if (!type) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeComponentMap[type as keyof typeof TypeComponentMap]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCellRenderer = (column: UIColumn) => {
|
||||||
if (column.calculationType) {
|
if (column.calculationType) {
|
||||||
return NumberCell
|
return NumberCell
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
TypeComponentMap[column?.schema?.cellRenderType] ||
|
getCellRendererByType(column.schema?.cellRenderType) ||
|
||||||
TypeComponentMap[column?.schema?.type] ||
|
getCellRendererByType(column.schema?.type) ||
|
||||||
TextCell
|
TextCell
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
// TODO: remove when all stores are typed
|
|
||||||
|
|
||||||
import { GeneratedIDPrefix, CellIDSeparator } from "./constants"
|
|
||||||
import { Helpers } from "@budibase/bbui"
|
|
||||||
|
|
||||||
export const parseCellID = cellId => {
|
|
||||||
if (!cellId) {
|
|
||||||
return { rowId: undefined, field: undefined }
|
|
||||||
}
|
|
||||||
const parts = cellId.split(CellIDSeparator)
|
|
||||||
const field = parts.pop()
|
|
||||||
return { rowId: parts.join(CellIDSeparator), field }
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getCellID = (rowId, fieldName) => {
|
|
||||||
return `${rowId}${CellIDSeparator}${fieldName}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const parseEventLocation = e => {
|
|
||||||
return {
|
|
||||||
x: e.clientX ?? e.touches?.[0]?.clientX,
|
|
||||||
y: e.clientY ?? e.touches?.[0]?.clientY,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const generateRowID = () => {
|
|
||||||
return `${GeneratedIDPrefix}${Helpers.uuid()}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isGeneratedRowID = id => {
|
|
||||||
return id?.startsWith(GeneratedIDPrefix)
|
|
||||||
}
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { createWebsocket } from "../../../utils"
|
import { createWebsocket } from "../../../utils"
|
||||||
import { SocketEvent, GridSocketEvent } from "@budibase/shared-core"
|
import { SocketEvent, GridSocketEvent } from "@budibase/shared-core"
|
||||||
|
import { Store } from "../stores"
|
||||||
|
import { UIDatasource, UIUser } from "@budibase/types"
|
||||||
|
|
||||||
export const createGridWebsocket = context => {
|
export const createGridWebsocket = (context: Store) => {
|
||||||
const { rows, datasource, users, focusedCellId, definition, API } = context
|
const { rows, datasource, users, focusedCellId, definition, API } = context
|
||||||
const socket = createWebsocket("/socket/grid")
|
const socket = createWebsocket("/socket/grid")
|
||||||
|
|
||||||
const connectToDatasource = datasource => {
|
const connectToDatasource = (datasource: UIDatasource) => {
|
||||||
if (!socket.connected) {
|
if (!socket.connected) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -18,7 +20,7 @@ export const createGridWebsocket = context => {
|
||||||
datasource,
|
datasource,
|
||||||
appId,
|
appId,
|
||||||
},
|
},
|
||||||
({ users: gridUsers }) => {
|
({ users: gridUsers }: { users: UIUser[] }) => {
|
||||||
users.set(gridUsers)
|
users.set(gridUsers)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -65,7 +67,7 @@ export const createGridWebsocket = context => {
|
||||||
GridSocketEvent.DatasourceChange,
|
GridSocketEvent.DatasourceChange,
|
||||||
({ datasource: newDatasource }) => {
|
({ datasource: newDatasource }) => {
|
||||||
// Listen builder renames, as these aren't handled otherwise
|
// Listen builder renames, as these aren't handled otherwise
|
||||||
if (newDatasource?.name !== get(definition).name) {
|
if (newDatasource?.name !== get(definition)?.name) {
|
||||||
definition.set(newDatasource)
|
definition.set(newDatasource)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -209,6 +209,9 @@ export const buildFormBlockButtonConfig = props => {
|
||||||
{
|
{
|
||||||
"##eventHandlerType": "Close Side Panel",
|
"##eventHandlerType": "Close Side Panel",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"##eventHandlerType": "Close Modal",
|
||||||
|
},
|
||||||
|
|
||||||
...(actionUrl
|
...(actionUrl
|
||||||
? [
|
? [
|
||||||
|
|
|
@ -15,5 +15,5 @@ export interface GetGlobalSelfResponse extends User {
|
||||||
license: License
|
license: License
|
||||||
budibaseAccess: boolean
|
budibaseAccess: boolean
|
||||||
accountPortalAccess: boolean
|
accountPortalAccess: boolean
|
||||||
csrfToken: boolean
|
csrfToken: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,11 +33,6 @@ export interface ScreenRoutesViewOutput extends Document {
|
||||||
export type ScreenRoutingJson = Record<
|
export type ScreenRoutingJson = Record<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
subpaths: Record<
|
subpaths: Record<string, any>
|
||||||
string,
|
|
||||||
{
|
|
||||||
screens: Record<string, string>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -14,6 +14,7 @@ export type UIColumn = FieldSchema & {
|
||||||
type: FieldType
|
type: FieldType
|
||||||
readonly: boolean
|
readonly: boolean
|
||||||
autocolumn: boolean
|
autocolumn: boolean
|
||||||
|
cellRenderType?: FieldType | "role"
|
||||||
}
|
}
|
||||||
calculationType: CalculationType
|
calculationType: CalculationType
|
||||||
__idx: number
|
__idx: number
|
||||||
|
|
Loading…
Reference in New Issue