diff --git a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js index 8d4dc48a94..603c730508 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/rowListScreen.js @@ -82,18 +82,45 @@ const createScreen = table => { }, }) - const grid = new Component("@budibase/standard-components/datagrid") + const spectrumTable = new Component("@budibase/standard-components/table") .customProps({ dataProvider: `{{ literal ${makePropSafe(provider._json._id)} }}`, - editable: false, - theme: "alpine", - height: "540", - pagination: true, - detailUrl: `${rowListUrl(table)}/:id`, + theme: "spectrum--lightest", + showAutoColumns: false, + quiet: false, + size: "spectrum--medium", + rowCount: 8, }) - .instanceName("Grid") + .instanceName(`${table.name} Table`) - provider.addChild(grid) + const safeTableId = makePropSafe(spectrumTable._json._id) + const safeRowId = makePropSafe("_id") + const viewButton = new Component("@budibase/standard-components/button") + .customProps({ + text: "View", + onClick: [ + { + "##eventHandlerType": "Navigate To", + parameters: { + url: `${rowListUrl(table)}/{{ ${safeTableId}.${safeRowId} }}`, + }, + }, + ], + }) + .instanceName("View Button") + .normalStyle({ + background: "transparent", + "font-family": "Inter, sans-serif", + "font-weight": "500", + color: "#888", + "border-width": "0", + }) + .hoverStyle({ + color: "#4285f4", + }) + + spectrumTable.addChild(viewButton) + provider.addChild(spectrumTable) const mainContainer = new Component("@budibase/standard-components/container") .normalStyle({ diff --git a/packages/builder/src/components/design/AppPreview/componentStructure.json b/packages/builder/src/components/design/AppPreview/componentStructure.json index 9dadf2aa25..267289a804 100644 --- a/packages/builder/src/components/design/AppPreview/componentStructure.json +++ b/packages/builder/src/components/design/AppPreview/componentStructure.json @@ -1,7 +1,6 @@ [ "container", "dataprovider", - "datagrid", "table", "repeater", "button", diff --git a/packages/standard-components/manifest.json b/packages/standard-components/manifest.json index 36a4cbd1d5..9cd8999088 100644 --- a/packages/standard-components/manifest.json +++ b/packages/standard-components/manifest.json @@ -8,47 +8,6 @@ "transitionable": true, "settings": [] }, - "datagrid": { - "name": "Grid", - "description": "A datagrid component with functionality to add, remove and edit rows.", - "icon": "ri-grid-line", - "styleable": true, - "settings": [ - { - "type": "dataProvider", - "label": "Data", - "key": "dataProvider" - }, - { - "type": "detailScreen", - "label": "Detail URL", - "key": "detailUrl" - }, - { - "type": "boolean", - "label": "Editable", - "key": "editable" - }, - { - "type": "select", - "label": "Theme", - "key": "theme", - "options": ["alpine", "alpine-dark", "balham", "balham-dark", "material"], - "defaultValue": "alpine" - }, - { - "type": "number", - "label": "Height", - "key": "height", - "defaultValue": "500" - }, - { - "type": "boolean", - "label": "Pagination", - "key": "pagination" - } - ] - }, "screenslot": { "name": "Screenslot", "icon": "ri-artboard-2-line", diff --git a/packages/standard-components/package.json b/packages/standard-components/package.json index 70e441b49a..492c6449c6 100644 --- a/packages/standard-components/package.json +++ b/packages/standard-components/package.json @@ -41,7 +41,6 @@ "dependencies": { "@adobe/spectrum-css-workflow-icons": "^1.1.0", "@budibase/bbui": "^1.58.13", - "@budibase/svelte-ag-grid": "^1.0.4", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/button": "^3.0.1", "@spectrum-css/checkbox": "^3.0.1", diff --git a/packages/standard-components/src/grid/AttachmentCell/Button.svelte b/packages/standard-components/src/grid/AttachmentCell/Button.svelte deleted file mode 100644 index 12f3cc8e9f..0000000000 --- a/packages/standard-components/src/grid/AttachmentCell/Button.svelte +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/packages/standard-components/src/grid/AttachmentCell/Modal.svelte b/packages/standard-components/src/grid/AttachmentCell/Modal.svelte deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/standard-components/src/grid/Component.svelte b/packages/standard-components/src/grid/Component.svelte deleted file mode 100644 index c7e0f24d3c..0000000000 --- a/packages/standard-components/src/grid/Component.svelte +++ /dev/null @@ -1,180 +0,0 @@ - - -
- {#if dataLoaded} - {#if canAddDelete} -
- {#if selectedRows.length > 0} - - - Delete - {selectedRows.length} - row(s) - - {/if} -
- {/if} - (selectedRows = detail)} /> - {/if} - - - Are you sure you want to delete {selectedRows.length} row(s)? - - -
- - diff --git a/packages/standard-components/src/grid/CreateRow/Button.svelte b/packages/standard-components/src/grid/CreateRow/Button.svelte deleted file mode 100644 index ab3513de91..0000000000 --- a/packages/standard-components/src/grid/CreateRow/Button.svelte +++ /dev/null @@ -1,37 +0,0 @@ - - -
- -
- -
Add New Row
- dispatch('newRow')} /> -
- - diff --git a/packages/standard-components/src/grid/CreateRow/Modal.svelte b/packages/standard-components/src/grid/CreateRow/Modal.svelte deleted file mode 100644 index 1cb9aa923d..0000000000 --- a/packages/standard-components/src/grid/CreateRow/Modal.svelte +++ /dev/null @@ -1,144 +0,0 @@ - - -
- {#each errorMessages as error} -

{error}

- {/each} -
- {#each fields as field} -
- - {#if schema[field].type === 'string' && schema[field].constraints.inclusion} - - {:else if schema[field].type === 'datetime'} - - {:else if schema[field].type === 'boolean'} - - {:else if schema[field].type === 'number'} - - {:else if schema[field].type === 'string'} - - {:else if schema[field].type === 'longform'} - - {:else if schema[field].type === 'attachment'} - - {/if} -
-
- {/each} -
-
- - - diff --git a/packages/standard-components/src/grid/DateTime/Wrapper.svelte b/packages/standard-components/src/grid/DateTime/Wrapper.svelte deleted file mode 100644 index b493626d64..0000000000 --- a/packages/standard-components/src/grid/DateTime/Wrapper.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/packages/standard-components/src/grid/Relationship/RelationshipDisplay.svelte b/packages/standard-components/src/grid/Relationship/RelationshipDisplay.svelte deleted file mode 100644 index f269f8f2a8..0000000000 --- a/packages/standard-components/src/grid/Relationship/RelationshipDisplay.svelte +++ /dev/null @@ -1,75 +0,0 @@ - - -
- {#if linkedRows && linkedRows.length && displayColumn} - {#each linkedRows as linkedRow} - {#if linkedRow[displayColumn] != null && linkedRow[displayColumn] !== ''} -
{linkedRow[displayColumn]}
- {/if} - {/each} - {:else}{count} related row(s){/if} -
- - diff --git a/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte b/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte deleted file mode 100644 index ec64255855..0000000000 --- a/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte +++ /dev/null @@ -1,32 +0,0 @@ - - -
- {#each items as item} -
{item?.primaryDisplay ?? ''}
- {/each} -
- - diff --git a/packages/standard-components/src/grid/Select/Wrapper.svelte b/packages/standard-components/src/grid/Select/Wrapper.svelte deleted file mode 100644 index 4c4a8eaf21..0000000000 --- a/packages/standard-components/src/grid/Select/Wrapper.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - - diff --git a/packages/standard-components/src/grid/ViewDetails/Cell.svelte b/packages/standard-components/src/grid/ViewDetails/Cell.svelte deleted file mode 100644 index f222429aa8..0000000000 --- a/packages/standard-components/src/grid/ViewDetails/Cell.svelte +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - diff --git a/packages/standard-components/src/grid/customRenderer.js b/packages/standard-components/src/grid/customRenderer.js deleted file mode 100644 index fd558baa98..0000000000 --- a/packages/standard-components/src/grid/customRenderer.js +++ /dev/null @@ -1,169 +0,0 @@ -// Custom renderers to handle special types -// https://www.ag-grid.com/javascript-grid-cell-rendering-components/ - -import AttachmentCell from "./AttachmentCell/Button.svelte" -import ViewDetails from "./ViewDetails/Cell.svelte" -import Select from "./Select/Wrapper.svelte" -import DatePicker from "./DateTime/Wrapper.svelte" -import RelationshipLabel from "./Relationship/RelationshipLabel.svelte" - -const renderers = new Map([ - ["boolean", booleanRenderer], - ["attachment", attachmentRenderer], - ["options", optionsRenderer], - ["link", linkedRowRenderer], - ["_id", viewDetailsRenderer], -]) - -export function getRenderer(schema, editable, SDK) { - if (renderers.get(schema.type)) { - return renderers.get(schema.type)( - schema.options, - schema.constraints, - editable, - SDK - ) - } else { - return false - } -} - -/* eslint-disable no-unused-vars */ -function booleanRenderer(options, constraints, editable, SDK) { - return params => { - const toggle = e => { - params.value = !params.value - params.setValue(e.currentTarget.checked) - } - let input = document.createElement("input") - input.style.display = "grid" - input.style.placeItems = "center" - input.style.height = "100%" - input.type = "checkbox" - input.checked = params.value - if (editable) { - input.addEventListener("click", toggle) - } else { - input.disabled = true - } - - return input - } -} -/* eslint-disable no-unused-vars */ -function attachmentRenderer(options, constraints, editable, SDK) { - return params => { - const container = document.createElement("div") - - const attachmentInstance = new AttachmentCell({ - target: container, - props: { - files: params.value || [], - SDK, - }, - }) - - const deleteFile = event => { - const newFilesArray = params.value.filter(file => file !== event.detail) - params.setValue(newFilesArray) - } - - attachmentInstance.$on("delete", deleteFile) - - return container - } -} -/* eslint-disable no-unused-vars */ -function dateRenderer(options, constraints, editable, SDK) { - return function(params) { - const container = document.createElement("div") - const toggle = e => { - params.setValue(e.detail[0][0]) - } - - // Options need to be passed in with minTime and maxTime! Needs bbui update. - new DatePicker({ - target: container, - props: { - value: params.value, - SDK, - }, - }) - - return container - } -} - -function optionsRenderer(options, constraints, editable, SDK) { - return params => { - if (!editable) return params.value - const container = document.createElement("div") - container.style.display = "grid" - container.style.placeItems = "center" - container.style.height = "100%" - const change = e => { - params.setValue(e.detail) - } - - const selectInstance = new Select({ - target: container, - props: { - value: params.value, - options: constraints.inclusion, - SDK, - }, - }) - - selectInstance.$on("change", change) - - return container - } -} -/* eslint-disable no-unused-vars */ -function linkedRowRenderer(options, constraints, editable, SDK) { - return params => { - let container = document.createElement("div") - container.style.display = "grid" - container.style.placeItems = "center" - container.style.height = "100%" - - new RelationshipLabel({ - target: container, - props: { - row: params.data, - columnName: params.column.colId, - SDK, - }, - }) - - return container - } -} - -/* eslint-disable no-unused-vars */ -function viewDetailsRenderer(options, constraints, editable, SDK) { - return params => { - let container = document.createElement("div") - container.style.display = "grid" - container.style.alignItems = "center" - container.style.height = "100%" - - let url = "/" - if (options.detailUrl) { - url = options.detailUrl.replace(":id", params.data._id) - } - if (!url.startsWith("/")) { - url = `/${url}` - } - - new ViewDetails({ - target: container, - props: { - url, - SDK, - }, - }) - - return container - } -} diff --git a/packages/standard-components/src/grid/valueSetters.js b/packages/standard-components/src/grid/valueSetters.js deleted file mode 100644 index 2da8182092..0000000000 --- a/packages/standard-components/src/grid/valueSetters.js +++ /dev/null @@ -1,6 +0,0 @@ -// https://www.ag-grid.com/javascript-grid-value-setters/ -// These handles values and makes sure they adhere to the data type provided by the table -export const number = params => { - params.data[params.colDef.field] = parseFloat(params.newValue) - return true -} diff --git a/packages/standard-components/src/index.js b/packages/standard-components/src/index.js index 9280825ebf..d1ad792247 100644 --- a/packages/standard-components/src/index.js +++ b/packages/standard-components/src/index.js @@ -14,7 +14,6 @@ loadSpectrumIcons() export { default as container } from "./Container.svelte" export { default as dataprovider } from "./DataProvider.svelte" -export { default as datagrid } from "./grid/Component.svelte" export { default as screenslot } from "./ScreenSlot.svelte" export { default as button } from "./Button.svelte" export { default as repeater } from "./Repeater.svelte" diff --git a/packages/standard-components/src/table/DateTimeRenderer.svelte b/packages/standard-components/src/table/DateTimeRenderer.svelte index fbde2999e1..169adab163 100644 --- a/packages/standard-components/src/table/DateTimeRenderer.svelte +++ b/packages/standard-components/src/table/DateTimeRenderer.svelte @@ -4,4 +4,10 @@ export let value -{dayjs(value).format('MMMM D YYYY, HH:mm')} +
{dayjs(value).format('MMMM D YYYY, HH:mm')}
+ + diff --git a/packages/standard-components/src/table/StringRenderer.svelte b/packages/standard-components/src/table/StringRenderer.svelte index 92f3c035c8..2756839616 100644 --- a/packages/standard-components/src/table/StringRenderer.svelte +++ b/packages/standard-components/src/table/StringRenderer.svelte @@ -8,6 +8,6 @@ div { overflow: hidden; text-overflow: ellipsis; - max-width: 320px; + width: 150px; } diff --git a/packages/standard-components/src/table/Table.svelte b/packages/standard-components/src/table/Table.svelte index b1f2a3ef2e..faa689aa97 100644 --- a/packages/standard-components/src/table/Table.svelte +++ b/packages/standard-components/src/table/Table.svelte @@ -14,22 +14,42 @@ const component = getContext("component") const { styleable, Provider } = getContext("sdk") + // Config + const rowHeight = 55 + const headerHeight = 36 + const rowPreload = 5 + const maxRows = 100 + + // Sorting state let sortColumn let sortOrder - $: rows = dataProvider?.rows ?? [] - $: contentStyle = getContentStyle(rowCount, rows.length) - $: sortedRows = sortRows(rows, sortColumn, sortOrder) + // Table state $: loaded = dataProvider?.loaded ?? false + $: rows = dataProvider?.rows ?? [] + $: visibleRowCount = Math.min(rows.length, rowCount || maxRows, maxRows) + $: scroll = rows.length > visibleRowCount + $: contentStyle = getContentStyle(visibleRowCount, scroll) + $: sortedRows = sortRows(rows, sortColumn, sortOrder) $: schema = dataProvider?.schema ?? {} $: fields = getFields(schema, columns, showAutoColumns) - const getContentStyle = (rowCount, dataCount) => { - if (!rowCount) { + // Scrolling state + let timeout + let nextScrollTop = 0 + let scrollTop = 0 + $: firstVisibleRow = calculateFirstVisibleRow(scrollTop) + $: lastVisibleRow = calculateLastVisibleRow( + firstVisibleRow, + visibleRowCount, + rows.length + ) + + const getContentStyle = (visibleRows, scroll) => { + if (!scroll) { return "" } - const actualCount = Math.min(rowCount, dataCount) - return `height: ${35 + actualCount * 56}px;` + return `height: ${headerHeight - 1 + visibleRows * (rowHeight + 1)}px;` } const sortRows = (rows, sortColumn, sortOrder) => { @@ -71,69 +91,101 @@ }) return columns.concat(autoColumns) } + + const onScroll = event => { + nextScrollTop = event.target.scrollTop + if (timeout) { + return + } + timeout = setTimeout(() => { + scrollTop = nextScrollTop + timeout = null + }, 50) + } + + const calculateFirstVisibleRow = scrollTop => { + return Math.max(Math.floor(scrollTop / (rowHeight + 1)) - rowPreload, 0) + } + + const calculateLastVisibleRow = (firstRow, visibleRowCount, allRowCount) => { + return Math.min(firstRow + visibleRowCount + 2 * rowPreload, allRowCount) + } -
-
-
- - - - {#if $component.children} - - {/if} - {#each fields as field} - - {/each} - - - - {#each sortedRows as row} - +{#if loaded} +
+
+
+
-
-
sortBy(field)}> -
- {schema[field]?.name} - -
-
+ + {#if $component.children} - + {/if} {#each fields as field} - {/each} - {/each} - -
-
- - - -
-
+
+
-
- +
sortBy(field)}> +
+
{schema[field]?.name}
+
- +
+ + + {#each sortedRows as row, idx} + lastVisibleRow}> + {#if idx < firstVisibleRow || idx > lastVisibleRow} + + {:else} + {#if $component.children} + +
+ + + +
+ + {/if} + {#each fields as field} + +
+ +
+ + {/each} + {/if} + + {/each} + + +
- +{/if}