From b5a45e6d0f8b3c8fb6c9efa04ccac57ced7a2be8 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 30 Dec 2024 15:19:18 +0000 Subject: [PATCH 01/23] Component, Integrations and componentTreeNode stores converted to typescript --- packages/builder/src/dataBinding.js | 2 +- packages/builder/src/stores/builder/app.ts | 12 +- .../builder/src/stores/builder/builder.ts | 28 +- .../src/stores/builder/componentTreeNodes.js | 67 ----- .../src/stores/builder/componentTreeNodes.ts | 69 +++++ .../builder/{components.js => components.ts} | 268 +++++++++++------- .../src/stores/builder/integrations.js | 18 -- .../src/stores/builder/integrations.ts | 41 +++ .../builder/src/stores/builder/screens.js | 2 +- 9 files changed, 301 insertions(+), 206 deletions(-) delete mode 100644 packages/builder/src/stores/builder/componentTreeNodes.js create mode 100644 packages/builder/src/stores/builder/componentTreeNodes.ts rename packages/builder/src/stores/builder/{components.js => components.ts} (83%) delete mode 100644 packages/builder/src/stores/builder/integrations.js create mode 100644 packages/builder/src/stores/builder/integrations.ts diff --git a/packages/builder/src/dataBinding.js b/packages/builder/src/dataBinding.js index c026a36cb3..796a271aff 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/builder/app.ts b/packages/builder/src/stores/builder/app.ts index f98e79eff1..e3226c1e13 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 00f6c5fce7..3822c079f3 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 a8e09a2051..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..72f541cb1b --- /dev/null +++ b/packages/builder/src/stores/builder/componentTreeNodes.ts @@ -0,0 +1,69 @@ +import { get } from "svelte/store" +import { createSessionStorageStore } from "@budibase/frontend-core" +import { selectedScreen as selectedScreenStore } from "./screens" +import { findComponentPath } from "helpers/components" +import { Screen, Component } from "@budibase/types" +import { BudiStore } from "stores/BudiStore" + +interface OpenNodesState { + [key: string]: boolean +} + +export class ComponentTreeNodesStore extends BudiStore { + private baseStore = createSessionStorageStore( + "openNodes", + {} as OpenNodesState + ) + + constructor() { + super({}) + this.subscribe = this.baseStore.subscribe + } + + toggleNode(componentId: string) { + this.baseStore.update((openNodes: OpenNodesState) => { + openNodes[`nodeOpen-${componentId}`] = + !openNodes[`nodeOpen-${componentId}`] + return openNodes + }) + } + + expandNodes(componentIds: string[]) { + this.baseStore.update((openNodes: OpenNodesState) => { + const newNodes = Object.fromEntries( + componentIds.map(id => [`nodeOpen-${id}`, true]) + ) + return { ...openNodes, ...newNodes } + }) + } + + collapseNodes(componentIds: string[]) { + this.baseStore.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 = get(selectedScreenStore) as Screen + const path = findComponentPath(selectedScreen.props, componentId) + const componentIds = path.map((component: Component) => component._id) + + this.baseStore.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.baseStore) + 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 e3fafd6f83..338c4ace2f 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 6ee58961c7..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..320a447068 --- /dev/null +++ b/packages/builder/src/stores/builder/integrations.ts @@ -0,0 +1,41 @@ +import { writable, type Writable } from "svelte/store" +import { API } from "api" +import { Integration, SourceName } from "@budibase/types" + +type IntegrationsState = Record + +const INITIAL_STATE: IntegrationsState = { + [SourceName.POSTGRES]: undefined, + [SourceName.DYNAMODB]: undefined, + [SourceName.MONGODB]: undefined, + [SourceName.ELASTICSEARCH]: undefined, + [SourceName.COUCHDB]: undefined, + [SourceName.SQL_SERVER]: undefined, + [SourceName.S3]: undefined, + [SourceName.AIRTABLE]: undefined, + [SourceName.MYSQL]: undefined, + [SourceName.ARANGODB]: undefined, + [SourceName.REST]: undefined, + [SourceName.FIRESTORE]: undefined, + [SourceName.GOOGLE_SHEETS]: undefined, + [SourceName.REDIS]: undefined, + [SourceName.SNOWFLAKE]: undefined, + [SourceName.ORACLE]: undefined, + [SourceName.BUDIBASE]: undefined, +} + +const createIntegrationsStore = () => { + const store: Writable = writable(INITIAL_STATE) + + 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/screens.js b/packages/builder/src/stores/builder/screens.js index 4e3d9b1ec6..42f61a5e0e 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) { From 0146b1c38925a1dc751d12e645e9875547bb3c81 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 30 Dec 2024 15:21:51 +0000 Subject: [PATCH 02/23] formatting --- packages/builder/src/stores/builder/componentTreeNodes.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/componentTreeNodes.ts b/packages/builder/src/stores/builder/componentTreeNodes.ts index 72f541cb1b..6d2d524a79 100644 --- a/packages/builder/src/stores/builder/componentTreeNodes.ts +++ b/packages/builder/src/stores/builder/componentTreeNodes.ts @@ -24,6 +24,7 @@ export class ComponentTreeNodesStore extends BudiStore { this.baseStore.update((openNodes: OpenNodesState) => { openNodes[`nodeOpen-${componentId}`] = !openNodes[`nodeOpen-${componentId}`] + return openNodes }) } @@ -33,6 +34,7 @@ export class ComponentTreeNodesStore extends BudiStore { const newNodes = Object.fromEntries( componentIds.map(id => [`nodeOpen-${id}`, true]) ) + return { ...openNodes, ...newNodes } }) } @@ -42,20 +44,24 @@ export class ComponentTreeNodesStore extends BudiStore { 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 = get(selectedScreenStore) as Screen + const selectedScreen: Screen = get(selectedScreenStore) + const path = findComponentPath(selectedScreen.props, componentId) + const componentIds = path.map((component: Component) => component._id) this.baseStore.update((openNodes: OpenNodesState) => { const newNodes = Object.fromEntries( componentIds.map((id: string) => [`nodeOpen-${id}`, true]) ) + return { ...openNodes, ...newNodes } }) } From ba834a8cfc4c673ca8b8fd482f51d853dd8d930d Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 31 Dec 2024 09:44:39 +0000 Subject: [PATCH 03/23] remove undefineds from integrations to satisfy response type --- .../src/stores/builder/integrations.ts | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/packages/builder/src/stores/builder/integrations.ts b/packages/builder/src/stores/builder/integrations.ts index 320a447068..786b74f1c9 100644 --- a/packages/builder/src/stores/builder/integrations.ts +++ b/packages/builder/src/stores/builder/integrations.ts @@ -1,34 +1,27 @@ import { writable, type Writable } from "svelte/store" import { API } from "api" -import { Integration, SourceName } from "@budibase/types" +import { Integration } from "@budibase/types" -type IntegrationsState = Record +type IntegrationsState = Record -const INITIAL_STATE: IntegrationsState = { - [SourceName.POSTGRES]: undefined, - [SourceName.DYNAMODB]: undefined, - [SourceName.MONGODB]: undefined, - [SourceName.ELASTICSEARCH]: undefined, - [SourceName.COUCHDB]: undefined, - [SourceName.SQL_SERVER]: undefined, - [SourceName.S3]: undefined, - [SourceName.AIRTABLE]: undefined, - [SourceName.MYSQL]: undefined, - [SourceName.ARANGODB]: undefined, - [SourceName.REST]: undefined, - [SourceName.FIRESTORE]: undefined, - [SourceName.GOOGLE_SHEETS]: undefined, - [SourceName.REDIS]: undefined, - [SourceName.SNOWFLAKE]: undefined, - [SourceName.ORACLE]: undefined, - [SourceName.BUDIBASE]: undefined, -} +const INITIAL_STATE: IntegrationsState = {} const createIntegrationsStore = () => { const store: Writable = writable(INITIAL_STATE) const init = async () => { - const integrations = await API.getIntegrations() + 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) } From 0b2b9ae1ac3a299f63ae5a67e3dbc891638a9b93 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 11:36:37 +0100 Subject: [PATCH 04/23] Initial viewport conversion --- .../grid/stores/{viewport.js => viewport.ts} | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) rename packages/frontend-core/src/components/grid/stores/{viewport.js => viewport.ts} (87%) diff --git a/packages/frontend-core/src/components/grid/stores/viewport.js b/packages/frontend-core/src/components/grid/stores/viewport.ts similarity index 87% rename from packages/frontend-core/src/components/grid/stores/viewport.js rename to packages/frontend-core/src/components/grid/stores/viewport.ts index 0797f38b55..3cc5c11000 100644 --- a/packages/frontend-core/src/components/grid/stores/viewport.js +++ b/packages/frontend-core/src/components/grid/stores/viewport.ts @@ -1,7 +1,15 @@ -import { derived } from "svelte/store" +import { derived, Readable } from "svelte/store" import { MinColumnWidth } from "../lib/constants" +import { Store as StoreContext } from "." -export const deriveStores = context => { +interface ViewportDerivedStore { + scrolledRowCount: Readable + visualRowCapacity: Readable + renderedRows: Readable + columnRenderMap: Readable +} + +export const deriveStores = (context: StoreContext): ViewportDerivedStore => { const { rowHeight, scrollableColumns, From 66e71caf1bc5987fb7e05aaa4839a2d8305b4d19 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:12:20 +0100 Subject: [PATCH 05/23] Type anys --- packages/frontend-core/src/components/grid/stores/viewport.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/viewport.ts b/packages/frontend-core/src/components/grid/stores/viewport.ts index 3cc5c11000..47cfc55d36 100644 --- a/packages/frontend-core/src/components/grid/stores/viewport.ts +++ b/packages/frontend-core/src/components/grid/stores/viewport.ts @@ -6,7 +6,7 @@ interface ViewportDerivedStore { scrolledRowCount: Readable visualRowCapacity: Readable renderedRows: Readable - columnRenderMap: Readable + columnRenderMap: Readable> } export const deriveStores = (context: StoreContext): ViewportDerivedStore => { @@ -85,7 +85,7 @@ export const deriveStores = (context: StoreContext): ViewportDerivedStore => { leftEdge += $scrollableColumns[endColIdx].width endColIdx++ } - let next = {} + let next: Record = {} $scrollableColumns .slice(Math.max(0, startColIdx), endColIdx) .forEach(col => { From d68bc44249c2c6596fc591d82cc1f58da8297678 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:13:19 +0100 Subject: [PATCH 06/23] Type anys --- .../frontend-core/src/components/grid/stores/viewport.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/viewport.ts b/packages/frontend-core/src/components/grid/stores/viewport.ts index 47cfc55d36..b7e6279db2 100644 --- a/packages/frontend-core/src/components/grid/stores/viewport.ts +++ b/packages/frontend-core/src/components/grid/stores/viewport.ts @@ -1,11 +1,12 @@ import { derived, Readable } from "svelte/store" import { MinColumnWidth } from "../lib/constants" import { Store as StoreContext } from "." +import { Row } from "@budibase/types" interface ViewportDerivedStore { - scrolledRowCount: Readable - visualRowCapacity: Readable - renderedRows: Readable + scrolledRowCount: Readable + visualRowCapacity: Readable + renderedRows: Readable columnRenderMap: Readable> } From 901e3eaba4a06fc1e07d5901937b1085ce0a46c6 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:14:51 +0100 Subject: [PATCH 07/23] Type bounds --- .../src/components/grid/stores/{bounds.js => bounds.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/frontend-core/src/components/grid/stores/{bounds.js => bounds.ts} (100%) diff --git a/packages/frontend-core/src/components/grid/stores/bounds.js b/packages/frontend-core/src/components/grid/stores/bounds.ts similarity index 100% rename from packages/frontend-core/src/components/grid/stores/bounds.js rename to packages/frontend-core/src/components/grid/stores/bounds.ts From 350c91012f43d71948b548dc917587dabe521a06 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:21:06 +0100 Subject: [PATCH 08/23] Type cache --- .../grid/stores/{cache.js => cache.ts} | 27 ++++++++++++++----- .../src/components/grid/stores/index.ts | 3 ++- 2 files changed, 23 insertions(+), 7 deletions(-) rename packages/frontend-core/src/components/grid/stores/{cache.js => cache.ts} (63%) diff --git a/packages/frontend-core/src/components/grid/stores/cache.js b/packages/frontend-core/src/components/grid/stores/cache.ts similarity index 63% rename from packages/frontend-core/src/components/grid/stores/cache.js rename to packages/frontend-core/src/components/grid/stores/cache.ts index cf4690f15b..999a3ea11d 100644 --- a/packages/frontend-core/src/components/grid/stores/cache.js +++ b/packages/frontend-core/src/components/grid/stores/cache.ts @@ -1,16 +1,31 @@ -export const createActions = context => { +import { FindTableResponse } from "@budibase/types" +import { Store as StoreContext } from "." + +interface CacheActionStore { + cache: { + actions: { + getPrimaryDisplayForTableId: (tableId: string) => Promise + getTable: (tableId: string) => Promise + resetCache: () => any + } + } +} + +export type Store = CacheActionStore + +export const createActions = (context: StoreContext): CacheActionStore => { const { API } = context // Cache for the primary display columns of different tables. // If we ever need to cache table definitions for other purposes then we can // expand this to be a more generic cache. - let tableCache = {} + let tableCache: Record> = {} const resetCache = () => { tableCache = {} } - const fetchTable = async tableId => { + const fetchTable = async (tableId: string) => { // If we've never encountered this tableId before then store a promise that // resolves to the primary display so that subsequent invocations before the // promise completes can reuse this promise @@ -21,13 +36,13 @@ export const createActions = context => { return await tableCache[tableId] } - const getPrimaryDisplayForTableId = async tableId => { + const getPrimaryDisplayForTableId = async (tableId: string) => { const table = await fetchTable(tableId) const display = table?.primaryDisplay || table?.schema?.[0]?.name return display } - const getTable = async tableId => { + const getTable = async (tableId: string) => { const table = await fetchTable(tableId) return table } @@ -43,7 +58,7 @@ export const createActions = context => { } } -export const initialise = context => { +export const initialise = (context: StoreContext) => { const { datasource, cache } = context // Wipe the caches whenever the datasource changes to ensure we aren't diff --git a/packages/frontend-core/src/components/grid/stores/index.ts b/packages/frontend-core/src/components/grid/stores/index.ts index 9581f9ff7c..755e69a0fa 100644 --- a/packages/frontend-core/src/components/grid/stores/index.ts +++ b/packages/frontend-core/src/components/grid/stores/index.ts @@ -106,7 +106,8 @@ export type Store = BaseStore & Reorder.Store & Resize.Store & Config.Store & - Conditions.Store + Conditions.Store & + Cache.Store export const attachStores = (context: Store): Store => { // Atomic store creation From bee3a4b2336c5db90e8be49b0ca5f5c86ee1d62e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:22:15 +0100 Subject: [PATCH 09/23] Type notifications --- .../grid/stores/{notifications.js => notifications.ts} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename packages/frontend-core/src/components/grid/stores/{notifications.js => notifications.ts} (87%) diff --git a/packages/frontend-core/src/components/grid/stores/notifications.js b/packages/frontend-core/src/components/grid/stores/notifications.ts similarity index 87% rename from packages/frontend-core/src/components/grid/stores/notifications.js rename to packages/frontend-core/src/components/grid/stores/notifications.ts index 4e8b49414d..05c8039704 100644 --- a/packages/frontend-core/src/components/grid/stores/notifications.js +++ b/packages/frontend-core/src/components/grid/stores/notifications.ts @@ -1,7 +1,8 @@ import { notifications as BBUINotifications } from "@budibase/bbui" import { derived } from "svelte/store" +import { Store as StoreContext } from "." -export const createStores = context => { +export const createStores = (context: StoreContext) => { const { notifySuccess, notifyError } = context // Normally we would not derive a store in "createStores" as it should be From 4ffb365c647bd76b25dbc2d1339eff60562af173 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:23:10 +0100 Subject: [PATCH 10/23] Type pagination --- packages/frontend-core/src/components/grid/stores/index.ts | 3 ++- .../components/grid/stores/{pagination.js => pagination.ts} | 3 ++- packages/frontend-core/src/components/grid/stores/viewport.ts | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) rename packages/frontend-core/src/components/grid/stores/{pagination.js => pagination.ts} (89%) diff --git a/packages/frontend-core/src/components/grid/stores/index.ts b/packages/frontend-core/src/components/grid/stores/index.ts index 755e69a0fa..753266f893 100644 --- a/packages/frontend-core/src/components/grid/stores/index.ts +++ b/packages/frontend-core/src/components/grid/stores/index.ts @@ -107,7 +107,8 @@ export type Store = BaseStore & Resize.Store & Config.Store & Conditions.Store & - Cache.Store + Cache.Store & + Viewport.Store export const attachStores = (context: Store): Store => { // Atomic store creation diff --git a/packages/frontend-core/src/components/grid/stores/pagination.js b/packages/frontend-core/src/components/grid/stores/pagination.ts similarity index 89% rename from packages/frontend-core/src/components/grid/stores/pagination.js rename to packages/frontend-core/src/components/grid/stores/pagination.ts index bcf10ee3df..5a97031147 100644 --- a/packages/frontend-core/src/components/grid/stores/pagination.js +++ b/packages/frontend-core/src/components/grid/stores/pagination.ts @@ -1,6 +1,7 @@ import { derived } from "svelte/store" +import { Store as StoreContext } from "." -export const initialise = context => { +export const initialise = (context: StoreContext) => { const { scrolledRowCount, rows, visualRowCapacity } = context // Derive how many rows we have in total diff --git a/packages/frontend-core/src/components/grid/stores/viewport.ts b/packages/frontend-core/src/components/grid/stores/viewport.ts index b7e6279db2..25620c33ef 100644 --- a/packages/frontend-core/src/components/grid/stores/viewport.ts +++ b/packages/frontend-core/src/components/grid/stores/viewport.ts @@ -10,6 +10,8 @@ interface ViewportDerivedStore { columnRenderMap: Readable> } +export type Store = ViewportDerivedStore + export const deriveStores = (context: StoreContext): ViewportDerivedStore => { const { rowHeight, From 4d784b530a85145927a03bc07c47a5bdad4ee641 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:27:58 +0100 Subject: [PATCH 11/23] Types notification --- .../src/components/grid/stores/index.ts | 4 ++-- .../src/components/grid/stores/notifications.ts | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/index.ts b/packages/frontend-core/src/components/grid/stores/index.ts index 753266f893..d55002186f 100644 --- a/packages/frontend-core/src/components/grid/stores/index.ts +++ b/packages/frontend-core/src/components/grid/stores/index.ts @@ -98,7 +98,6 @@ export type Store = BaseStore & sort: Writable subscribe: any dispatch: (event: string, data: any) => any - notifications: Writable width: Writable bounds: Readable height: Readable @@ -108,7 +107,8 @@ export type Store = BaseStore & Config.Store & Conditions.Store & Cache.Store & - Viewport.Store + Viewport.Store & + Notifications.Store export const attachStores = (context: Store): Store => { // Atomic store creation diff --git a/packages/frontend-core/src/components/grid/stores/notifications.ts b/packages/frontend-core/src/components/grid/stores/notifications.ts index 05c8039704..429760ed50 100644 --- a/packages/frontend-core/src/components/grid/stores/notifications.ts +++ b/packages/frontend-core/src/components/grid/stores/notifications.ts @@ -1,8 +1,17 @@ import { notifications as BBUINotifications } from "@budibase/bbui" -import { derived } from "svelte/store" +import { derived, Readable } from "svelte/store" import { Store as StoreContext } from "." -export const createStores = (context: StoreContext) => { +interface NotificationStore { + notifications: Readable<{ + success: (message: string) => void + error: (message: string) => void + }> +} + +export type Store = NotificationStore + +export const createStores = (context: StoreContext): NotificationStore => { const { notifySuccess, notifyError } = context // Normally we would not derive a store in "createStores" as it should be From 078053a417e0d6016801dd4789e62f390d6040cc Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:28:59 +0100 Subject: [PATCH 12/23] Convert sort --- .../src/components/grid/stores/{sort.js => sort.ts} | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename packages/frontend-core/src/components/grid/stores/{sort.js => sort.ts} (88%) diff --git a/packages/frontend-core/src/components/grid/stores/sort.js b/packages/frontend-core/src/components/grid/stores/sort.ts similarity index 88% rename from packages/frontend-core/src/components/grid/stores/sort.js rename to packages/frontend-core/src/components/grid/stores/sort.ts index 9ab393b11f..474de59e7b 100644 --- a/packages/frontend-core/src/components/grid/stores/sort.js +++ b/packages/frontend-core/src/components/grid/stores/sort.ts @@ -1,8 +1,9 @@ import { derived, get } from "svelte/store" import { memo } from "../../../utils" import { SortOrder } from "@budibase/types" +import { Store as StoreContext } from "." -export const createStores = context => { +export const createStores = (context: StoreContext) => { const { props } = context const $props = get(props) @@ -17,7 +18,7 @@ export const createStores = context => { } } -export const initialise = context => { +export const initialise = (context: StoreContext) => { const { sort, initialSortColumn, initialSortOrder, schema } = context // Reset sort when initial sort props change From 56fe3ce6feeeb4c0ebcf6dacad8340931195f3df Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:40:52 +0100 Subject: [PATCH 13/23] Type sort store --- .../components/grid/stores/datasources/viewV2.ts | 2 +- .../src/components/grid/stores/index.ts | 4 ++-- .../src/components/grid/stores/sort.ts | 13 +++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts b/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts index 71c22e6866..6a788d3ec6 100644 --- a/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts +++ b/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts @@ -173,7 +173,7 @@ export const initialise = (context: StoreContext) => { await datasource.actions.saveDefinition({ ...$view, sort: { - field: $sort.column, + field: $sort.column!, order: $sort.order || SortOrder.ASCENDING, }, }) diff --git a/packages/frontend-core/src/components/grid/stores/index.ts b/packages/frontend-core/src/components/grid/stores/index.ts index d55002186f..8a4d40976d 100644 --- a/packages/frontend-core/src/components/grid/stores/index.ts +++ b/packages/frontend-core/src/components/grid/stores/index.ts @@ -95,7 +95,6 @@ export type Store = BaseStore & Clipboard.Store & Scroll.Store & { // TODO while typing the rest of stores - sort: Writable subscribe: any dispatch: (event: string, data: any) => any width: Writable @@ -108,7 +107,8 @@ export type Store = BaseStore & Conditions.Store & Cache.Store & Viewport.Store & - Notifications.Store + Notifications.Store & + Sort.Store export const attachStores = (context: Store): Store => { // Atomic store creation diff --git a/packages/frontend-core/src/components/grid/stores/sort.ts b/packages/frontend-core/src/components/grid/stores/sort.ts index 474de59e7b..ab58d7dabe 100644 --- a/packages/frontend-core/src/components/grid/stores/sort.ts +++ b/packages/frontend-core/src/components/grid/stores/sort.ts @@ -1,9 +1,18 @@ -import { derived, get } from "svelte/store" +import { derived, get, Writable } from "svelte/store" import { memo } from "../../../utils" import { SortOrder } from "@budibase/types" import { Store as StoreContext } from "." -export const createStores = (context: StoreContext) => { +interface SortStore { + sort: Writable<{ + column: string | null | undefined + order: SortOrder + }> +} + +export type Store = SortStore + +export const createStores = (context: StoreContext): SortStore => { const { props } = context const $props = get(props) From 0c937e0827688313ea479249fd45a56d54f5f58b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:44:43 +0100 Subject: [PATCH 14/23] Type bounds --- .../src/components/grid/stores/bounds.ts | 17 +++++++++++++++-- .../src/components/grid/stores/index.ts | 8 +++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/bounds.ts b/packages/frontend-core/src/components/grid/stores/bounds.ts index c0939f7389..0050555f96 100644 --- a/packages/frontend-core/src/components/grid/stores/bounds.ts +++ b/packages/frontend-core/src/components/grid/stores/bounds.ts @@ -1,6 +1,19 @@ -import { derived, writable } from "svelte/store" +import { derived, Readable, Writable, writable } from "svelte/store" -export const createStores = () => { +interface BoundsStore { + bounds: Writable<{ + left: number + top: number + width: number + height: number + }> + height: Readable + width: Readable +} + +export type Store = BoundsStore + +export const createStores = (): BoundsStore => { const bounds = writable({ left: 0, top: 0, diff --git a/packages/frontend-core/src/components/grid/stores/index.ts b/packages/frontend-core/src/components/grid/stores/index.ts index 8a4d40976d..1b5e2a48c1 100644 --- a/packages/frontend-core/src/components/grid/stores/index.ts +++ b/packages/frontend-core/src/components/grid/stores/index.ts @@ -1,4 +1,4 @@ -import { Readable, Writable } from "svelte/store" +import { Writable } from "svelte/store" import type { APIClient } from "../../../api/types" import * as Bounds from "./bounds" @@ -97,9 +97,6 @@ export type Store = BaseStore & // TODO while typing the rest of stores subscribe: any dispatch: (event: string, data: any) => any - width: Writable - bounds: Readable - height: Readable } & Rows.Store & Reorder.Store & Resize.Store & @@ -108,7 +105,8 @@ export type Store = BaseStore & Cache.Store & Viewport.Store & Notifications.Store & - Sort.Store + Sort.Store & + Bounds.Store export const attachStores = (context: Store): Store => { // Atomic store creation From d476a5c5cd519fa0427cbca4dc833d1eb22970c8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 13:59:08 +0100 Subject: [PATCH 15/23] Type event store --- .../src/components/grid/lib/{events.js => events.ts} | 6 +++--- .../frontend-core/src/components/grid/stores/index.ts | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) rename packages/frontend-core/src/components/grid/lib/{events.js => events.ts} (78%) diff --git a/packages/frontend-core/src/components/grid/lib/events.js b/packages/frontend-core/src/components/grid/lib/events.ts similarity index 78% rename from packages/frontend-core/src/components/grid/lib/events.js rename to packages/frontend-core/src/components/grid/lib/events.ts index 1c486858b2..7fd826954a 100644 --- a/packages/frontend-core/src/components/grid/lib/events.js +++ b/packages/frontend-core/src/components/grid/lib/events.ts @@ -2,11 +2,11 @@ import { createEventDispatcher } from "svelte" export const createEventManagers = () => { const svelteDispatch = createEventDispatcher() - let subscribers = {} + let subscribers: Record void)[]> = {} // Dispatches an event, notifying subscribers and also emitting a normal // svelte event - const dispatch = (event, payload) => { + const dispatch = (event: string, payload: any) => { svelteDispatch(event, payload) const subs = subscribers[event] || [] for (let i = 0; i < subs.length; i++) { @@ -15,7 +15,7 @@ export const createEventManagers = () => { } // Subscribes to events - const subscribe = (event, callback) => { + const subscribe = (event: string, callback: () => void) => { const subs = subscribers[event] || [] subscribers[event] = [...subs, callback] diff --git a/packages/frontend-core/src/components/grid/stores/index.ts b/packages/frontend-core/src/components/grid/stores/index.ts index 1b5e2a48c1..422b264473 100644 --- a/packages/frontend-core/src/components/grid/stores/index.ts +++ b/packages/frontend-core/src/components/grid/stores/index.ts @@ -79,6 +79,8 @@ export interface BaseStore { API: APIClient gridID: string props: Writable + subscribe: any + dispatch: (event: string, data: any) => any } export type Store = BaseStore & @@ -93,11 +95,8 @@ export type Store = BaseStore & Filter.Store & UI.Store & Clipboard.Store & - Scroll.Store & { - // TODO while typing the rest of stores - subscribe: any - dispatch: (event: string, data: any) => any - } & Rows.Store & + Scroll.Store & + Rows.Store & Reorder.Store & Resize.Store & Config.Store & From 51c7fe8c5b98ca009e3e143b87756b4843a942c2 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 14:05:17 +0100 Subject: [PATCH 16/23] Type grid svelte file --- .../src/components/grid/layout/Grid.svelte | 11 +++++------ .../frontend-core/src/components/grid/stores/index.ts | 5 ++++- 2 files changed, 9 insertions(+), 7 deletions(-) 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 @@ - diff --git a/tsconfig.build.json b/tsconfig.build.json index d51625a34f..a05fa2c976 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -19,7 +19,8 @@ "@budibase/pro": ["./packages/pro/src"], "@budibase/string-templates": ["./packages/string-templates/src"], "@budibase/string-templates/*": ["./packages/string-templates/*"], - "@budibase/frontend-core": ["./packages/frontend-core/src"] + "@budibase/frontend-core": ["./packages/frontend-core/src"], + "@budibase/bbui": ["./packages/bbui/src"] } }, "exclude": [] From 405c0184057b78cfaa46afe3702b47e69aff053d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 30 Dec 2024 22:30:23 +0100 Subject: [PATCH 19/23] Allow client to consume frontend-core svelte.ts --- packages/client/svelte.config.mjs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/client/svelte.config.mjs 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 From aa07af596be8ef9bed524aab25fbccb9d40311f4 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 31 Dec 2024 12:24:26 +0100 Subject: [PATCH 20/23] Fix types --- .../src/components/grid/stores/datasources/nonPlus.ts | 2 +- .../src/components/grid/stores/datasources/table.ts | 2 +- .../src/components/grid/stores/datasources/viewV2.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasources/nonPlus.ts b/packages/frontend-core/src/components/grid/stores/datasources/nonPlus.ts index ae8f187278..6e81ff3e48 100644 --- a/packages/frontend-core/src/components/grid/stores/datasources/nonPlus.ts +++ b/packages/frontend-core/src/components/grid/stores/datasources/nonPlus.ts @@ -122,7 +122,7 @@ export const initialise = (context: StoreContext) => { } $fetch?.update({ sortOrder: $sort.order || SortOrder.ASCENDING, - sortColumn: $sort.column, + sortColumn: $sort.column ?? undefined, }) }) ) diff --git a/packages/frontend-core/src/components/grid/stores/datasources/table.ts b/packages/frontend-core/src/components/grid/stores/datasources/table.ts index e52faef5cc..27fa638596 100644 --- a/packages/frontend-core/src/components/grid/stores/datasources/table.ts +++ b/packages/frontend-core/src/components/grid/stores/datasources/table.ts @@ -139,7 +139,7 @@ export const initialise = (context: StoreContext) => { } $fetch.update({ sortOrder: $sort.order || SortOrder.ASCENDING, - sortColumn: $sort.column, + sortColumn: $sort.column ?? undefined, }) }) ) diff --git a/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts b/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts index 6a788d3ec6..4dc5a44fd5 100644 --- a/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts +++ b/packages/frontend-core/src/components/grid/stores/datasources/viewV2.ts @@ -187,7 +187,7 @@ export const initialise = (context: StoreContext) => { } $fetch.update({ sortOrder: $sort.order, - sortColumn: $sort.column, + sortColumn: $sort.column ?? undefined, }) }) ) From 71c4d3bc5af2767ae02f6cf132efce37cb626004 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 31 Dec 2024 12:40:51 +0100 Subject: [PATCH 21/23] Fix width when default --- packages/frontend-core/src/components/grid/stores/columns.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/stores/columns.ts b/packages/frontend-core/src/components/grid/stores/columns.ts index 70b93d93e6..f54e8067b2 100644 --- a/packages/frontend-core/src/components/grid/stores/columns.ts +++ b/packages/frontend-core/src/components/grid/stores/columns.ts @@ -182,7 +182,7 @@ export const initialise = (context: StoreContext) => { name: field, label: fieldSchema.displayName || field, schema: fieldSchema, - width: fieldSchema.width || oldColumn?.width || DefaultColumnWidth, + width: fieldSchema.width || DefaultColumnWidth, visible: fieldSchema.visible ?? true, readonly: fieldSchema.readonly, order: fieldSchema.order ?? oldColumn?.order, From 511592bf6c0a83be4674711d5d646352904b901f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 31 Dec 2024 12:43:16 +0100 Subject: [PATCH 22/23] Fix order between views --- packages/frontend-core/src/components/grid/stores/columns.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/columns.ts b/packages/frontend-core/src/components/grid/stores/columns.ts index f54e8067b2..1b3f6624e1 100644 --- a/packages/frontend-core/src/components/grid/stores/columns.ts +++ b/packages/frontend-core/src/components/grid/stores/columns.ts @@ -161,7 +161,7 @@ export const initialise = (context: StoreContext) => { columns.set([]) return } - const $columns = get(columns) + const $displayColumn = get(displayColumn) // Find primary display @@ -176,7 +176,6 @@ export const initialise = (context: StoreContext) => { Object.keys($enrichedSchema) .map(field => { const fieldSchema = $enrichedSchema[field] - const oldColumn = $columns?.find(col => col.name === field) const column: UIColumn = { type: fieldSchema.type, name: field, @@ -185,7 +184,7 @@ export const initialise = (context: StoreContext) => { width: fieldSchema.width || DefaultColumnWidth, visible: fieldSchema.visible ?? true, readonly: fieldSchema.readonly, - order: fieldSchema.order ?? oldColumn?.order, + order: fieldSchema.order, conditions: fieldSchema.conditions, related: fieldSchema.related, calculationType: fieldSchema.calculationType, From 28116f135c49836c8104ab457d096b43d79959d0 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 31 Dec 2024 12:19:47 +0000 Subject: [PATCH 23/23] allow passing of persistance storage opt --- packages/builder/src/stores/BudiStore.ts | 30 ++++++++++++++++++- .../src/stores/builder/componentTreeNodes.ts | 26 ++++++++-------- 2 files changed, 41 insertions(+), 15 deletions(-) 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/componentTreeNodes.ts b/packages/builder/src/stores/builder/componentTreeNodes.ts index 6d2d524a79..6c6f522ce1 100644 --- a/packages/builder/src/stores/builder/componentTreeNodes.ts +++ b/packages/builder/src/stores/builder/componentTreeNodes.ts @@ -1,27 +1,25 @@ import { get } from "svelte/store" -import { createSessionStorageStore } from "@budibase/frontend-core" import { selectedScreen as selectedScreenStore } from "./screens" import { findComponentPath } from "helpers/components" import { Screen, Component } from "@budibase/types" -import { BudiStore } from "stores/BudiStore" +import { BudiStore, PersistenceType } from "stores/BudiStore" interface OpenNodesState { [key: string]: boolean } export class ComponentTreeNodesStore extends BudiStore { - private baseStore = createSessionStorageStore( - "openNodes", - {} as OpenNodesState - ) - constructor() { - super({}) - this.subscribe = this.baseStore.subscribe + super({} as OpenNodesState, { + persistence: { + type: PersistenceType.SESSION, + key: "openNodes", + }, + }) } toggleNode(componentId: string) { - this.baseStore.update((openNodes: OpenNodesState) => { + this.update((openNodes: OpenNodesState) => { openNodes[`nodeOpen-${componentId}`] = !openNodes[`nodeOpen-${componentId}`] @@ -30,7 +28,7 @@ export class ComponentTreeNodesStore extends BudiStore { } expandNodes(componentIds: string[]) { - this.baseStore.update((openNodes: OpenNodesState) => { + this.update((openNodes: OpenNodesState) => { const newNodes = Object.fromEntries( componentIds.map(id => [`nodeOpen-${id}`, true]) ) @@ -40,7 +38,7 @@ export class ComponentTreeNodesStore extends BudiStore { } collapseNodes(componentIds: string[]) { - this.baseStore.update((openNodes: OpenNodesState) => { + this.update((openNodes: OpenNodesState) => { const newNodes = Object.fromEntries( componentIds.map(id => [`nodeOpen-${id}`, false]) ) @@ -57,7 +55,7 @@ export class ComponentTreeNodesStore extends BudiStore { const componentIds = path.map((component: Component) => component._id) - this.baseStore.update((openNodes: OpenNodesState) => { + this.update((openNodes: OpenNodesState) => { const newNodes = Object.fromEntries( componentIds.map((id: string) => [`nodeOpen-${id}`, true]) ) @@ -67,7 +65,7 @@ export class ComponentTreeNodesStore extends BudiStore { } isNodeExpanded(componentId: string): boolean { - const openNodes = get(this.baseStore) + const openNodes = get(this) return !!openNodes[`nodeOpen-${componentId}`] } }