diff --git a/packages/bbui/src/ProgressCircle/ProgressCircle.svelte b/packages/bbui/src/ProgressCircle/ProgressCircle.svelte index 37a1e07d73..112fa739c7 100644 --- a/packages/bbui/src/ProgressCircle/ProgressCircle.svelte +++ b/packages/bbui/src/ProgressCircle/ProgressCircle.svelte @@ -37,7 +37,7 @@ } } - export let overBackground + export let overBackground = false diff --git a/packages/builder/src/dataBinding.js b/packages/builder/src/dataBinding.js index 4a9d45158c..1272c9eb6d 100644 --- a/packages/builder/src/dataBinding.js +++ b/packages/builder/src/dataBinding.js @@ -900,7 +900,7 @@ export const getSchemaForDatasourcePlus = (resourceId, options) => { * optional and only needed for "provider" datasource types. * @param datasource the datasource definition * @param options options for generating the schema - * @return {{schema: Object, table: Object}} + * @return {{schema: Object, table: Table}} */ export const getSchemaForDatasource = (asset, datasource, options) => { options = options || {} diff --git a/packages/builder/src/stores/BudiStore.ts b/packages/builder/src/stores/BudiStore.ts index 706fa9474a..d5bbc99328 100644 --- a/packages/builder/src/stores/BudiStore.ts +++ b/packages/builder/src/stores/BudiStore.ts @@ -1,7 +1,21 @@ import { writable, Writable, Readable } from "svelte/store" +import { + createLocalStorageStore, + createSessionStorageStore, +} from "@budibase/frontend-core" + +export enum PersistenceType { + NONE = "none", + LOCAL = "local", + SESSION = "session", +} interface BudiStoreOpts { debug?: boolean + persistence?: { + type: PersistenceType + key: string + } } export class BudiStore { @@ -11,7 +25,21 @@ export class BudiStore { set: Writable["set"] constructor(init: T, opts?: BudiStoreOpts) { - this.store = writable(init) + if (opts?.persistence) { + switch (opts.persistence.type) { + case PersistenceType.LOCAL: + this.store = createLocalStorageStore(opts.persistence.key, init) + break + case PersistenceType.SESSION: + this.store = createSessionStorageStore(opts.persistence.key, init) + break + default: + this.store = writable(init) + } + } else { + this.store = writable(init) + } + this.subscribe = this.store.subscribe this.update = this.store.update this.set = this.store.set diff --git a/packages/builder/src/stores/builder/app.ts b/packages/builder/src/stores/builder/app.ts index dffdb79ee1..3c8ed4afc1 100644 --- a/packages/builder/src/stores/builder/app.ts +++ b/packages/builder/src/stores/builder/app.ts @@ -86,7 +86,7 @@ export class AppMetaStore extends BudiStore { super(INITIAL_APP_META_STATE) } - reset(): void { + reset() { this.store.set({ ...INITIAL_APP_META_STATE }) } @@ -94,7 +94,7 @@ export class AppMetaStore extends BudiStore { application: App clientLibPath: string hasLock: boolean - }): void { + }) { const { application: app, clientLibPath, hasLock } = pkg this.update(state => ({ @@ -121,7 +121,7 @@ export class AppMetaStore extends BudiStore { })) } - syncClientFeatures(features: Partial): void { + syncClientFeatures(features: Partial) { this.update(state => ({ ...state, clientFeatures: { @@ -131,14 +131,14 @@ export class AppMetaStore extends BudiStore { })) } - syncClientTypeSupportPresets(typeSupportPresets: TypeSupportPresets): void { + syncClientTypeSupportPresets(typeSupportPresets: TypeSupportPresets) { this.update(state => ({ ...state, typeSupportPresets, })) } - async syncAppRoutes(): Promise { + async syncAppRoutes() { const resp = await API.fetchAppRoutes() this.update(state => ({ ...state, @@ -147,7 +147,7 @@ export class AppMetaStore extends BudiStore { } // Returned from socket - syncMetadata(metadata: { name: string; url: string; icon?: AppIcon }): void { + syncMetadata(metadata: { name: string; url: string; icon?: AppIcon }) { const { name, url, icon } = metadata this.update(state => ({ ...state, diff --git a/packages/builder/src/stores/builder/builder.ts b/packages/builder/src/stores/builder/builder.ts index 65ffc84e95..e4cbbba7f1 100644 --- a/packages/builder/src/stores/builder/builder.ts +++ b/packages/builder/src/stores/builder/builder.ts @@ -54,7 +54,7 @@ export class BuilderStore extends BudiStore { this.startBuilderOnboarding = this.startBuilderOnboarding.bind(this) } - init(app: App): void { + init(app: App) { if (!app?.appId) { console.error("BuilderStore: No appId supplied for websocket") return @@ -64,46 +64,46 @@ export class BuilderStore extends BudiStore { } } - refresh(): void { + refresh() { const currentState = get(this.store) this.store.set(currentState) } - reset(): void { + reset() { this.store.set({ ...INITIAL_BUILDER_STATE }) this.websocket?.disconnect() this.websocket = undefined } - highlightSetting(key?: string, type?: string): void { + highlightSetting(key?: string, type?: string) { this.update(state => ({ ...state, highlightedSetting: key ? { key, type: type || "info" } : null, })) } - propertyFocus(key: string | null): void { + propertyFocus(key: string | null) { this.update(state => ({ ...state, propertyFocus: key, })) } - showBuilderSidePanel(): void { + showBuilderSidePanel() { this.update(state => ({ ...state, builderSidePanel: true, })) } - hideBuilderSidePanel(): void { + hideBuilderSidePanel() { this.update(state => ({ ...state, builderSidePanel: false, })) } - setPreviousTopNavPath(route: string, url: string): void { + setPreviousTopNavPath(route: string, url: string) { this.update(state => ({ ...state, previousTopNavPath: { @@ -113,13 +113,13 @@ export class BuilderStore extends BudiStore { })) } - selectResource(id: string): void { + selectResource(id: string) { this.websocket?.emit(BuilderSocketEvent.SelectResource, { resourceId: id, }) } - registerTourNode(tourStepKey: string, node: HTMLElement): void { + registerTourNode(tourStepKey: string, node: HTMLElement) { this.update(state => { const update = { ...state, @@ -132,7 +132,7 @@ export class BuilderStore extends BudiStore { }) } - destroyTourNode(tourStepKey: string): void { + destroyTourNode(tourStepKey: string) { const store = get(this.store) if (store.tourNodes?.[tourStepKey]) { const nodes = { ...store.tourNodes } @@ -144,7 +144,7 @@ export class BuilderStore extends BudiStore { } } - startBuilderOnboarding(): void { + startBuilderOnboarding() { this.update(state => ({ ...state, onboarding: true, @@ -152,14 +152,14 @@ export class BuilderStore extends BudiStore { })) } - endBuilderOnboarding(): void { + endBuilderOnboarding() { this.update(state => ({ ...state, onboarding: false, })) } - setTour(tourKey?: string | null): void { + setTour(tourKey?: string | null) { this.update(state => ({ ...state, tourStepKey: null, diff --git a/packages/builder/src/stores/builder/componentTreeNodes.js b/packages/builder/src/stores/builder/componentTreeNodes.js deleted file mode 100644 index 6d82732722..0000000000 --- a/packages/builder/src/stores/builder/componentTreeNodes.js +++ /dev/null @@ -1,67 +0,0 @@ -import { get } from "svelte/store" -import { createSessionStorageStore } from "@budibase/frontend-core" -import { selectedScreen as selectedScreenStore } from "./screens" -import { findComponentPath } from "@/helpers/components" - -const baseStore = createSessionStorageStore("openNodes", {}) - -const toggleNode = componentId => { - baseStore.update(openNodes => { - openNodes[`nodeOpen-${componentId}`] = !openNodes[`nodeOpen-${componentId}`] - - return openNodes - }) -} - -const expandNodes = componentIds => { - baseStore.update(openNodes => { - const newNodes = Object.fromEntries( - componentIds.map(id => [`nodeOpen-${id}`, true]) - ) - - return { ...openNodes, ...newNodes } - }) -} - -const collapseNodes = componentIds => { - baseStore.update(openNodes => { - const newNodes = Object.fromEntries( - componentIds.map(id => [`nodeOpen-${id}`, false]) - ) - - return { ...openNodes, ...newNodes } - }) -} - -// Will ensure all parents of a node are expanded so that it is visible in the tree -const makeNodeVisible = componentId => { - const selectedScreen = get(selectedScreenStore) - - const path = findComponentPath(selectedScreen.props, componentId) - - const componentIds = path.map(component => component._id) - - baseStore.update(openNodes => { - const newNodes = Object.fromEntries( - componentIds.map(id => [`nodeOpen-${id}`, true]) - ) - - return { ...openNodes, ...newNodes } - }) -} - -const isNodeExpanded = componentId => { - const openNodes = get(baseStore) - return !!openNodes[`nodeOpen-${componentId}`] -} - -const store = { - subscribe: baseStore.subscribe, - toggleNode, - expandNodes, - makeNodeVisible, - collapseNodes, - isNodeExpanded, -} - -export default store diff --git a/packages/builder/src/stores/builder/componentTreeNodes.ts b/packages/builder/src/stores/builder/componentTreeNodes.ts new file mode 100644 index 0000000000..420c540e37 --- /dev/null +++ b/packages/builder/src/stores/builder/componentTreeNodes.ts @@ -0,0 +1,73 @@ +import { get } from "svelte/store" +import { selectedScreen as selectedScreenStore } from "./screens" +import { findComponentPath } from "@/helpers/components" +import { Screen, Component } from "@budibase/types" +import { BudiStore, PersistenceType } from "@/stores/BudiStore" + +interface OpenNodesState { + [key: string]: boolean +} + +export class ComponentTreeNodesStore extends BudiStore { + constructor() { + super({} as OpenNodesState, { + persistence: { + type: PersistenceType.SESSION, + key: "openNodes", + }, + }) + } + + toggleNode(componentId: string) { + this.update((openNodes: OpenNodesState) => { + openNodes[`nodeOpen-${componentId}`] = + !openNodes[`nodeOpen-${componentId}`] + + return openNodes + }) + } + + expandNodes(componentIds: string[]) { + this.update((openNodes: OpenNodesState) => { + const newNodes = Object.fromEntries( + componentIds.map(id => [`nodeOpen-${id}`, true]) + ) + + return { ...openNodes, ...newNodes } + }) + } + + collapseNodes(componentIds: string[]) { + this.update((openNodes: OpenNodesState) => { + const newNodes = Object.fromEntries( + componentIds.map(id => [`nodeOpen-${id}`, false]) + ) + + return { ...openNodes, ...newNodes } + }) + } + + // Will ensure all parents of a node are expanded so that it is visible in the tree + makeNodeVisible(componentId: string) { + const selectedScreen: Screen = get(selectedScreenStore) + + const path = findComponentPath(selectedScreen.props, componentId) + + const componentIds = path.map((component: Component) => component._id) + + this.update((openNodes: OpenNodesState) => { + const newNodes = Object.fromEntries( + componentIds.map((id: string) => [`nodeOpen-${id}`, true]) + ) + + return { ...openNodes, ...newNodes } + }) + } + + isNodeExpanded(componentId: string): boolean { + const openNodes = get(this) + return !!openNodes[`nodeOpen-${componentId}`] + } +} + +export default new ComponentTreeNodesStore() diff --git a/packages/builder/src/stores/builder/components.js b/packages/builder/src/stores/builder/components.ts similarity index 83% rename from packages/builder/src/stores/builder/components.js rename to packages/builder/src/stores/builder/components.ts index b9e0e01a3c..9ad9a75f84 100644 --- a/packages/builder/src/stores/builder/components.js +++ b/packages/builder/src/stores/builder/components.ts @@ -30,10 +30,40 @@ import { } from "@/constants/backend" import { BudiStore } from "../BudiStore" import { Utils } from "@budibase/frontend-core" -import { FieldType } from "@budibase/types" +import { Component, FieldType, Screen, Table } from "@budibase/types" import { utils } from "@budibase/shared-core" -export const INITIAL_COMPONENTS_STATE = { +interface ComponentDefinition { + component: string + name: string + friendlyName?: string + hasChildren?: boolean + settings?: ComponentSetting[] + features?: Record + typeSupportPresets?: Record +} + +interface ComponentSetting { + key: string + type: string + section?: string + name?: string + defaultValue?: any + selectAllFields?: boolean + resetOn?: string | string[] + settings?: ComponentSetting[] +} + +interface ComponentState { + components: Record + customComponents: string[] + selectedComponentId: string | null + componentToPaste?: Component | null + settingsCache: Record + selectedScreenId?: string | null +} + +export const INITIAL_COMPONENTS_STATE: ComponentState = { components: {}, customComponents: [], selectedComponentId: null, @@ -41,7 +71,7 @@ export const INITIAL_COMPONENTS_STATE = { settingsCache: {}, } -export class ComponentStore extends BudiStore { +export class ComponentStore extends BudiStore { constructor() { super(INITIAL_COMPONENTS_STATE) @@ -89,14 +119,14 @@ export class ComponentStore extends BudiStore { * @param {string} appId * @returns */ - async refreshDefinitions(appId) { + async refreshDefinitions(appId: string) { if (!appId) { return } // Fetch definitions and filter out custom component definitions so we // can flag them - const components = await API.fetchComponentLibDefinitions(appId) + const components: any = await API.fetchComponentLibDefinitions(appId) const customComponents = Object.keys(components).filter(key => key.startsWith("plugin/") ) @@ -122,7 +152,7 @@ export class ComponentStore extends BudiStore { * '@budibase/standard-components/container' * @returns {object} */ - getDefinition(componentType) { + getDefinition(componentType: string) { if (!componentType) { return null } @@ -169,7 +199,7 @@ export class ComponentStore extends BudiStore { * @param {object} enrichedComponent * @returns {object} migrated Component */ - migrateSettings(enrichedComponent) { + migrateSettings(enrichedComponent: Component) { const componentPrefix = "@budibase/standard-components" let migrated = false @@ -224,7 +254,7 @@ export class ComponentStore extends BudiStore { * @param {object} opts * @returns */ - enrichEmptySettings(component, opts) { + enrichEmptySettings(component: Component, opts: any) { if (!component?._component) { return } @@ -235,7 +265,7 @@ export class ComponentStore extends BudiStore { if (!screen) { return } - settings.forEach(setting => { + settings.forEach((setting: ComponentSetting) => { const value = component[setting.key] // Fill empty settings @@ -257,7 +287,7 @@ export class ComponentStore extends BudiStore { } else if (setting.type === "dataProvider") { // Pick closest data provider where required const path = findComponentPath(screen.props, treeId) - const providers = path.filter(component => + const providers = path.filter((component: Component) => component._component?.endsWith("/dataprovider") ) if (providers.length) { @@ -278,7 +308,8 @@ export class ComponentStore extends BudiStore { const form = findClosestMatchingComponent( screen.props, treeId, - x => x._component === "@budibase/standard-components/form" + (x: Component) => + x._component === "@budibase/standard-components/form" ) const usedFields = Object.keys(buildFormSchema(form) || {}) @@ -302,7 +333,8 @@ export class ComponentStore extends BudiStore { // Validate data provider exists, or else clear it const providers = findAllMatchingComponents( screen?.props, - x => x._component === "@budibase/standard-components/dataprovider" + (x: Component) => + x._component === "@budibase/standard-components/dataprovider" ) const valid = providers?.some(dp => value.includes?.(dp._id)) if (!valid) { @@ -325,10 +357,14 @@ export class ComponentStore extends BudiStore { if (cardKeys.every(key => !component[key]) && !component.cardImageURL) { const { _id, dataSource } = component if (dataSource) { - const { schema, table } = getSchemaForDatasource(screen, dataSource) + const { + schema, + table, + }: { schema: Record; table: Table } = + getSchemaForDatasource(screen, dataSource, {}) // Finds fields by types from the schema of the configured datasource - const findFieldTypes = fieldTypes => { + const findFieldTypes = (fieldTypes: any) => { if (!Array.isArray(fieldTypes)) { fieldTypes = [fieldTypes] } @@ -345,7 +381,11 @@ export class ComponentStore extends BudiStore { } // Inserts a card binding for a certain setting - const addBinding = (key, fallback, ...parts) => { + const addBinding = ( + key: string, + fallback: string | null, + ...parts: any[] + ) => { if (parts.some(x => x == null)) { component[key] = fallback } else { @@ -363,7 +403,7 @@ export class ComponentStore extends BudiStore { ...findFieldTypes(FieldType.NUMBER), ] const longFields = findFieldTypes(FieldType.LONGFORM) - if (schema?.[table?.primaryDisplay]) { + if (table?.primaryDisplay && schema?.[table.primaryDisplay]) { shortFields.unshift(table.primaryDisplay) } @@ -399,7 +439,7 @@ export class ComponentStore extends BudiStore { * @param {object} parent * @returns */ - createInstance(componentName, presetProps, parent) { + createInstance(componentName: string, presetProps: any, parent: any) { const definition = this.getDefinition(componentName) if (!definition) { return null @@ -433,7 +473,7 @@ export class ComponentStore extends BudiStore { } // Custom post processing for creation only - let extras = {} + let extras: any = {} if (definition.hasChildren) { extras._children = [] } @@ -443,10 +483,11 @@ export class ComponentStore extends BudiStore { const parentForm = findClosestMatchingComponent( get(selectedScreen).props, get(selectedComponent)._id, - component => component._component.endsWith("/form") + (component: Component) => component._component.endsWith("/form") ) - const formSteps = findAllMatchingComponents(parentForm, component => - component._component.endsWith("/formstep") + const formSteps = findAllMatchingComponents( + parentForm, + (component: Component) => component._component.endsWith("/formstep") ) extras.step = formSteps.length + 1 extras._instanceName = `Step ${formSteps.length + 1}` @@ -466,7 +507,12 @@ export class ComponentStore extends BudiStore { * @param {number} index * @returns */ - async create(componentName, presetProps, parent, index) { + async create( + componentName: string, + presetProps: any, + parent: any, + index: number + ) { const state = get(this.store) const componentInstance = this.createInstance( componentName, @@ -479,23 +525,23 @@ export class ComponentStore extends BudiStore { // Insert in position if specified if (parent && index != null) { - await screenStore.patch(screen => { + await screenStore.patch((screen: Screen) => { let parentComponent = findComponent(screen.props, parent) if (!parentComponent._children?.length) { parentComponent._children = [componentInstance] } else { parentComponent._children.splice(index, 0, componentInstance) } - }) + }, null) } // Otherwise we work out where this component should be inserted else { - await screenStore.patch(screen => { + await screenStore.patch((screen: Screen) => { // Find the selected component let selectedComponentId = state.selectedComponentId - if (selectedComponentId.startsWith(`${screen._id}-`)) { - selectedComponentId = screen?.props._id + if (selectedComponentId?.startsWith(`${screen._id}-`)) { + selectedComponentId = screen.props._id || null } const currentComponent = findComponent( screen.props, @@ -533,7 +579,7 @@ export class ComponentStore extends BudiStore { parentComponent._children = [] } parentComponent._children.push(componentInstance) - }) + }, null) } // Select new component @@ -559,18 +605,22 @@ export class ComponentStore extends BudiStore { * @param {string} screenId * @returns */ - async patch(patchFn, componentId, screenId) { + async patch( + patchFn: (component: Component, screen: Screen) => any, + componentId?: string, + screenId?: string + ) { // Use selected component by default if (!componentId || !screenId) { const state = get(this.store) - componentId = componentId || state.selectedComponentId + componentId = componentId ?? state.selectedComponentId ?? undefined const screenState = get(screenStore) screenId = screenId || screenState.selectedScreenId } if (!componentId || !screenId || !patchFn) { return } - const patchScreen = screen => { + const patchScreen = (screen: Screen) => { let component = findComponent(screen.props, componentId) if (!component) { return false @@ -594,7 +644,7 @@ export class ComponentStore extends BudiStore { * @param {object} component * @returns */ - async delete(component) { + async delete(component: Component) { if (!component) { return } @@ -602,7 +652,7 @@ export class ComponentStore extends BudiStore { // Determine the next component to select, and select it before deletion // to avoid an intermediate state of no component selection const state = get(this.store) - let nextId + let nextId: string | null = "" if (state.selectedComponentId === component._id) { nextId = this.getNext() if (!nextId) { @@ -621,7 +671,7 @@ export class ComponentStore extends BudiStore { } // Patch screen - await screenStore.patch(screen => { + await screenStore.patch((screen: Screen) => { // Check component exists component = findComponent(screen.props, component._id) if (!component) { @@ -634,12 +684,12 @@ export class ComponentStore extends BudiStore { return false } parent._children = parent._children.filter( - child => child._id !== component._id + (child: Component) => child._id !== component._id ) - }) + }, null) } - copy(component, cut = false, selectParent = true) { + copy(component: Component, cut = false, selectParent = true) { // Update store with copied component this.update(state => { state.componentToPaste = cloneDeep(component) @@ -665,7 +715,7 @@ export class ComponentStore extends BudiStore { * * @param {string} componentId */ - select(componentId) { + select(componentId: string) { this.update(state => { state.selectedComponentId = componentId return state @@ -679,12 +729,17 @@ export class ComponentStore extends BudiStore { * @param {object} targetScreen * @returns */ - async paste(targetComponent, mode, targetScreen, selectComponent = true) { + async paste( + targetComponent: Component, + mode: string, + targetScreen: Screen, + selectComponent = true + ) { const state = get(this.store) if (!state.componentToPaste) { return } - let newComponentId + let newComponentId: string | null = "" // Remove copied component if cutting, regardless if pasting works let componentToPaste = cloneDeep(state.componentToPaste) @@ -696,7 +751,7 @@ export class ComponentStore extends BudiStore { } // Patch screen - const patch = screen => { + const patch = (screen: Screen) => { // Get up to date ref to target targetComponent = findComponent(screen.props, targetComponent._id) if (!targetComponent) { @@ -712,7 +767,7 @@ export class ComponentStore extends BudiStore { if (!cut) { componentToPaste = makeComponentUnique(componentToPaste) } - newComponentId = componentToPaste._id + newComponentId = componentToPaste._id! // Strip grid position metadata if pasting into a new screen, but keep // alignment metadata @@ -732,7 +787,7 @@ export class ComponentStore extends BudiStore { const parent = findComponentParent(screen.props, originalId) if (parent?._children) { parent._children = parent._children.filter( - component => component._id !== originalId + (component: Component) => component._id !== originalId ) } } @@ -740,7 +795,7 @@ export class ComponentStore extends BudiStore { // Check inside is valid if (mode === "inside") { const definition = this.getDefinition(targetComponent._component) - if (!definition.hasChildren) { + if (!definition?.hasChildren) { mode = "below" } } @@ -758,14 +813,16 @@ export class ComponentStore extends BudiStore { if (!parent?._children) { return false } - const targetIndex = parent._children.findIndex(component => { - return component._id === targetComponent._id - }) + const targetIndex = parent._children.findIndex( + (component: Component) => { + return component._id === targetComponent._id + } + ) const index = mode === "above" ? targetIndex : targetIndex + 1 parent._children.splice(index, 0, componentToPaste) } } - const targetScreenId = targetScreen?._id || state.selectedScreenId + const targetScreenId = targetScreen?._id ?? state.selectedScreenId ?? null await screenStore.patch(patch, targetScreenId) // Select the new component @@ -785,7 +842,9 @@ export class ComponentStore extends BudiStore { const componentId = state.selectedComponentId const screen = get(selectedScreen) const parent = findComponentParent(screen.props, componentId) - const index = parent?._children.findIndex(x => x._id === componentId) + const index = parent?._children.findIndex( + (x: Component) => x._id === componentId + ) // Check for screen and navigation component edge cases const screenComponentId = `${screen._id}-screen` @@ -832,7 +891,9 @@ export class ComponentStore extends BudiStore { const componentId = component?._id const screen = get(selectedScreen) const parent = findComponentParent(screen.props, componentId) - const index = parent?._children.findIndex(x => x._id === componentId) + const index = parent?._children.findIndex( + (x: Component) => x._id === componentId + ) // Check for screen and navigation component edge cases const screenComponentId = `${screen._id}-screen` @@ -862,7 +923,7 @@ export class ComponentStore extends BudiStore { let target = parent let targetParent = findComponentParent(screen.props, target._id) let targetIndex = targetParent?._children.findIndex( - child => child._id === target._id + (child: Component) => child._id === target._id ) while ( targetParent != null && @@ -871,7 +932,7 @@ export class ComponentStore extends BudiStore { target = targetParent targetParent = findComponentParent(screen.props, target._id) targetIndex = targetParent?._children.findIndex( - child => child._id === target._id + (child: Component) => child._id === target._id ) } if (targetParent) { @@ -901,13 +962,15 @@ export class ComponentStore extends BudiStore { } } - async moveUp(component) { - await screenStore.patch(screen => { + async moveUp(component: Component) { + await screenStore.patch((screen: Screen) => { const componentId = component?._id const parent = findComponentParent(screen.props, componentId) // Check we aren't right at the top of the tree - const index = parent?._children.findIndex(x => x._id === componentId) + const index = parent?._children.findIndex( + (x: Component) => x._id === componentId + ) if (!parent || (index === 0 && parent._id === screen.props._id)) { return } @@ -915,7 +978,7 @@ export class ComponentStore extends BudiStore { // Copy original component and remove it from the parent const originalComponent = cloneDeep(parent._children[index]) parent._children = parent._children.filter( - component => component._id !== componentId + (component: Component) => component._id !== componentId ) // If we have siblings above us, move up @@ -925,7 +988,7 @@ export class ComponentStore extends BudiStore { const previousSibling = parent._children[index - 1] const definition = this.getDefinition(previousSibling._component) if ( - definition.hasChildren && + definition?.hasChildren && componentTreeNodesStore.isNodeExpanded(previousSibling._id) ) { previousSibling._children.push(originalComponent) @@ -942,15 +1005,15 @@ export class ComponentStore extends BudiStore { else if (parent._id !== screen.props._id) { const grandParent = findComponentParent(screen.props, parent._id) const parentIndex = grandParent._children.findIndex( - child => child._id === parent._id + (child: Component) => child._id === parent._id ) grandParent._children.splice(parentIndex, 0, originalComponent) } - }) + }, null) } - async moveDown(component) { - await screenStore.patch(screen => { + async moveDown(component: Component) { + await screenStore.patch((screen: Screen) => { const componentId = component?._id const parent = findComponentParent(screen.props, componentId) @@ -960,7 +1023,9 @@ export class ComponentStore extends BudiStore { } // Check we aren't right at the bottom of the tree - const index = parent._children.findIndex(x => x._id === componentId) + const index = parent._children.findIndex( + (x: Component) => x._id === componentId + ) if ( index === parent._children.length - 1 && parent._id === screen.props._id @@ -971,7 +1036,7 @@ export class ComponentStore extends BudiStore { // Copy the original component and remove from parent const originalComponent = cloneDeep(parent._children[index]) parent._children = parent._children.filter( - component => component._id !== componentId + (component: Component) => component._id !== componentId ) // Move below the next sibling if we are not the last sibling @@ -980,7 +1045,7 @@ export class ComponentStore extends BudiStore { const nextSibling = parent._children[index] const definition = this.getDefinition(nextSibling._component) if ( - definition.hasChildren && + definition?.hasChildren && componentTreeNodesStore.isNodeExpanded(nextSibling._id) ) { nextSibling._children.splice(0, 0, originalComponent) @@ -996,15 +1061,15 @@ export class ComponentStore extends BudiStore { else { const grandParent = findComponentParent(screen.props, parent._id) const parentIndex = grandParent._children.findIndex( - child => child._id === parent._id + (child: Component) => child._id === parent._id ) grandParent._children.splice(parentIndex + 1, 0, originalComponent) } - }) + }, null) } - async updateStyle(name, value) { - await this.patch(component => { + async updateStyle(name: string, value: string) { + await this.patch((component: Component) => { if (value == null || value === "") { delete component._styles.normal[name] } else { @@ -1013,8 +1078,8 @@ export class ComponentStore extends BudiStore { }) } - async updateStyles(styles, id) { - const patchFn = component => { + async updateStyles(styles: Record, id: string) { + const patchFn = (component: Component) => { component._styles.normal = { ...component._styles.normal, ...styles, @@ -1023,24 +1088,24 @@ export class ComponentStore extends BudiStore { await this.patch(patchFn, id) } - async updateCustomStyle(style) { - await this.patch(component => { + async updateCustomStyle(style: Record) { + await this.patch((component: Component) => { component._styles.custom = style }) } - async updateConditions(conditions) { - await this.patch(component => { + async updateConditions(conditions: Record) { + await this.patch((component: Component) => { component._conditions = conditions }) } - async updateSetting(name, value) { + async updateSetting(name: string, value: any) { await this.patch(this.updateComponentSetting(name, value)) } - updateComponentSetting(name, value) { - return component => { + updateComponentSetting(name: string, value: any) { + return (component: Component) => { if (!name || !component) { return false } @@ -1050,10 +1115,12 @@ export class ComponentStore extends BudiStore { } const settings = this.getComponentSettings(component._component) - const updatedSetting = settings.find(setting => setting.key === name) + const updatedSetting = settings.find( + (setting: ComponentSetting) => setting.key === name + ) // Reset dependent fields - settings.forEach(setting => { + settings.forEach((setting: ComponentSetting) => { const needsReset = name === setting.resetOn || (Array.isArray(setting.resetOn) && setting.resetOn.includes(name)) @@ -1066,15 +1133,16 @@ export class ComponentStore extends BudiStore { updatedSetting?.type === "dataSource" || updatedSetting?.type === "table" ) { - const { schema } = getSchemaForDatasource(null, value) + const { schema }: { schema: Record } = + getSchemaForDatasource(null, value, null) const columnNames = Object.keys(schema || {}) const multifieldKeysToSelectAll = settings - .filter(setting => { + .filter((setting: ComponentSetting) => { return setting.type === "multifield" && setting.selectAllFields }) - .map(setting => setting.key) + .map((setting: ComponentSetting) => setting.key) - multifieldKeysToSelectAll.forEach(key => { + multifieldKeysToSelectAll.forEach((key: string) => { component[key] = columnNames }) } @@ -1083,14 +1151,14 @@ export class ComponentStore extends BudiStore { } } - requestEjectBlock(componentId) { + requestEjectBlock(componentId: string) { previewStore.sendEvent("eject-block", componentId) } - async handleEjectBlock(componentId, ejectedDefinition) { - let nextSelectedComponentId + async handleEjectBlock(componentId: string, ejectedDefinition: Component) { + let nextSelectedComponentId: string | null = null - await screenStore.patch(screen => { + await screenStore.patch((screen: Screen) => { const block = findComponent(screen.props, componentId) const parent = findComponentParent(screen.props, componentId) @@ -1108,7 +1176,7 @@ export class ComponentStore extends BudiStore { // _containsSlot flag to know where to insert them const slotContainer = findAllMatchingComponents( ejectedDefinition, - x => x._containsSlot + (x: Component) => x._containsSlot )[0] if (slotContainer) { delete slotContainer._containsSlot @@ -1120,10 +1188,12 @@ export class ComponentStore extends BudiStore { // Replace block with ejected definition ejectedDefinition = makeComponentUnique(ejectedDefinition) - const index = parent._children.findIndex(x => x._id === componentId) + const index = parent._children.findIndex( + (x: Component) => x._id === componentId + ) parent._children[index] = ejectedDefinition - nextSelectedComponentId = ejectedDefinition._id - }) + nextSelectedComponentId = ejectedDefinition._id ?? null + }, null) // Select new root component if (nextSelectedComponentId) { @@ -1134,7 +1204,7 @@ export class ComponentStore extends BudiStore { } } - async addParent(componentId, parentType) { + async addParent(componentId: string, parentType: string) { if (!componentId || !parentType) { return } @@ -1146,7 +1216,7 @@ export class ComponentStore extends BudiStore { } // Replace component with a version wrapped in a new parent - await screenStore.patch(screen => { + await screenStore.patch((screen: Screen) => { // Get this component definition and parent definition let definition = findComponent(screen.props, componentId) let oldParentDefinition = findComponentParent(screen.props, componentId) @@ -1156,7 +1226,7 @@ export class ComponentStore extends BudiStore { // Replace component with parent const index = oldParentDefinition._children.findIndex( - component => component._id === componentId + (component: Component) => component._id === componentId ) if (index === -1) { return false @@ -1165,7 +1235,7 @@ export class ComponentStore extends BudiStore { ...newParentDefinition, _children: [definition], } - }) + }, null) // Select the new parent this.update(state => { @@ -1181,7 +1251,7 @@ export class ComponentStore extends BudiStore { * '@budibase/standard-components/container' * @returns {boolean} */ - isCached(componentType) { + isCached(componentType: string) { const settings = get(this.store).settingsCache return componentType in settings } @@ -1194,8 +1264,8 @@ export class ComponentStore extends BudiStore { * '@budibase/standard-components/container' * @returns {array} the settings */ - cacheSettings(componentType, definition) { - let settings = [] + cacheSettings(componentType: string, definition: ComponentDefinition | null) { + let settings: ComponentSetting[] = [] if (definition) { settings = definition.settings?.filter(setting => !setting.section) ?? [] definition.settings @@ -1229,7 +1299,7 @@ export class ComponentStore extends BudiStore { * '@budibase/standard-components/container' * @returns {Array} */ - getComponentSettings(componentType) { + getComponentSettings(componentType: string) { if (!componentType) { return [] } diff --git a/packages/builder/src/stores/builder/integrations.js b/packages/builder/src/stores/builder/integrations.js deleted file mode 100644 index 32631b83ee..0000000000 --- a/packages/builder/src/stores/builder/integrations.js +++ /dev/null @@ -1,18 +0,0 @@ -import { writable } from "svelte/store" -import { API } from "@/api" - -const createIntegrationsStore = () => { - const store = writable({}) - - const init = async () => { - const integrations = await API.getIntegrations() - store.set(integrations) - } - - return { - ...store, - init, - } -} - -export const integrations = createIntegrationsStore() diff --git a/packages/builder/src/stores/builder/integrations.ts b/packages/builder/src/stores/builder/integrations.ts new file mode 100644 index 0000000000..b48f45a654 --- /dev/null +++ b/packages/builder/src/stores/builder/integrations.ts @@ -0,0 +1,34 @@ +import { writable, type Writable } from "svelte/store" +import { API } from "@/api" +import { Integration } from "@budibase/types" + +type IntegrationsState = Record + +const INITIAL_STATE: IntegrationsState = {} + +const createIntegrationsStore = () => { + const store: Writable = writable(INITIAL_STATE) + + const init = async () => { + const response = await API.getIntegrations() + + // Filter out undefineds + const integrations = Object.entries(response).reduce( + (acc, [key, value]) => { + if (value) { + acc[key] = value + } + return acc + }, + {} as IntegrationsState + ) + store.set(integrations) + } + + return { + ...store, + init, + } +} + +export const integrations = createIntegrationsStore() diff --git a/packages/builder/src/stores/builder/screens.js b/packages/builder/src/stores/builder/screens.js index 4132a2082f..8298a1469d 100644 --- a/packages/builder/src/stores/builder/screens.js +++ b/packages/builder/src/stores/builder/screens.js @@ -274,7 +274,7 @@ export class ScreenStore extends BudiStore { /** * @param {function} patchFn - * @param {string} screenId + * @param {string | null} screenId * @returns */ async patch(patchFn, screenId) { diff --git a/packages/client/svelte.config.mjs b/packages/client/svelte.config.mjs new file mode 100644 index 0000000000..af7d74ea4b --- /dev/null +++ b/packages/client/svelte.config.mjs @@ -0,0 +1,7 @@ +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte" + +const config = { + preprocess: vitePreprocess(), +} + +export default config diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index c0ad5810b7..bd630e9908 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -1,4 +1,4 @@ -