Rewrite most of the screen creation code to account for views and clean up mess

This commit is contained in:
Andrew Kingston 2023-08-25 12:14:17 +01:00
parent 71c092be1e
commit 09ad3e73ae
5 changed files with 122 additions and 153 deletions

View File

@ -1,10 +1,10 @@
import rowListScreen from "./rowListScreen"
import createFromScratchScreen from "./createFromScratchScreen"
const allTemplates = tables => [...rowListScreen(tables)]
const allTemplates = datasources => [...rowListScreen(datasources)]
// Allows us to apply common behaviour to all create() functions
const createTemplateOverride = (frontendState, template) => () => {
const createTemplateOverride = template => () => {
const screen = template.create()
screen.name = screen.props._id
screen.routing.route = screen.routing.route.toLowerCase()
@ -12,14 +12,13 @@ const createTemplateOverride = (frontendState, template) => () => {
return screen
}
export default (frontendState, tables) => {
export default datasources => {
const enrichTemplate = template => ({
...template,
create: createTemplateOverride(frontendState, template),
create: createTemplateOverride(template),
})
const fromScratch = enrichTemplate(createFromScratchScreen)
const tableTemplates = allTemplates(tables).map(enrichTemplate)
const tableTemplates = allTemplates(datasources).map(enrichTemplate)
return [
fromScratch,
...tableTemplates.sort((templateA, templateB) => {

View File

@ -2,31 +2,26 @@ import sanitizeUrl from "./utils/sanitizeUrl"
import { Screen } from "./utils/Screen"
import { Component } from "./utils/Component"
export default function (tables) {
return tables.map(table => {
export default function (datasources) {
return datasources.map(datasource => {
return {
name: `${table.name} - List`,
create: () => createScreen(table),
name: `${datasource.name} - List`,
create: () => createScreen(datasource),
id: ROW_LIST_TEMPLATE,
table: table._id,
resourceId: datasource.resourceId,
}
})
}
export const ROW_LIST_TEMPLATE = "ROW_LIST_TEMPLATE"
export const rowListUrl = table => sanitizeUrl(`/${table.name}`)
export const rowListUrl = datasource => sanitizeUrl(`/${datasource.name}`)
const generateTableBlock = table => {
const generateTableBlock = datasource => {
const tableBlock = new Component("@budibase/standard-components/tableblock")
tableBlock
.customProps({
title: table.name,
dataSource: {
label: table.name,
name: table._id,
tableId: table._id,
type: "table",
},
title: datasource.name,
dataSource: datasource,
sortOrder: "Ascending",
size: "spectrum--medium",
paginate: true,
@ -36,14 +31,14 @@ const generateTableBlock = table => {
titleButtonText: "Create row",
titleButtonClickBehaviour: "new",
})
.instanceName(`${table.name} - Table block`)
.instanceName(`${datasource.name} - Table block`)
return tableBlock
}
const createScreen = table => {
const createScreen = datasource => {
return new Screen()
.route(rowListUrl(table))
.instanceName(`${table.name} - List`)
.addChild(generateTableBlock(table))
.route(rowListUrl(datasource))
.instanceName(`${datasource.name} - List`)
.addChild(generateTableBlock(datasource))
.json()
}

View File

@ -179,7 +179,7 @@
<Modal bind:this={datasourceModal}>
<DatasourceModal
onConfirm={confirmScreenDatasources}
initalScreens={!selectedTemplates ? [] : [...selectedTemplates]}
initialScreens={!selectedTemplates ? [] : [...selectedTemplates]}
/>
</Modal>

View File

@ -1,41 +1,30 @@
<script>
import { store } from "builderStore"
import {
ModalContent,
Layout,
notifications,
Icon,
Body,
} from "@budibase/bbui"
import { tables, datasources } from "stores/backend"
import getTemplates from "builderStore/store/screenTemplates"
import { ModalContent, Layout, notifications, Body } from "@budibase/bbui"
import { datasources } from "stores/backend"
import ICONS from "components/backend/DatasourceNavigator/icons"
import { IntegrationNames } from "constants"
import { onMount } from "svelte"
import rowListScreen from "builderStore/store/screenTemplates/rowListScreen"
import DatasourceTemplateRow from "./DatasourceTemplateRow.svelte"
export let onCancel
export let onConfirm
export let initalScreens = []
export let initialScreens = []
let selectedScreens = [...initalScreens]
let selectedScreens = [...initialScreens]
const toggleScreenSelection = (table, datasource) => {
if (selectedScreens.find(s => s.table === table._id)) {
$: filteredSources = $datasources.list?.filter(datasource => {
return datasource.source !== IntegrationNames.REST && datasource["entities"]
})
const toggleSelection = datasource => {
const { resourceId } = datasource
if (selectedScreens.find(s => s.resourceId === resourceId)) {
selectedScreens = selectedScreens.filter(
screen => screen.table !== table._id
screen => screen.resourceId !== resourceId
)
} else {
let partialTemplates = getTemplates($store, $tables.list).reduce(
(acc, template) => {
if (template.table === table._id) {
template.datasource = datasource.name
acc.push(template)
}
return acc
},
[]
)
selectedScreens = [...partialTemplates, ...selectedScreens]
selectedScreens = [...selectedScreens, rowListScreen([datasource])[0]]
}
}
@ -45,18 +34,6 @@
})
}
$: filteredSources = Array.isArray($datasources.list)
? $datasources.list.reduce((acc, datasource) => {
if (
datasource.source !== IntegrationNames.REST &&
datasource["entities"]
) {
acc.push(datasource)
}
return acc
}, [])
: []
onMount(async () => {
try {
await datasources.fetch()
@ -81,6 +58,9 @@
</Body>
<Layout noPadding gap="S">
{#each filteredSources as datasource}
{@const entities = Array.isArray(datasource.entities)
? datasource.entities
: Object.values(datasource.entities || {})}
<div class="data-source-wrap">
<div class="data-source-header">
<svelte:component
@ -90,64 +70,49 @@
/>
<div class="data-source-name">{datasource.name}</div>
</div>
{#if Array.isArray(datasource.entities)}
{#each datasource.entities.filter(table => table._id !== "ta_users") as table}
<div
class="data-source-entry"
class:selected={selectedScreens.find(
x => x.table === table._id
)}
on:click={() => toggleScreenSelection(table, datasource)}
>
<svg
width="16px"
height="16px"
class="spectrum-Icon"
style="color: white"
focusable="false"
>
<use xlink:href="#spectrum-icon-18-Table" />
</svg>
{table.name}
{#if selectedScreens.find(x => x.table === table._id)}
<span class="data-source-check">
<Icon size="S" name="CheckmarkCircle" />
</span>
{/if}
</div>
<!-- List all tables -->
{#each entities.filter(table => table._id !== "ta_users") as table}
{@const views = Object.values(table.views || {})}
{@const datasource = {
...table,
// Legacy properties
tableId: table._id,
label: table.name,
// New consistent properties
resourceId: table._id,
name: table.name,
type: "table",
}}
{@const selected = selectedScreens.find(
x => x.resourceId === datasource.resourceId
)}
<DatasourceTemplateRow
on:click={() => toggleSelection(datasource)}
{selected}
{datasource}
/>
<!-- List all views inside this table -->
{#each views as view}
{@const datasource = {
...view,
// Legacy properties
label: view.name,
// New consistent properties
resourceId: view.id,
name: view.name,
type: "viewV2",
}}
{@const selected = selectedScreens.find(
x => x.resourceId === datasource.resourceId
)}
<DatasourceTemplateRow
on:click={() => toggleSelection(datasource)}
{selected}
{datasource}
/>
{/each}
{/if}
{#if datasource["entities"] && !Array.isArray(datasource.entities)}
{#each Object.keys(datasource.entities).filter(table => table._id !== "ta_users") as table_key}
<div
class="data-source-entry"
class:selected={selectedScreens.find(
x => x.table === datasource.entities[table_key]._id
)}
on:click={() =>
toggleScreenSelection(
datasource.entities[table_key],
datasource
)}
>
<svg
width="16px"
height="16px"
class="spectrum-Icon"
style="color: white"
focusable="false"
>
<use xlink:href="#spectrum-icon-18-Table" />
</svg>
{datasource.entities[table_key].name}
{#if selectedScreens.find(x => x.table === datasource.entities[table_key]._id)}
<span class="data-source-check">
<Icon size="S" name="CheckmarkCircle" />
</span>
{/if}
</div>
{/each}
{/if}
{/each}
</div>
{/each}
</Layout>
@ -160,42 +125,10 @@
display: grid;
grid-gap: var(--spacing-s);
}
.data-source-header {
display: flex;
align-items: center;
gap: var(--spacing-m);
padding-bottom: var(--spacing-xs);
}
.data-source-entry {
cursor: pointer;
grid-gap: var(--spectrum-alias-grid-margin-xsmall);
padding: var(--spectrum-alias-item-padding-s);
background: var(--spectrum-alias-background-color-secondary);
transition: 0.3s all;
border: 1px solid var(--spectrum-global-color-gray-300);
border-radius: 4px;
border-width: 1px;
display: flex;
align-items: center;
}
.data-source-entry:hover,
.selected {
background: var(--spectrum-alias-background-color-tertiary);
}
.data-source-entry .data-source-check {
margin-left: auto;
}
.data-source-entry :global(.spectrum-Icon) {
min-width: 16px;
}
.data-source-entry .data-source-check :global(.spectrum-Icon) {
color: var(--spectrum-global-color-green-600);
display: block;
}
</style>

View File

@ -0,0 +1,42 @@
<script>
import { Icon } from "@budibase/bbui"
export let datasource
export let selected = false
$: icon = datasource.type === "viewV2" ? "Remove" : "Table"
</script>
<div class="data-source-entry" class:selected on:click>
<Icon name={icon} color="var(--spectrum-global-color-gray-600)" />
{datasource.name}
{#if selected}
<span class="data-source-check">
<Icon size="S" name="CheckmarkCircle" />
</span>
{/if}
</div>
<style>
.data-source-entry {
cursor: pointer;
grid-gap: 12px;
padding: var(--spectrum-alias-item-padding-s);
background: var(--spectrum-alias-background-color-secondary);
transition: 0.3s all;
border: 1px solid var(--spectrum-global-color-gray-300);
border-radius: 4px;
display: flex;
align-items: center;
}
.data-source-entry:hover,
.selected {
background: var(--spectrum-alias-background-color-tertiary);
}
.data-source-check {
margin-left: auto;
}
.data-source-check :global(.spectrum-Icon) {
color: var(--spectrum-global-color-green-600);
}
</style>