1
0
Fork 0
mirror of synced 2024-09-21 03:43:21 +12:00

Add new builder store for row action CRUD, ensuring consistent state everywhere

This commit is contained in:
Andrew Kingston 2024-09-03 18:58:22 +01:00
parent 0e6d903c74
commit 53ff7e1167
No known key found for this signature in database
8 changed files with 173 additions and 63 deletions

View file

@ -9,21 +9,20 @@
} from "@budibase/bbui"
import DetailPopover from "components/common/DetailPopover.svelte"
import { getContext } from "svelte"
import { appStore, automationStore } from "stores/builder"
import { appStore, rowActions } from "stores/builder"
import { API } from "api"
import { goto, url } from "@roxi/routify"
import { derived } from "svelte/store"
import { getSequentialName } from "helpers/duplicate"
const { datasource } = getContext("grid")
let rowActions = []
$: ds = $datasource
$: tableId = ds?.tableId
$: viewId = ds?.id
$: isView = ds?.type === "viewV2"
$: fetchRowActions(ds)
$: actionCount = rowActions.filter(action => !isView || action.enabled).length
$: tableRowActions = $rowActions[tableId] || []
$: viewRowActions = $rowActions[viewId] || []
$: actionCount = isView ? viewRowActions.length : tableRowActions.length
const rowActionUrl = derived([url, appStore], ([$url, $appStore]) => {
return ({ automationId }) => {
@ -31,30 +30,11 @@
}
})
const fetchRowActions = async datasource => {
if (!datasource?.tableId) {
rowActions = []
return
}
const res = await API.rowActions.fetch(datasource.tableId)
rowActions = Object.values(res || {}).map(action => ({
...action,
enabled: !isView || action.allowedViews?.includes(ds.id),
}))
}
const createRowAction = async () => {
try {
const name = getSequentialName(rowActions, "New row action ", {
getName: x => x.name,
})
const res = await API.rowActions.create({
name,
tableId,
})
await automationStore.actions.fetch()
const newRowAction = await rowActions.createRowAction(tableId, viewId)
notifications.success("Row action created successfully")
$goto($rowActionUrl(res))
// $goto($rowActionUrl(newRowAction))
} catch (error) {
console.error(error)
notifications.error("Error creating row action")
@ -62,19 +42,10 @@
}
const toggleAction = async (action, enabled) => {
console.log(action, enabled)
if (enabled) {
await API.rowActions.enableView({
tableId,
rowActionId: action.id,
viewId: ds.id,
})
await rowActions.enableView(tableId, viewId, action.id)
} else {
await API.rowActions.disableView({
tableId,
rowActionId: action.id,
viewId: ds.id,
})
await rowActions.disableView(tableId, viewId, action.id)
}
}
</script>
@ -96,18 +67,18 @@
Use the toggle to enable/disable row actions for this view.
<br />
{/if}
{#if !rowActions.length}
{#if !tableRowActions.length}
<br />
You haven't created any row actions.
{:else}
<List>
{#each rowActions as action}
{#each tableRowActions as action}
<ListItem title={action.name} url={$rowActionUrl(action)} showArrow>
<svelte:fragment slot="right">
{#if isView}
<span>
<Toggle
value={action.enabled}
value={action.allowedViews?.includes(viewId)}
on:change={e => toggleAction(action, e.detail)}
/>
</span>

View file

@ -1,5 +1,5 @@
<script>
import { viewsV2 } from "stores/builder"
import { viewsV2, rowActions } from "stores/builder"
import { admin } from "stores/portal"
import { Grid } from "@budibase/frontend-core"
import { API } from "api"
@ -21,6 +21,21 @@
id,
tableId: $viewsV2.selected?.tableId,
}
$: buttons = makeRowActionButtons($rowActions[id])
$: rowActions.refreshRowActions(id)
const makeRowActionButtons = rowActions => {
return (rowActions || []).map(action => ({
text: action.name,
onClick: async row => {
await API.rowActions.trigger({
rowActionId: action.id,
sourceId: id,
rowId: row._id,
})
},
}))
}
const handleGridViewUpdate = async e => {
viewsV2.replaceView(id, e.detail)
@ -35,6 +50,8 @@
showAvatars={false}
on:updatedatasource={handleGridViewUpdate}
isCloud={$admin.cloud}
{buttons}
buttonsCollapsed
>
<svelte:fragment slot="controls">
<GridFilterButton />

View file

@ -1,6 +1,12 @@
<script>
import { Banner } from "@budibase/bbui"
import { datasources, tables, integrations, appStore } from "stores/builder"
import {
datasources,
tables,
integrations,
appStore,
rowActions,
} from "stores/builder"
import { themeStore, admin } from "stores/portal"
import { TableNames } from "constants"
import { Grid } from "@budibase/frontend-core"
@ -28,7 +34,6 @@
status: { displayName: "Status", disabled: true },
}
let rowActions = []
let generateButton
$: autoColumnStatus = verifyAutocolumns($tables?.selected)
@ -54,11 +59,11 @@
$: relationshipsEnabled = relationshipSupport(tableDatasource)
$: currentTheme = $themeStore?.theme
$: darkMode = !currentTheme.includes("light")
$: buttons = makeRowActionButtons(rowActions)
$: fetchRowActions(id)
$: buttons = makeRowActionButtons($rowActions[id])
$: rowActions.refreshRowActions(id)
const makeRowActionButtons = rowActions => {
return rowActions.map(action => ({
return (rowActions || []).map(action => ({
text: action.name,
onClick: async row => {
await API.rowActions.trigger({
@ -98,15 +103,6 @@
return acc
}, {})
}
const fetchRowActions = async tableId => {
if (!tableId) {
rowActions = []
return
}
const res = await API.rowActions.fetch(tableId)
rowActions = Object.values(res || {})
}
</script>
{#if $tables?.selected?.name}

View file

@ -2,9 +2,8 @@ import { writable } from "svelte/store"
export default class BudiStore {
constructor(init, opts) {
const store = writable({
...init,
})
this.initialState = init
const store = writable({ ...init })
/**
* Internal Svelte store
@ -23,6 +22,7 @@ export default class BudiStore {
* *Store modification should be kept to a minimum
*/
this.update = this.store.update
this.set = this.store.set
/**
* Optional debug mode to output the store updates to console
@ -33,4 +33,8 @@ export default class BudiStore {
})
}
}
reset = () => {
this.store.set({ ...this.initialState })
}
}

View file

@ -29,6 +29,7 @@ import { integrations } from "./integrations"
import { sortedIntegrations } from "./sortedIntegrations"
import { queries } from "./queries"
import { flags } from "./flags"
import { rowActions } from "./rowActions"
import componentTreeNodesStore from "./componentTreeNodes"
export {
@ -65,6 +66,7 @@ export {
flags,
hoverStore,
snippets,
rowActions,
}
export const reset = () => {
@ -74,6 +76,7 @@ export const reset = () => {
componentStore.reset()
layoutStore.reset()
navigationStore.reset()
rowActions.reset()
}
const refreshBuilderData = async () => {

View file

@ -0,0 +1,114 @@
import { get, derived } from "svelte/store"
import BudiStore from "stores/BudiStore"
import { tables } from "./tables"
import { viewsV2 } from "./viewsV2"
import { automationStore } from "./automations"
import { API } from "api"
import { getSequentialName } from "helpers/duplicate"
const initialState = {}
export class RowActionStore extends BudiStore {
constructor() {
super(initialState)
}
refreshRowActions = async sourceId => {
if (!sourceId) {
return
}
// Get the underlying table ID for this source ID
let tableId = get(tables).list.find(table => table._id === sourceId)?._id
if (!tableId) {
const view = get(viewsV2).list.find(view => view.id === sourceId)
tableId = view?.tableId
}
if (!tableId) {
return
}
// Fetch row actions for this table
const res = await API.rowActions.fetch(tableId)
const actions = Object.values(res || {})
this.update(state => ({
...state,
[tableId]: actions,
}))
}
createRowAction = async (tableId, viewId) => {
if (!tableId) {
return
}
// Get a unique name for this action
const existingRowActions = get(this.store)[tableId] || []
const name = getSequentialName(existingRowActions, "New row action ", {
getName: x => x.name,
})
// Create the action and update state
const res = await API.rowActions.create({
name,
tableId,
})
this.update(state => ({
...state,
[tableId]: [...(state[tableId] || []), res],
}))
// If adding to a view, enable on this view
if (viewId) {
await this.enableView(tableId, viewId, res.id)
}
// Refresh automations so we have this new row action automation
await automationStore.actions.fetch()
return res
}
enableView = async (tableId, viewId, rowActionId) => {
await API.rowActions.enableView({
tableId,
viewId,
rowActionId,
})
await this.refreshRowActions(tableId)
}
disableView = async (tableId, viewId, rowActionId) => {
await API.rowActions.disableView({
tableId,
viewId,
rowActionId,
})
await this.refreshRowActions(tableId)
}
}
const store = new RowActionStore()
const derivedStore = derived(store, $store => {
let map = {}
// Generate an entry for every view as well
Object.keys($store || {}).forEach(tableId => {
map[tableId] = $store[tableId]
for (let action of $store[tableId]) {
for (let viewId of action.allowedViews || []) {
if (!map[viewId]) {
map[viewId] = []
}
map[viewId].push(action)
}
}
})
return map
})
export const rowActions = {
...store,
subscribe: derivedStore.subscribe,
}

View file

@ -104,7 +104,6 @@ export const createLicensingStore = () => {
const isBusinessPlan = planType === Constants.PlanType.BUSINESS
const isEnterpriseTrial =
planType === Constants.PlanType.ENTERPRISE_BASIC_TRIAL
console.log(license)
const groupsEnabled = license.features.includes(
Constants.Features.USER_GROUPS
)
@ -143,8 +142,6 @@ export const createLicensingStore = () => {
Constants.Features.VIEW_READONLY_COLUMNS
)
console.log(isViewReadonlyColumnsEnabled)
store.update(state => {
return {
...state,

View file

@ -25,7 +25,7 @@
let container
$: buttons = $props.buttons?.slice(0, 3) || []
$: buttons = getButtons($props)
$: columnsWidth = $scrollableColumns.reduce(
(total, col) => (total += col.width),
0
@ -34,6 +34,14 @@
$: gridEnd = $width - $buttonColumnWidth - 1
$: left = Math.min(columnEnd, gridEnd)
const getButtons = ({ buttons, buttonsCollapsed }) => {
let gridButtons = buttons || []
if (!buttonsCollapsed) {
return gridButtons.slice(0, 3)
}
return gridButtons
}
const handleClick = async (button, row) => {
await button.onClick?.(rows.actions.cleanRow(row))
await rows.actions.refreshRow(row._id)