move tables to separate store

This commit is contained in:
Keviin Åberg Kultalahti 2021-03-23 11:54:03 +01:00
parent 99423ee51b
commit a440e7631b
27 changed files with 194 additions and 170 deletions

View File

@ -40,101 +40,6 @@ export const getBackendUiStore = () => {
return state
}),
},
tables: {
fetch: async () => {
const tablesResponse = await api.get(`/api/tables`)
const tables = await tablesResponse.json()
store.update(state => {
state.tables = tables
return state
})
},
select: table =>
store.update(state => {
state.selectedTable = table
state.draftTable = cloneDeep(table)
state.selectedView = { name: `all_${table._id}` }
return state
}),
save: async table => {
const updatedTable = cloneDeep(table)
const oldTable = get(store).tables.filter(t => t._id === table._id)[0]
const fieldNames = []
// update any renamed schema keys to reflect their names
for (let key of Object.keys(updatedTable.schema)) {
// if field name has been seen before remove it
if (fieldNames.indexOf(key.toLowerCase()) !== -1) {
delete updatedTable.schema[key]
continue
}
const field = updatedTable.schema[key]
const oldField = oldTable?.schema[key]
// if the type has changed then revert back to the old field
if (oldField != null && oldField.type !== field.type) {
updatedTable.schema[key] = oldField
}
// field has been renamed
if (field.name && field.name !== key) {
updatedTable.schema[field.name] = field
updatedTable._rename = { old: key, updated: field.name }
delete updatedTable.schema[key]
}
// finally record this field has been used
fieldNames.push(key.toLowerCase())
}
const SAVE_TABLE_URL = `/api/tables`
const response = await api.post(SAVE_TABLE_URL, updatedTable)
const savedTable = await response.json()
await store.actions.tables.fetch()
store.actions.tables.select(savedTable)
return savedTable
},
delete: async table => {
await api.delete(`/api/tables/${table._id}/${table._rev}`)
store.update(state => {
state.tables = state.tables.filter(
existing => existing._id !== table._id
)
state.selectedTable = {}
return state
})
},
saveField: ({ originalName, field, primaryDisplay = false, indexes }) => {
store.update(state => {
// delete the original if renaming
// need to handle if the column had no name, empty string
if (originalName || originalName === "") {
delete state.draftTable.schema[originalName]
state.draftTable._rename = {
old: originalName,
updated: field.name,
}
}
// Optionally set display column
if (primaryDisplay) {
state.draftTable.primaryDisplay = field.name
}
if (indexes) {
state.draftTable.indexes = indexes
}
state.draftTable.schema[field.name] = cloneDeep(field)
store.actions.tables.save(state.draftTable)
return state
})
},
deleteField: field => {
store.update(state => {
delete state.draftTable.schema[field.name]
store.actions.tables.save(state.draftTable)
return state
})
},
},
views: {
select: view =>
store.update(state => {

View File

@ -1,4 +1,5 @@
export { database } from "./database"
export { tables } from "./tables"
export { permissions } from "./permissions"
export { roles } from "./roles"
export { datasources } from "./datasources"

View File

@ -0,0 +1,107 @@
import { writable } from "svelte/store"
import { cloneDeep } from "lodash/fp"
import api from "../../api"
function createTablesStore() {
const store = writable({
list: [],
selected: {},
draft: {},
view: {}
})
const { subscribe, update, set } = store
return {
subscribe,
set,
fetch: async () => {
const tablesResponse = await api.get(`/api/tables`)
const tables = await tablesResponse.json()
update(state => ({...state, list: tables}))
},
select: table =>
update(state => ({
...state,
selected: table,
draft: cloneDeep(table),
view: { name: `all_${table._id}` }
})),
save: async table => {
const updatedTable = cloneDeep(table)
const oldTable = get(store).list.filter(t => t._id === table._id)[0]
const fieldNames = []
// update any renamed schema keys to reflect their names
for (let key of Object.keys(updatedTable.schema)) {
// if field name has been seen before remove it
if (fieldNames.indexOf(key.toLowerCase()) !== -1) {
delete updatedTable.schema[key]
continue
}
const field = updatedTable.schema[key]
const oldField = oldTable?.schema[key]
// if the type has changed then revert back to the old field
if (oldField != null && oldField?.type !== field.type) {
updatedTable.schema[key] = oldField
}
// field has been renamed
if (field.name && field.name !== key) {
updatedTable.schema[field.name] = field
updatedTable._rename = { old: key, updated: field.name }
delete updatedTable.schema[key]
}
// finally record this field has been used
fieldNames.push(key.toLowerCase())
}
const response = await api.post(`/api/tables`, updatedTable)
const savedTable = await response.json()
await store.fetch()
await store.select(savedTable)
return savedTable
},
delete: async table => {
await api.delete(`/api/tables/${table._id}/${table._rev}`)
update(state => ({
...state,
list: state.list.filter(existing => existing._id !== table._id),
selected: {}
}))
},
saveField: ({ originalName, field, primaryDisplay = false, indexes }) => {
update(state => {
// delete the original if renaming
// need to handle if the column had no name, empty string
if (originalName || originalName === "") {
delete state.draft.schema[originalName]
state.draft._rename = {
old: originalName,
updated: field.name,
}
}
// Optionally set display column
if (primaryDisplay) {
state.draft.primaryDisplay = field.name
}
if (indexes) {
state.draft.indexes = indexes
}
state.draft.schema[field.name] = cloneDeep(field)
store.save(state.draft)
return state
})
},
deleteField: field => {
update(state => {
delete state.draft.schema[field.name]
store.save(state.draft)
return state
})
},
}
}
export const tables = createTablesStore()

View File

@ -10,7 +10,7 @@ import {
selectedAccessRole,
} from "builderStore"
// Backendstores
import { datasources, integrations, queries, database } from 'builderStore/store/backend/'
import { datasources, integrations, queries, database, tables } from 'builderStore/store/backend/'
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
import api from "../api"
@ -62,15 +62,21 @@ export const getFrontendStore = () => {
await hostingStore.actions.fetch()
// Initialise backend stores
const [_datasources, _integrations, _queries] = await Promise.all([
const [_datasources, _integrations, _queries, _tables] = await Promise.all([
api.get(`/api/datasources`).then(r => r.json()),
api.get("/api/integrations").then(r => r.json()),
api.get(`/api/queries`).then(r => r.json())
api.get(`/api/queries`).then(r => r.json()),
api.get(`/api/tables`).then(r => r.json()),
])
datasources.set({ list: _datasources, selected: null })
integrations.set(_integrations)
queries.set({ list: _queries, selected: null })
database.set(application.instance)
tables.set({
list: _tables,
selected: {},
draft: {}
})
},
routing: {

View File

@ -1,7 +1,7 @@
<script>
import { processStringSync } from "@budibase/string-templates"
import { get } from "lodash/fp"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
export let block
@ -15,7 +15,7 @@
let enrichedInputs = { ...inputs, enriched: {} }
const tableId = inputs.tableId || inputs.row?.tableId
if (tableId) {
enrichedInputs.enriched.table = $backendUiStore.tables.find(
enrichedInputs.enriched.table = $tables.list.find(
table => table._id === tableId
)
}

View File

@ -1,5 +1,5 @@
<script>
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { Select } from "@budibase/bbui"
import DrawerBindableInput from "../../common/DrawerBindableInput.svelte"
import AutomationBindingPanel from "./AutomationBindingPanel.svelte"
@ -7,7 +7,7 @@
export let value
export let bindings
$: table = $backendUiStore.tables.find(table => table._id === value?.tableId)
$: table = $tables.list.find(table => table._id === value?.tableId)
$: schemaFields = Object.entries(table?.schema ?? {})
// Ensure any nullish tableId values get set to empty string so
@ -22,7 +22,7 @@
<div class="block-field">
<Select bind:value={value.tableId} extraThin secondary>
<option value="">Choose an option</option>
{#each $backendUiStore.tables as table}
{#each $tables.list as table}
<option value={table._id}>{table.name}</option>
{/each}
</Select>

View File

@ -1,5 +1,5 @@
<script>
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { Select } from "@budibase/bbui"
export let value
@ -8,7 +8,7 @@
<div class="block-field">
<Select bind:value secondary extraThin>
<option value="">Choose an option</option>
{#each $backendUiStore.tables as table}
{#each $tables.list as table}
<option value={table._id}>{table.name}</option>
{/each}
</Select>

View File

@ -1,7 +1,7 @@
<script>
import api from "builderStore/api"
import Table from "./Table.svelte"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
export let tableId
export let rowId
@ -12,11 +12,11 @@
$: data = row?.[fieldName] ?? []
$: linkedTableId = data?.length ? data[0].tableId : null
$: linkedTable = $backendUiStore.tables.find(
$: linkedTable = $tables.list.find(
table => table._id === linkedTableId
)
$: schema = linkedTable?.schema
$: table = $backendUiStore.tables.find(table => table._id === tableId)
$: table = $tables.list.find(table => table._id === tableId)
$: fetchData(tableId, rowId)
$: {
let rowLabel = row?.[table?.primaryDisplay]

View File

@ -1,6 +1,7 @@
<script>
import api from "builderStore/api"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import Table from "./Table.svelte"
import CalculateButton from "./buttons/CalculateButton.svelte"
import GroupByButton from "./buttons/GroupByButton.svelte"
@ -26,8 +27,8 @@
}
async function fetchViewData(name, field, groupBy, calculation) {
const tables = $backendUiStore.tables
const allTableViews = tables.map(table => table.views)
const _tables = $tables.list
const allTableViews = _tables.map(table => table.views)
const thisView = allTableViews.filter(
views => views != null && views[name] != null
)[0]

View File

@ -9,7 +9,8 @@
Radio,
} from "@budibase/bbui"
import { cloneDeep } from "lodash/fp"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { TableNames, UNEDITABLE_USER_FIELDS } from "constants"
import {
FIELDS,
@ -33,29 +34,29 @@
constraints: fieldDefinitions.STRING.constraints,
// Initial value for column name in other table for linked records
fieldName: $backendUiStore.selectedTable.name,
fieldName: $tables.selected.name,
}
let originalName = field.name
let primaryDisplay =
$backendUiStore.selectedTable.primaryDisplay == null ||
$backendUiStore.selectedTable.primaryDisplay === field.name
$tables.selected.primaryDisplay == null ||
$tables.selected.primaryDisplay === field.name
let table = $backendUiStore.selectedTable
let indexes = [...($backendUiStore.selectedTable.indexes || [])]
let table = $tables.selected
let indexes = [...($tables.selected.indexes || [])]
let confirmDeleteDialog
let deletion
$: tableOptions = $backendUiStore.tables.filter(
table => table._id !== $backendUiStore.draftTable._id
$: tableOptions = $tables.list.filter(
table => table._id !== $tables.draft._id
)
$: required = !!field?.constraints?.presence || primaryDisplay
$: uneditable =
$backendUiStore.selectedTable?._id === TableNames.USERS &&
$tables.selected?._id === TableNames.USERS &&
UNEDITABLE_USER_FIELDS.includes(field.name)
$: invalid =
(field.type === LINK_TYPE && !field.tableId) ||
Object.keys($backendUiStore.draftTable.schema).some(
Object.keys($tables.draft.schema).some(
key => key === field.name
)
@ -72,28 +73,25 @@
async function saveColumn() {
if (field.type === AUTO_COL) {
field = buildAutoColumn(
$backendUiStore.draftTable.name,
$tables.draft.name,
field.name,
field.subtype
)
}
backendUiStore.update(state => {
backendUiStore.actions.tables.saveField({
tables.saveField({
originalName,
field,
primaryDisplay,
indexes,
})
return state
})
onClosed()
}
function deleteColumn() {
if (field.name === $backendUiStore.selectedTable.primaryDisplay) {
if (field.name === $tables.selected.primaryDisplay) {
notifier.danger("You cannot delete the display column")
} else {
backendUiStore.actions.tables.deleteField(field)
tables.deleteField(field)
notifier.success(`Column ${field.name} deleted.`)
onClosed()
}

View File

@ -1,5 +1,6 @@
<script>
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import RowFieldControl from "../RowFieldControl.svelte"
import * as api from "../api"
@ -12,8 +13,8 @@
$: creating = row?._id == null
$: table = row.tableId
? $backendUiStore.tables.find(table => table._id === row?.tableId)
: $backendUiStore.selectedTable
? $tables.list.find(table => table._id === row?.tableId)
: $tables.selected
$: tableSchema = Object.entries(table?.schema ?? {})
async function saveRow() {

View File

@ -1,5 +1,6 @@
<script>
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { roles } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import RowFieldControl from "../RowFieldControl.svelte"
@ -13,8 +14,8 @@
$: creating = row?._id == null
$: table = row.tableId
? $backendUiStore.tables.find(table => table._id === row?.tableId)
: $backendUiStore.selectedTable
? $tables.list.find(table => table._id === row?.tableId)
: $tables.selected
$: tableSchema = getUserSchema(table)
$: customSchemaKeys = getCustomSchemaKeys(tableSchema)

View File

@ -1,6 +1,7 @@
<script>
import { Button, Select } from "@budibase/bbui"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import analytics from "analytics"
@ -22,7 +23,7 @@
export let view = {}
export let onClosed
$: viewTable = $backendUiStore.tables.find(
$: viewTable = $tables.list.find(
({ _id }) => _id === $backendUiStore.selectedView.tableId
)
$: fields =

View File

@ -2,6 +2,7 @@
import { Button, Input } from "@budibase/bbui"
import { goto } from "@sveltech/routify"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import analytics from "analytics"
@ -10,10 +11,7 @@
let name
let field
$: fields = Object.keys($backendUiStore.selectedTable.schema).filter(key => {
return $backendUiStore.selectedTable.schema[key].type === "number"
})
$: views = $backendUiStore.tables.flatMap(table =>
$: views = $tables.list.flatMap(table =>
Object.keys(table.views || {})
)
@ -24,7 +22,7 @@
}
backendUiStore.actions.views.save({
name,
tableId: $backendUiStore.selectedTable._id,
tableId: $tables.selected._id,
field,
})
notifier.success(`View ${name} created`)

View File

@ -1,6 +1,7 @@
<script>
import { Button, Input, Select, DatePicker } from "@budibase/bbui"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import analytics from "analytics"
@ -49,7 +50,7 @@
export let view = {}
export let onClosed
$: viewTable = $backendUiStore.tables.find(
$: viewTable = $tables.list.find(
({ _id }) => _id === $backendUiStore.selectedView.tableId
)
$: fields = viewTable && Object.keys(viewTable.schema)

View File

@ -1,13 +1,14 @@
<script>
import { Button, Select } from "@budibase/bbui"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import { FIELDS } from "constants/backend"
export let view = {}
export let onClosed
$: viewTable = $backendUiStore.tables.find(
$: viewTable = $tables.list.find(
({ _id }) => _id === $backendUiStore.selectedView.tableId
)
$: fields =

View File

@ -1,6 +1,7 @@
<script>
import { goto } from "@sveltech/routify"
import { backendUiStore } from "builderStore"
import { tables, database } from 'builderStore/store/backend/'
import { TableNames } from "constants"
import EditTablePopover from "./popovers/EditTablePopover.svelte"
import EditViewPopover from "./popovers/EditViewPopover.svelte"
@ -10,7 +11,7 @@
$backendUiStore.selectedView && $backendUiStore.selectedView.name
function selectTable(table) {
backendUiStore.actions.tables.select(table)
tables.select(table)
$goto(`./table/${table._id}`)
}
@ -30,9 +31,9 @@
}
</script>
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
{#if $database?.selected?._id}
<div class="hierarchy-items-container">
{#each $backendUiStore.tables as table, idx}
{#each $tables.list as table, idx}
<NavItem
border={idx > 0}
icon={`ri-${table._id === TableNames.USERS ? 'user' : 'table'}-line`}

View File

@ -1,6 +1,7 @@
<script>
import { goto } from "@sveltech/routify"
import { backendUiStore, store } from "builderStore"
import { store } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import { Input, Label, ModalContent, Toggle } from "@budibase/bbui"
import TableDataImport from "../TableDataImport.svelte"
@ -17,7 +18,7 @@
ROW_LIST_TEMPLATE,
]
$: tableNames = $backendUiStore.tables.map(table => table.name)
$: tableNames = $tables.list.map(table => table.name)
let modal
let name
@ -58,7 +59,7 @@
}
// Create table
const table = await backendUiStore.actions.tables.save(newTable)
const table = await tables.save(newTable)
notifier.success(`Table ${name} created successfully.`)
analytics.captureEvent("Table Created", { name })

View File

@ -1,5 +1,5 @@
<script>
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import api from "builderStore/api"
import { Select, Label, Multiselect } from "@budibase/bbui"
import { capitalise } from "../../helpers"
@ -13,7 +13,7 @@
$: linkedRows = linkedIds
$: label = capitalise(schema.name)
$: linkedTableId = schema.tableId
$: linkedTable = $backendUiStore.tables.find(
$: linkedTable = $tables.list.find(
table => table._id === linkedTableId
)
$: fetchRows(linkedTableId)

View File

@ -1,5 +1,6 @@
<script>
import { store, backendUiStore, allScreens } from "builderStore"
import { store, allScreens } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { roles } from 'builderStore/store/backend/'
import { Input, Select, ModalContent, Toggle } from "@budibase/bbui"
import getTemplates from "builderStore/store/screenTemplates"
@ -15,7 +16,7 @@
let createLink = true
let roleId = "BASIC"
$: templates = getTemplates($store, $backendUiStore.tables)
$: templates = getTemplates($store, $tables)
$: route = !route && $allScreens.length === 0 ? "*" : route
$: {
if (templates && templateIndex === undefined) {

View File

@ -9,7 +9,8 @@
Drawer,
} from "@budibase/bbui"
import { createEventDispatcher } from "svelte"
import { store, backendUiStore, currentAsset } from "builderStore"
import { store, currentAsset } from "builderStore"
import { tables as tablesStore } from 'builderStore/store/backend/'
import { datasources, integrations } from 'builderStore/store/backend/'
import { notifier } from "builderStore/store/notifications"
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
@ -23,12 +24,12 @@
export let otherSources
export let showAllQueries
$: tables = $backendUiStore.tables.map(m => ({
$: tables = $tablesStore.list.map(m => ({
label: m.name,
tableId: m._id,
type: "table",
}))
$: views = $backendUiStore.tables.reduce((acc, cur) => {
$: views = $tablesStore.list.reduce((acc, cur) => {
let viewsArr = Object.entries(cur.views).map(([key, value]) => ({
label: key,
name: key,

View File

@ -1,6 +1,6 @@
<script>
import { Select } from "@budibase/bbui"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
export let value
</script>
@ -8,7 +8,7 @@
<div>
<Select extraThin secondary wide on:change {value}>
<option value="">Choose a table</option>
{#each $backendUiStore.tables as table}
{#each $tables.list as table}
<option value={table._id}>{table.name}</option>
{/each}
</Select>

View File

@ -1,6 +1,5 @@
<script>
import { backendUiStore } from "builderStore"
import { datasources } from 'builderStore/store/backend/'
import { datasources, tables } from 'builderStore/store/backend/'
import { goto } from "@sveltech/routify"
import { onMount } from "svelte"
@ -10,7 +9,7 @@
})
</script>
{#if $backendUiStore.tables.length === 0}
{#if $tables.list.length === 0}
<i>Connect your first datasource to start building.</i>
{:else}<i>Select a datasource to edit</i>{/if}

View File

@ -1,13 +1,13 @@
<script>
import { params } from "@sveltech/routify"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
if ($params.selectedTable) {
const table = $backendUiStore.tables.find(
const table = $tables.list.find(
m => m._id === $params.selectedTable
)
if (table) {
backendUiStore.actions.tables.select(table)
tables.select(table)
}
}
</script>

View File

@ -1,5 +1,5 @@
<script>
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { goto, leftover } from "@sveltech/routify"
import { onMount } from "svelte"
@ -8,10 +8,10 @@
// and this is the final url (i.e. no selectedTable)
if (
!$leftover &&
$backendUiStore.tables.length > 0 &&
(!$backendUiStore.selectedTable || !$backendUiStore.selectedTable._id)
$tables.list.length > 0 &&
(!$tables.selected || !$tables.selected._id)
) {
$goto(`./${$backendUiStore.tables[0]._id}`)
$goto(`./${$tables.list[0]._id}`)
}
})
</script>

View File

@ -1,14 +1,14 @@
<script>
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
import { goto } from "@sveltech/routify"
import { onMount } from "svelte"
onMount(async () => {
$backendUiStore.tables.length > 0 && $goto(`../${$backendUiStore.tables[0]._id}`)
$tables.list.length > 0 && $goto(`../${$tables.list[0]._id}`)
})
</script>
{#if $backendUiStore.tables.length === 0}
{#if $tables.list.length === 0}
<i>Create your first table to start building</i>
{:else}<i>Select a table to edit</i>{/if}

View File

@ -1,11 +1,11 @@
<script>
import { params } from "@sveltech/routify"
import { backendUiStore } from "builderStore"
import { tables } from 'builderStore/store/backend/'
if ($params.selectedView) {
let view
const viewName = decodeURI($params.selectedView)
for (let table of $backendUiStore.tables) {
for (let table of $tables.list) {
if (table.views && table.views[viewName]) {
view = table.views[viewName]
}