Add new builder store for row action CRUD, ensuring consistent state everywhere
This commit is contained in:
parent
0e6d903c74
commit
53ff7e1167
|
@ -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>
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue