Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert screen store #15408

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions packages/builder/src/stores/builder/automations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { derived, get } from "svelte/store"
import { API } from "@/api"
import { cloneDeep } from "lodash/fp"
import { generate } from "shortid"
import { createHistoryStore } from "@/stores/builder/history"
import { createHistoryStore, HistoryStore } from "@/stores/builder/history"
import { licensing } from "@/stores/portal"
import { tables, appStore } from "@/stores/builder"
import { notifications } from "@budibase/bbui"
Expand Down Expand Up @@ -1428,7 +1428,7 @@ const automationActions = (store: AutomationStore) => ({
})

class AutomationStore extends BudiStore<AutomationState> {
history: any
history: HistoryStore<Automation>
actions: ReturnType<typeof automationActions>

constructor() {
Expand Down
6 changes: 3 additions & 3 deletions packages/builder/src/stores/builder/componentTreeNodes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { get } from "svelte/store"
import { selectedScreen as selectedScreenStore } from "./screens"
import { findComponentPath } from "@/helpers/components"
import { Screen, Component } from "@budibase/types"
import { Component } from "@budibase/types"
import { BudiStore, PersistenceType } from "@/stores/BudiStore"

interface OpenNodesState {
Expand Down Expand Up @@ -49,9 +49,9 @@ export class ComponentTreeNodesStore extends BudiStore<OpenNodesState> {

// 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 selectedScreen = get(selectedScreenStore)

const path = findComponentPath(selectedScreen.props, componentId)
const path = findComponentPath(selectedScreen?.props, componentId)

const componentIds = path.map((component: Component) => component._id)

Expand Down
14 changes: 8 additions & 6 deletions packages/builder/src/stores/builder/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface ComponentDefinition {
settings?: ComponentSetting[]
features?: Record<string, boolean>
typeSupportPresets?: Record<string, any>
illegalChildren?: string[]
}

interface ComponentSetting {
Expand All @@ -57,7 +58,7 @@ interface ComponentSetting {
interface ComponentState {
components: Record<string, ComponentDefinition>
customComponents: string[]
selectedComponentId: string | null
selectedComponentId: string | null | undefined
componentToPaste?: Component | null
settingsCache: Record<string, ComponentSetting[]>
selectedScreenId?: string | null
Expand Down Expand Up @@ -478,10 +479,11 @@ export class ComponentStore extends BudiStore<ComponentState> {
extras._children = []
}

const $selectedScreen = get(selectedScreen)
// Add step name to form steps
if (componentName.endsWith("/formstep")) {
if (componentName.endsWith("/formstep") && $selectedScreen) {
const parentForm = findClosestMatchingComponent(
get(selectedScreen).props,
$selectedScreen.props,
get(selectedComponent)._id,
(component: Component) => component._component.endsWith("/form")
)
Expand Down Expand Up @@ -615,7 +617,7 @@ export class ComponentStore extends BudiStore<ComponentState> {
const state = get(this.store)
componentId = componentId ?? state.selectedComponentId ?? undefined
const screenState = get(screenStore)
screenId = screenId || screenState.selectedScreenId
screenId = (screenId || screenState.selectedScreenId) ?? undefined
}
if (!componentId || !screenId || !patchFn) {
return
Expand Down Expand Up @@ -840,7 +842,7 @@ export class ComponentStore extends BudiStore<ComponentState> {
getPrevious() {
const state = get(this.store)
const componentId = state.selectedComponentId
const screen = get(selectedScreen)
const screen = get(selectedScreen)!
const parent = findComponentParent(screen.props, componentId)
const index = parent?._children.findIndex(
(x: Component) => x._id === componentId
Expand Down Expand Up @@ -889,7 +891,7 @@ export class ComponentStore extends BudiStore<ComponentState> {
const state = get(this.store)
const component = get(selectedComponent)
const componentId = component?._id
const screen = get(selectedScreen)
const screen = get(selectedScreen)!
const parent = findComponentParent(screen.props, componentId)
const index = parent?._children.findIndex(
(x: Component) => x._id === componentId
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
import * as jsonpatch from "fast-json-patch/index.mjs"
import { writable, derived, get } from "svelte/store"
import { Document } from "@budibase/types"
import * as jsonpatch from "fast-json-patch"
import { writable, derived, get, Readable } from "svelte/store"

export const Operations = {
Add: "Add",
Delete: "Delete",
Change: "Change",
export const enum Operations {
Add = "Add",
Delete = "Delete",
Change = "Change",
}

interface Operator<T extends Document> {
id?: number
type: Operations
doc: T
forwardPatch?: jsonpatch.Operation[]
backwardsPatch?: jsonpatch.Operation[]
}

interface HistoryState<T extends Document> {
history: Operator<T>[]
position: number
loading?: boolean
}

export const initialState = {
Expand All @@ -13,14 +28,38 @@ export const initialState = {
loading: false,
}

export const createHistoryStore = ({
export interface HistoryStore<T extends Document>
extends Readable<
HistoryState<T> & {
canUndo: boolean
canRedo: boolean
}
> {
wrapSaveDoc: (
fn: (doc: T) => Promise<T>
) => (doc: T, operationId?: number) => Promise<T>
wrapDeleteDoc: (
fn: (doc: T) => Promise<void>
) => (doc: T, operationId?: number) => Promise<void>

reset: () => void
undo: () => Promise<void>
redo: () => Promise<void>
}

export const createHistoryStore = <T extends Document>({
getDoc,
selectDoc,
beforeAction,
afterAction,
}) => {
}: {
getDoc: (id: string) => T | undefined
selectDoc: (id: string) => void
beforeAction?: (operation?: Operator<T>) => void
afterAction?: (operation?: Operator<T>) => void
}): HistoryStore<T> => {
// Use a derived store to check if we are able to undo or redo any operations
const store = writable(initialState)
const store = writable<HistoryState<T>>(initialState)
const derivedStore = derived(store, $store => {
return {
...$store,
Expand All @@ -31,8 +70,8 @@ export const createHistoryStore = ({

// Wrapped versions of essential functions which we call ourselves when using
// undo and redo
let saveFn
let deleteFn
let saveFn: (doc: T, operationId?: number) => Promise<T>
let deleteFn: (doc: T, operationId?: number) => Promise<void>

/**
* Internal util to set the loading flag
Expand Down Expand Up @@ -66,7 +105,7 @@ export const createHistoryStore = ({
* For internal use only.
* @param operation the operation to save
*/
const saveOperation = operation => {
const saveOperation = (operation: Operator<T>) => {
store.update(state => {
// Update history
let history = state.history
Expand All @@ -93,15 +132,15 @@ export const createHistoryStore = ({
* @param fn the save function
* @returns {function} a wrapped version of the save function
*/
const wrapSaveDoc = fn => {
saveFn = async (doc, operationId) => {
const wrapSaveDoc = (fn: (doc: T) => Promise<T>) => {
saveFn = async (doc: T, operationId?: number) => {
// Only works on a single doc at a time
if (!doc || Array.isArray(doc)) {
return
}
startLoading()
try {
const oldDoc = getDoc(doc._id)
const oldDoc = getDoc(doc._id!)
const newDoc = jsonpatch.deepClone(await fn(doc))

// Store the change
Expand Down Expand Up @@ -141,8 +180,8 @@ export const createHistoryStore = ({
* @param fn the delete function
* @returns {function} a wrapped version of the delete function
*/
const wrapDeleteDoc = fn => {
deleteFn = async (doc, operationId) => {
const wrapDeleteDoc = (fn: (doc: T) => Promise<void>) => {
deleteFn = async (doc: T, operationId?: number) => {
// Only works on a single doc at a time
if (!doc || Array.isArray(doc)) {
return
Expand Down Expand Up @@ -201,7 +240,7 @@ export const createHistoryStore = ({
// Undo ADD
if (operation.type === Operations.Add) {
// Try to get the latest doc version to delete
const latestDoc = getDoc(operation.doc._id)
const latestDoc = getDoc(operation.doc._id!)
const doc = latestDoc || operation.doc
await deleteFn(doc, operation.id)
}
Expand All @@ -219,7 +258,7 @@ export const createHistoryStore = ({
// Undo CHANGE
else {
// Get the current doc and apply the backwards patch on top of it
let doc = jsonpatch.deepClone(getDoc(operation.doc._id))
let doc = jsonpatch.deepClone(getDoc(operation.doc._id!))
if (doc) {
jsonpatch.applyPatch(
doc,
Expand Down Expand Up @@ -283,15 +322,15 @@ export const createHistoryStore = ({
// Redo DELETE
else if (operation.type === Operations.Delete) {
// Try to get the latest doc version to delete
const latestDoc = getDoc(operation.doc._id)
const latestDoc = getDoc(operation.doc._id!)
const doc = latestDoc || operation.doc
await deleteFn(doc, operation.id)
}

// Redo CHANGE
else {
// Get the current doc and apply the forwards patch on top of it
let doc = jsonpatch.deepClone(getDoc(operation.doc._id))
let doc = jsonpatch.deepClone(getDoc(operation.doc._id!))
if (doc) {
jsonpatch.applyPatch(doc, jsonpatch.deepClone(operation.forwardPatch))
await saveFn(doc, operation.id)
Expand Down
Loading
Loading