Use patch for all component methods, add core component patch function, add component move functions to store
This commit is contained in:
parent
5cdd37f6d8
commit
587b385a47
3 changed files with 131 additions and 98 deletions
|
@ -11,7 +11,6 @@ import {
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
import {
|
import {
|
||||||
findComponentType,
|
|
||||||
findComponentParent,
|
findComponentParent,
|
||||||
findClosestMatchingComponent,
|
findClosestMatchingComponent,
|
||||||
findAllMatchingComponents,
|
findAllMatchingComponents,
|
||||||
|
@ -62,7 +61,21 @@ const INITIAL_FRONTEND_STATE = {
|
||||||
export const getFrontendStore = () => {
|
export const getFrontendStore = () => {
|
||||||
const store = writable({ ...INITIAL_FRONTEND_STATE })
|
const store = writable({ ...INITIAL_FRONTEND_STATE })
|
||||||
|
|
||||||
store.subscribe(state => {
|
const sequentialScreenPatch = Utils.sequential(async (patchFn, screenId) => {
|
||||||
|
const state = get(store)
|
||||||
|
const screen = state.screens.find(screen => screen._id === screenId)
|
||||||
|
if (!screen) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let clone = cloneDeep(screen)
|
||||||
|
const result = patchFn(clone)
|
||||||
|
if (result === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return await store.actions.screens.save(clone)
|
||||||
|
})
|
||||||
|
|
||||||
|
store.subscribe(() => {
|
||||||
console.log("new state")
|
console.log("new state")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -228,19 +241,17 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
return savedScreen
|
return savedScreen
|
||||||
},
|
},
|
||||||
patch: Utils.sequential(async (screenId, patchFn) => {
|
patch: async (patchFn, screenId) => {
|
||||||
const state = get(store)
|
// Default to the currently selected screen
|
||||||
const screen = state.screens.find(screen => screen._id === screenId)
|
if (!screenId) {
|
||||||
if (!screen) {
|
const state = get(store)
|
||||||
|
screenId = state.selectedScreenId
|
||||||
|
}
|
||||||
|
if (!screenId || !patchFn) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let clone = cloneDeep(screen)
|
return await sequentialScreenPatch(patchFn, screenId)
|
||||||
const result = patchFn(clone)
|
},
|
||||||
if (result === false) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return await store.actions.screens.save(clone)
|
|
||||||
}),
|
|
||||||
delete: async screens => {
|
delete: async screens => {
|
||||||
const screensToDelete = Array.isArray(screens) ? screens : [screens]
|
const screensToDelete = Array.isArray(screens) ? screens : [screens]
|
||||||
|
|
||||||
|
@ -282,7 +293,9 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateHomeScreen: async (screen, makeHomeScreen = true) => {
|
updateHomeScreen: async (screen, makeHomeScreen = true) => {
|
||||||
let promises = []
|
if (!screen) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Find any existing home screen for this role so we can remove it,
|
// Find any existing home screen for this role so we can remove it,
|
||||||
// if we are setting this to be the new home screen
|
// if we are setting this to be the new home screen
|
||||||
|
@ -297,16 +310,13 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
if (existingHomeScreen) {
|
if (existingHomeScreen) {
|
||||||
const patch = screen => (screen.routing.homeScreen = false)
|
const patch = screen => (screen.routing.homeScreen = false)
|
||||||
promises.push(
|
await store.actions.screens.patch(patch, existingHomeScreen._id)
|
||||||
store.actions.screens.patch(existingHomeScreen._id, patch)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the passed in screen
|
// Update the passed in screen
|
||||||
const patch = screen => (screen.routing.homeScreen = makeHomeScreen)
|
const patch = screen => (screen.routing.homeScreen = makeHomeScreen)
|
||||||
promises.push(store.actions.screens.patch(screen._id, patch))
|
await store.actions.screens.patch(patch, screen._id)
|
||||||
return await Promise.all(promises)
|
|
||||||
},
|
},
|
||||||
removeCustomLayout: async screen => {
|
removeCustomLayout: async screen => {
|
||||||
// Pull relevant settings from old layout, if required
|
// Pull relevant settings from old layout, if required
|
||||||
|
@ -316,14 +326,10 @@ export const getFrontendStore = () => {
|
||||||
screen.showNavigation = layout?.props.navigation !== "None"
|
screen.showNavigation = layout?.props.navigation !== "None"
|
||||||
screen.width = layout?.props.width || "Large"
|
screen.width = layout?.props.width || "Large"
|
||||||
}
|
}
|
||||||
await store.actions.screens.patch(screen._id, patch)
|
await store.actions.screens.patch(patch, screen._id)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
preview: {
|
preview: {
|
||||||
saveSelected: async () => {
|
|
||||||
const selectedAsset = get(currentAsset)
|
|
||||||
return await store.actions.screens.save(selectedAsset)
|
|
||||||
},
|
|
||||||
setDevice: device => {
|
setDevice: device => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.previewDevice = device
|
state.previewDevice = device
|
||||||
|
@ -431,8 +437,8 @@ export const getFrontendStore = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch screen
|
// Patch selected screen
|
||||||
const patch = screen => {
|
await store.actions.screens.patch(screen => {
|
||||||
// Find the selected component
|
// Find the selected component
|
||||||
const currentComponent = findComponent(
|
const currentComponent = findComponent(
|
||||||
screen.props,
|
screen.props,
|
||||||
|
@ -472,8 +478,7 @@ export const getFrontendStore = () => {
|
||||||
parentComponent._children = []
|
parentComponent._children = []
|
||||||
}
|
}
|
||||||
parentComponent._children.push(componentInstance)
|
parentComponent._children.push(componentInstance)
|
||||||
}
|
})
|
||||||
await store.actions.screens.patch(state.selectedScreenId, patch)
|
|
||||||
|
|
||||||
// Select new component
|
// Select new component
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -488,15 +493,34 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
return componentInstance
|
return componentInstance
|
||||||
},
|
},
|
||||||
|
patch: async (patchFn, componentId, screenId) => {
|
||||||
|
// Use selected component by default
|
||||||
|
if (!componentId && !screenId) {
|
||||||
|
const state = get(store)
|
||||||
|
componentId = state.selectedComponentId
|
||||||
|
screenId = state.selectedScreenId
|
||||||
|
}
|
||||||
|
// Invalid if only a screen or component ID provided
|
||||||
|
if (!componentId || !screenId || !patchFn) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const patchScreen = screen => {
|
||||||
|
let component = findComponent(screen.props, componentId)
|
||||||
|
if (!component) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return patchFn(component, screen)
|
||||||
|
}
|
||||||
|
await store.actions.screens.patch(patchScreen, screenId)
|
||||||
|
},
|
||||||
delete: async component => {
|
delete: async component => {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const state = get(store)
|
|
||||||
let parentId
|
let parentId
|
||||||
|
|
||||||
// Patch screen
|
// Patch screen
|
||||||
const patch = screen => {
|
await store.actions.screens.patch(screen => {
|
||||||
// Check component exists
|
// Check component exists
|
||||||
component = findComponent(screen.props, component._id)
|
component = findComponent(screen.props, component._id)
|
||||||
if (!component) {
|
if (!component) {
|
||||||
|
@ -512,8 +536,7 @@ export const getFrontendStore = () => {
|
||||||
parent._children = parent._children.filter(
|
parent._children = parent._children.filter(
|
||||||
child => child._id !== component._id
|
child => child._id !== component._id
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
await store.actions.screens.patch(state.selectedScreenId, patch)
|
|
||||||
|
|
||||||
// Select the deleted component's parent
|
// Select the deleted component's parent
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -522,11 +545,6 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
copy: (component, cut = false, selectParent = true) => {
|
copy: (component, cut = false, selectParent = true) => {
|
||||||
const selectedAsset = get(currentAsset)
|
|
||||||
if (!selectedAsset) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update store with copied component
|
// Update store with copied component
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.componentToPaste = cloneDeep(component)
|
state.componentToPaste = cloneDeep(component)
|
||||||
|
@ -536,7 +554,8 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
// Select the parent if cutting
|
// Select the parent if cutting
|
||||||
if (cut) {
|
if (cut) {
|
||||||
const parent = findComponentParent(selectedAsset.props, component._id)
|
const screen = get(selectedScreen)
|
||||||
|
const parent = findComponentParent(screen?.props, component._id)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
if (selectParent) {
|
if (selectParent) {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -555,7 +574,7 @@ export const getFrontendStore = () => {
|
||||||
let newComponentId
|
let newComponentId
|
||||||
|
|
||||||
// Patch screen
|
// Patch screen
|
||||||
const patch = screen => {
|
await store.actions.screens.patch(screen => {
|
||||||
// Get up to date ref to target
|
// Get up to date ref to target
|
||||||
targetComponent = findComponent(screen.props, targetComponent._id)
|
targetComponent = findComponent(screen.props, targetComponent._id)
|
||||||
if (!targetComponent) {
|
if (!targetComponent) {
|
||||||
|
@ -604,8 +623,7 @@ export const getFrontendStore = () => {
|
||||||
const index = mode === "above" ? targetIndex : targetIndex + 1
|
const index = mode === "above" ? targetIndex : targetIndex + 1
|
||||||
parent._children.splice(index, 0, componentToPaste)
|
parent._children.splice(index, 0, componentToPaste)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
await store.actions.screens.patch(state.selectedScreenId, patch)
|
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -614,39 +632,78 @@ export const getFrontendStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
moveUp: async component => {
|
||||||
|
await store.actions.screens.patch(screen => {
|
||||||
|
const componentId = component?._id
|
||||||
|
const parent = findComponentParent(screen.props, componentId)
|
||||||
|
if (!parent?._children?.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const currentIndex = parent._children.findIndex(
|
||||||
|
child => child._id === componentId
|
||||||
|
)
|
||||||
|
if (currentIndex === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const originalComponent = cloneDeep(parent._children[currentIndex])
|
||||||
|
const newChildren = parent._children.filter(
|
||||||
|
component => component._id !== componentId
|
||||||
|
)
|
||||||
|
newChildren.splice(currentIndex - 1, 0, originalComponent)
|
||||||
|
parent._children = newChildren
|
||||||
|
})
|
||||||
|
},
|
||||||
|
moveDown: async component => {
|
||||||
|
await store.actions.screens.patch(screen => {
|
||||||
|
const componentId = component?._id
|
||||||
|
const parent = findComponentParent(screen.props, componentId)
|
||||||
|
if (!parent?._children?.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const currentIndex = parent._children.findIndex(
|
||||||
|
child => child._id === componentId
|
||||||
|
)
|
||||||
|
if (currentIndex === parent._children.length - 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const originalComponent = cloneDeep(parent._children[currentIndex])
|
||||||
|
const newChildren = parent._children.filter(
|
||||||
|
component => component._id !== componentId
|
||||||
|
)
|
||||||
|
newChildren.splice(currentIndex + 1, 0, originalComponent)
|
||||||
|
parent._children = newChildren
|
||||||
|
})
|
||||||
|
},
|
||||||
updateStyle: async (name, value) => {
|
updateStyle: async (name, value) => {
|
||||||
const selected = get(selectedComponent)
|
await store.actions.components.patch(component => {
|
||||||
if (value == null || value === "") {
|
if (value == null || value === "") {
|
||||||
delete selected._styles.normal[name]
|
delete component._styles.normal[name]
|
||||||
} else {
|
} else {
|
||||||
selected._styles.normal[name] = value
|
component._styles.normal[name] = value
|
||||||
}
|
}
|
||||||
await store.actions.preview.saveSelected()
|
})
|
||||||
},
|
},
|
||||||
updateCustomStyle: async style => {
|
updateCustomStyle: async style => {
|
||||||
const selected = get(selectedComponent)
|
await store.actions.components.patch(component => {
|
||||||
selected._styles.custom = style
|
component._styles.custom = style
|
||||||
await store.actions.preview.saveSelected()
|
})
|
||||||
},
|
},
|
||||||
updateConditions: async conditions => {
|
updateConditions: async conditions => {
|
||||||
const selected = get(selectedComponent)
|
await store.actions.components.patch(component => {
|
||||||
selected._conditions = conditions
|
component._conditions = conditions
|
||||||
await store.actions.preview.saveSelected()
|
})
|
||||||
},
|
},
|
||||||
updateProp: async (name, value) => {
|
updateProp: async (name, value) => {
|
||||||
let component = get(selectedComponent)
|
await store.actions.components.patch(component => {
|
||||||
if (!name || !component) {
|
if (!name || !component) {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
if (component[name] === value) {
|
// Skip update if the value is the same
|
||||||
return
|
if (component[name] === value) {
|
||||||
}
|
return false
|
||||||
component[name] = value
|
}
|
||||||
store.update(state => {
|
component[name] = value
|
||||||
state.selectedComponentId = component._id
|
|
||||||
return state
|
|
||||||
})
|
})
|
||||||
await store.actions.preview.saveSelected()
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
links: {
|
links: {
|
||||||
|
|
|
@ -19,43 +19,19 @@
|
||||||
// not show a context menu.
|
// not show a context menu.
|
||||||
$: showMenu = definition?.editable !== false && definition?.static !== true
|
$: showMenu = definition?.editable !== false && definition?.static !== true
|
||||||
|
|
||||||
const moveUpComponent = () => {
|
const moveUpComponent = async () => {
|
||||||
const asset = get(currentAsset)
|
|
||||||
const parent = findComponentParent(asset?.props, component._id)
|
|
||||||
if (!parent) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const currentIndex = parent._children.indexOf(component)
|
|
||||||
if (currentIndex === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const newChildren = parent._children.filter(c => c !== component)
|
await store.actions.components.moveUp(component)
|
||||||
newChildren.splice(currentIndex - 1, 0, component)
|
|
||||||
parent._children = newChildren
|
|
||||||
store.actions.preview.saveSelected()
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error saving screen")
|
notifications.error("Error moving component up")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const moveDownComponent = () => {
|
const moveDownComponent = async () => {
|
||||||
const asset = get(currentAsset)
|
|
||||||
const parent = findComponentParent(asset?.props, component._id)
|
|
||||||
if (!parent) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const currentIndex = parent._children.indexOf(component)
|
|
||||||
if (currentIndex === parent._children.length - 1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const newChildren = parent._children.filter(c => c !== component)
|
await store.actions.components.moveDown(component)
|
||||||
newChildren.splice(currentIndex + 1, 0, component)
|
|
||||||
parent._children = newChildren
|
|
||||||
store.actions.preview.saveSelected()
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error saving screen")
|
notifications.error("Error moving component down")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,13 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateProp = Utils.sequential(async (key, value) => {
|
const updateProp = async (key, value) => {
|
||||||
try {
|
try {
|
||||||
await store.actions.components.updateProp(key, value)
|
await store.actions.components.updateProp(key, value)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error updating component prop")
|
notifications.error("Error updating component prop")
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
const canRenderControl = setting => {
|
const canRenderControl = setting => {
|
||||||
const control = getComponentForSetting(setting)
|
const control = getComponentForSetting(setting)
|
||||||
|
|
Loading…
Reference in a new issue