rename data design, ag grid mvp
This commit is contained in:
parent
ce5dca72b4
commit
1add16147d
|
@ -66,6 +66,7 @@
|
||||||
"@budibase/bbui": "^1.44.1",
|
"@budibase/bbui": "^1.44.1",
|
||||||
"@budibase/client": "^0.2.5",
|
"@budibase/client": "^0.2.5",
|
||||||
"@budibase/colorpicker": "^1.0.1",
|
"@budibase/colorpicker": "^1.0.1",
|
||||||
|
"@budibase/svelte-ag-grid": "^0.0.13",
|
||||||
"@fortawesome/fontawesome-free": "^5.14.0",
|
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||||
"@sentry/browser": "5.19.1",
|
"@sentry/browser": "5.19.1",
|
||||||
"@svelteschool/svelte-forms": "^0.7.0",
|
"@svelteschool/svelte-forms": "^0.7.0",
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
<script>
|
||||||
|
import { goto, params } from "@sveltech/routify"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { fade } from "svelte/transition"
|
||||||
|
import fsort from "fast-sort"
|
||||||
|
import getOr from "lodash/fp/getOr"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
import { Button, Icon } from "@budibase/bbui"
|
||||||
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
import AttachmentList from "./AttachmentList.svelte"
|
||||||
|
import TablePagination from "./TablePagination.svelte"
|
||||||
|
import CreateEditRowModal from "./modals/CreateEditRowModal.svelte"
|
||||||
|
import RowPopover from "./buttons/CreateRowButton.svelte"
|
||||||
|
import ColumnPopover from "./buttons/CreateColumnButton.svelte"
|
||||||
|
import ViewPopover from "./buttons/CreateViewButton.svelte"
|
||||||
|
import ColumnHeaderPopover from "./popovers/ColumnPopover.svelte"
|
||||||
|
import EditRowPopover from "./popovers/RowPopover.svelte"
|
||||||
|
import CalculationPopover from "./buttons/CalculateButton.svelte"
|
||||||
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
|
|
||||||
|
const ITEMS_PER_PAGE = 10
|
||||||
|
|
||||||
|
export let schema = []
|
||||||
|
export let data = []
|
||||||
|
export let title
|
||||||
|
export let allowEditing = false
|
||||||
|
export let loading = false
|
||||||
|
|
||||||
|
let currentPage = 0
|
||||||
|
|
||||||
|
$: columns = schema ? Object.keys(schema) : []
|
||||||
|
$: sort = $backendUiStore.sort
|
||||||
|
$: sorted = sort ? fsort(data)[sort.direction](sort.column) : data
|
||||||
|
$: paginatedData =
|
||||||
|
sorted && sorted.length
|
||||||
|
? sorted.slice(
|
||||||
|
currentPage * ITEMS_PER_PAGE,
|
||||||
|
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
||||||
|
)
|
||||||
|
: []
|
||||||
|
$: tableId = data?.length ? data[0].tableId : null
|
||||||
|
|
||||||
|
function selectRelationship(row, fieldName) {
|
||||||
|
if (!row?.[fieldName]?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$goto(
|
||||||
|
`/${$params.application}/backend/table/${tableId}/relationship/${row._id}/${fieldName}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="table-controls">
|
||||||
|
<h2 class="title">
|
||||||
|
<span>{title}</span>
|
||||||
|
{#if loading}
|
||||||
|
<div transition:fade>
|
||||||
|
<Spinner size="10" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</h2>
|
||||||
|
<div class="popovers">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="bb-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{#if allowEditing}
|
||||||
|
<th class="edit-header">
|
||||||
|
<div>Edit</div>
|
||||||
|
</th>
|
||||||
|
{/if}
|
||||||
|
{#each columns as header}
|
||||||
|
<th>
|
||||||
|
{#if allowEditing}
|
||||||
|
<ColumnHeaderPopover field={schema[header]} />
|
||||||
|
{:else}
|
||||||
|
<div class="header">{header}</div>
|
||||||
|
{/if}
|
||||||
|
</th>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#if paginatedData.length === 0}
|
||||||
|
{#if allowEditing}
|
||||||
|
<td class="no-border">No data.</td>
|
||||||
|
{/if}
|
||||||
|
{#each columns as header, idx}
|
||||||
|
<td class="no-border">
|
||||||
|
{#if idx === 0 && !allowEditing}No data.{/if}
|
||||||
|
</td>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{#each paginatedData as row}
|
||||||
|
<tr>
|
||||||
|
{#if allowEditing}
|
||||||
|
<td>
|
||||||
|
<EditRowPopover {row} />
|
||||||
|
</td>
|
||||||
|
{/if}
|
||||||
|
{#each columns as header}
|
||||||
|
<td>
|
||||||
|
{#if schema[header].type === 'link'}
|
||||||
|
<div
|
||||||
|
class:link={row[header] && row[header].length}
|
||||||
|
on:click={() => selectRelationship(row, header)}>
|
||||||
|
{row[header] ? row[header].length : 0}
|
||||||
|
related row(s)
|
||||||
|
</div>
|
||||||
|
{:else if schema[header].type === 'attachment'}
|
||||||
|
<AttachmentList files={row[header] || []} />
|
||||||
|
{:else}{getOr('', header, row)}{/if}
|
||||||
|
</td>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<TablePagination
|
||||||
|
{data}
|
||||||
|
bind:currentPage
|
||||||
|
pageItemCount={paginatedData.length}
|
||||||
|
{ITEMS_PER_PAGE} />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
margin-top: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.title > span {
|
||||||
|
margin-right: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: 1px solid var(--grey-4);
|
||||||
|
background: #fff;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
background: var(--grey-3);
|
||||||
|
border: 1px solid var(--grey-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th {
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
transition: 0.5s all;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 48px;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th:hover {
|
||||||
|
color: var(--blue);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
max-width: 200px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--grey-4);
|
||||||
|
white-space: nowrap;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: var(--spacing-l) var(--spacing-m);
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
td.no-border {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr {
|
||||||
|
border-bottom: 1px solid var(--grey-4);
|
||||||
|
transition: 0.3s background-color;
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:hover {
|
||||||
|
background: var(--grey-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-controls {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovers {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.popovers > div) {
|
||||||
|
margin-right: var(--spacing-m);
|
||||||
|
margin-bottom: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-header {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-header:hover {
|
||||||
|
cursor: default;
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link:hover {
|
||||||
|
color: var(--grey-6);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,8 +8,6 @@
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
import { Button, Icon } from "@budibase/bbui"
|
import { Button, Icon } from "@budibase/bbui"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
import AttachmentList from "./AttachmentList.svelte"
|
|
||||||
import TablePagination from "./TablePagination.svelte"
|
|
||||||
import CreateEditRowModal from "./modals/CreateEditRowModal.svelte"
|
import CreateEditRowModal from "./modals/CreateEditRowModal.svelte"
|
||||||
import RowPopover from "./buttons/CreateRowButton.svelte"
|
import RowPopover from "./buttons/CreateRowButton.svelte"
|
||||||
import ColumnPopover from "./buttons/CreateColumnButton.svelte"
|
import ColumnPopover from "./buttons/CreateColumnButton.svelte"
|
||||||
|
@ -19,7 +17,13 @@
|
||||||
import CalculationPopover from "./buttons/CalculateButton.svelte"
|
import CalculationPopover from "./buttons/CalculateButton.svelte"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 10
|
// New
|
||||||
|
import AgGrid from "@budibase/svelte-ag-grid"
|
||||||
|
import { getRenderer, editRowRenderer } from "./cells/cellRenderers";
|
||||||
|
import TableHeader from "./TableHeader"
|
||||||
|
|
||||||
|
// const ITEMS_PER_PAGE = 10
|
||||||
|
|
||||||
|
|
||||||
export let schema = []
|
export let schema = []
|
||||||
export let data = []
|
export let data = []
|
||||||
|
@ -27,18 +31,61 @@
|
||||||
export let allowEditing = false
|
export let allowEditing = false
|
||||||
export let loading = false
|
export let loading = false
|
||||||
|
|
||||||
let currentPage = 0
|
// New stuff
|
||||||
|
export let theme = "alpine"
|
||||||
|
|
||||||
$: columns = schema ? Object.keys(schema) : []
|
let columnDefs = []
|
||||||
$: sort = $backendUiStore.sort
|
|
||||||
$: sorted = sort ? fsort(data)[sort.direction](sort.column) : data
|
let options = {
|
||||||
$: paginatedData =
|
defaultColDef: {
|
||||||
sorted && sorted.length
|
flex: 1,
|
||||||
? sorted.slice(
|
minWidth: 150,
|
||||||
currentPage * ITEMS_PER_PAGE,
|
filter: true,
|
||||||
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
},
|
||||||
)
|
rowSelection: "multiple",
|
||||||
: []
|
suppressRowClickSelection: false,
|
||||||
|
paginationAutoPageSize: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// let currentPage = 0
|
||||||
|
// $: columns = schema ? Object.keys(schema) : []
|
||||||
|
// $: sort = $backendUiStore.sort
|
||||||
|
// $: sorted = sort ? fsort(data)[sort.direction](sort.column) : data
|
||||||
|
// $: paginatedData =
|
||||||
|
// sorted && sorted.length
|
||||||
|
// ? sorted.slice(
|
||||||
|
// currentPage * ITEMS_PER_PAGE,
|
||||||
|
// currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
||||||
|
// )
|
||||||
|
// : []
|
||||||
|
// TODO: refactor
|
||||||
|
$: {
|
||||||
|
let result = []
|
||||||
|
if (allowEditing) {
|
||||||
|
result.push({
|
||||||
|
headerName: "Edit",
|
||||||
|
sortable: false,
|
||||||
|
resizable: false,
|
||||||
|
suppressMovable: true,
|
||||||
|
width: 10,
|
||||||
|
cellRenderer: editRowRenderer
|
||||||
|
})
|
||||||
|
}
|
||||||
|
columnDefs = [...result, ...Object.keys(schema).map(key => ({
|
||||||
|
// headerCheckboxSelection: i === 0 && canEdit,
|
||||||
|
// checkboxSelection: i === 0 && canEdit,
|
||||||
|
// valueSetter: setters.get(schema[key].type),
|
||||||
|
headerComponent: TableHeader,
|
||||||
|
headerName: key,
|
||||||
|
field: key,
|
||||||
|
// hide: shouldHideField(key),
|
||||||
|
sortable: true,
|
||||||
|
// editable: canEdit && schema[key].type !== "link",
|
||||||
|
cellRenderer: getRenderer(schema[key], true),
|
||||||
|
autoHeight: true,
|
||||||
|
resizable: true,
|
||||||
|
}))]
|
||||||
|
}
|
||||||
$: tableId = data?.length ? data[0].tableId : null
|
$: tableId = data?.length ? data[0].tableId : null
|
||||||
|
|
||||||
function selectRelationship(row, fieldName) {
|
function selectRelationship(row, fieldName) {
|
||||||
|
@ -46,9 +93,24 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
$goto(
|
$goto(
|
||||||
`/${$params.application}/backend/table/${tableId}/relationship/${row._id}/${fieldName}`
|
`/${$params.application}/data/table/${tableId}/relationship/${row._id}/${fieldName}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New stuff
|
||||||
|
const deleteRows = async () => {
|
||||||
|
const response = await api.post(`/api/${tableId}/rows`, {
|
||||||
|
rows: selectedRows,
|
||||||
|
type: "delete",
|
||||||
|
})
|
||||||
|
data = data.filter(row => !selectedRows.includes(row))
|
||||||
|
selectedRows = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpdate = ({ detail }) => {
|
||||||
|
data[detail.row] = detail.data
|
||||||
|
updateRow(detail.data)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
@ -65,7 +127,14 @@
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="bb-table">
|
<AgGrid
|
||||||
|
{theme}
|
||||||
|
{options}
|
||||||
|
{data}
|
||||||
|
{columnDefs}
|
||||||
|
on:update={handleUpdate}
|
||||||
|
on:select={({ detail }) => (console.log(detail))} />
|
||||||
|
<!-- <table class="bb-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{#if allowEditing}
|
{#if allowEditing}
|
||||||
|
@ -119,12 +188,12 @@
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table> -->
|
||||||
<TablePagination
|
<!-- <TablePagination
|
||||||
{data}
|
{data}
|
||||||
bind:currentPage
|
bind:currentPage
|
||||||
pageItemCount={paginatedData.length}
|
pageItemCount={paginatedData.length}
|
||||||
{ITEMS_PER_PAGE} />
|
{ITEMS_PER_PAGE} /> -->
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -142,64 +211,6 @@
|
||||||
margin-right: var(--spacing-xs);
|
margin-right: var(--spacing-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
|
||||||
border: 1px solid var(--grey-4);
|
|
||||||
background: #fff;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead {
|
|
||||||
background: var(--grey-3);
|
|
||||||
border: 1px solid var(--grey-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
thead th {
|
|
||||||
color: var(--ink);
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
transition: 0.5s all;
|
|
||||||
vertical-align: middle;
|
|
||||||
height: 48px;
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead th:hover {
|
|
||||||
color: var(--blue);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
max-width: 200px;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid var(--grey-4);
|
|
||||||
white-space: nowrap;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: var(--spacing-l) var(--spacing-m);
|
|
||||||
font-size: var(--font-size-xs);
|
|
||||||
}
|
|
||||||
|
|
||||||
td.no-border {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody tr {
|
|
||||||
border-bottom: 1px solid var(--grey-4);
|
|
||||||
transition: 0.3s background-color;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody tr:hover {
|
|
||||||
background: var(--grey-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-controls {
|
.table-controls {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -212,22 +223,4 @@
|
||||||
margin-right: var(--spacing-m);
|
margin-right: var(--spacing-m);
|
||||||
margin-bottom: var(--spacing-xl);
|
margin-bottom: var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-header {
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-header:hover {
|
|
||||||
cursor: default;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link:hover {
|
|
||||||
color: var(--grey-6);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<script>
|
||||||
|
export let params
|
||||||
|
console.log("in svelte", params)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>Fackle</h1>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
color: rebeccapurple;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,67 @@
|
||||||
|
// // the column the header is for
|
||||||
|
// column: Column;
|
||||||
|
|
||||||
|
// // the name to display for the column. if the column is using a headerValueGetter,
|
||||||
|
// // the displayName will take this into account.
|
||||||
|
// displayName: string;
|
||||||
|
|
||||||
|
// // whether sorting is enabled for the column. only put sort logic into
|
||||||
|
// // your header if this is true.
|
||||||
|
// enableSorting: boolean;
|
||||||
|
|
||||||
|
// // whether menu is enabled for the column. only display a menu button
|
||||||
|
// // in your header if this is true.
|
||||||
|
// enableMenu: boolean;
|
||||||
|
|
||||||
|
// // callback to progress the sort for this column.
|
||||||
|
// // the grid will decide the next sort direction eg ascending, descending or 'no sort'.
|
||||||
|
// // pass multiSort=true if you want to do a multi sort (eg user has shift held down when
|
||||||
|
// // they click)
|
||||||
|
// progressSort(multiSort: boolean): void;
|
||||||
|
|
||||||
|
// // callback to set the sort for this column.
|
||||||
|
// // pass the sort direction to use ignoring the current sort eg one of 'asc', 'desc' or null
|
||||||
|
// // (for no sort). pass multiSort=true if you want to do a multi sort (eg user has shift held
|
||||||
|
// // down when they click)
|
||||||
|
// setSort(sort: string, multiSort?: boolean): void;
|
||||||
|
|
||||||
|
// // callback to request the grid to show the column menu.
|
||||||
|
// // pass in the html element of the column menu to have the
|
||||||
|
// // grid position the menu over the button.
|
||||||
|
// showColumnMenu(menuButton: HTMLElement): void;
|
||||||
|
|
||||||
|
// // The grid API
|
||||||
|
// api: any;
|
||||||
|
import TableHeader from "./TableHeader.svelte"
|
||||||
|
|
||||||
|
export default class TableHeaderWrapper {
|
||||||
|
constructor() {
|
||||||
|
// foo
|
||||||
|
}
|
||||||
|
|
||||||
|
init(params) {
|
||||||
|
console.log("init", params)
|
||||||
|
this.agParams = params
|
||||||
|
const container = document.createElement("div")
|
||||||
|
new TableHeader({
|
||||||
|
target: container,
|
||||||
|
props: params,
|
||||||
|
})
|
||||||
|
this.eGui = container
|
||||||
|
}
|
||||||
|
|
||||||
|
// can get called more than once, you should return the HTML element
|
||||||
|
getGui() {
|
||||||
|
return this.eGui
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets called when a new Column Definition has been set for this header
|
||||||
|
refresh(params) {
|
||||||
|
console.log("Refreshing", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional method, gets called once, when component is destroyed
|
||||||
|
destroy() {
|
||||||
|
console.log("Destroy")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
import { getTable } from "./tableCache"
|
||||||
|
|
||||||
|
export let columnName
|
||||||
|
export let row
|
||||||
|
|
||||||
|
$: count =
|
||||||
|
row && columnName && Array.isArray(row[columnName])
|
||||||
|
? row[columnName].length
|
||||||
|
: 0
|
||||||
|
let linkedRows = []
|
||||||
|
let displayColumn
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
linkedRows = await fetchLinkedRowsData(row, columnName)
|
||||||
|
if (linkedRows && linkedRows.length) {
|
||||||
|
const table = await getTable(linkedRows[0].tableId)
|
||||||
|
if (table && table.primaryDisplay) {
|
||||||
|
displayColumn = table.primaryDisplay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
async function fetchLinkedRowsData(row, columnName) {
|
||||||
|
if (!row || !row._id) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const QUERY_URL = `/api/${row.tableId}/${row._id}/enrich`
|
||||||
|
const response = await api.get(QUERY_URL)
|
||||||
|
const enrichedRow = await response.json()
|
||||||
|
return enrichedRow[columnName]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{#if linkedRows && linkedRows.length && displayColumn}
|
||||||
|
{#each linkedRows as linkedRow}
|
||||||
|
{#if linkedRow[displayColumn] != null && linkedRow[displayColumn] !== ''}
|
||||||
|
<div class="linked-row">{linkedRow[displayColumn]}</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{:else}{count} related row(s){/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This styling is opinionated to ensure these always look consistent */
|
||||||
|
.linked-row {
|
||||||
|
color: white;
|
||||||
|
background-color: #616161;
|
||||||
|
border-radius: var(--border-radius-xs);
|
||||||
|
padding: var(--spacing-xs) var(--spacing-s) calc(var(--spacing-xs) + 1px)
|
||||||
|
var(--spacing-s);
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,129 @@
|
||||||
|
import AttachmentList from "./AttachmentCell.svelte"
|
||||||
|
import EditRowPopover from "../popovers/RowPopover.svelte"
|
||||||
|
import RelationshipDisplay from "./RelationshipCell.svelte"
|
||||||
|
// import BooleanCell from "./BooleanCell.svelte"
|
||||||
|
|
||||||
|
const renderers = {
|
||||||
|
attachment: attachmentRenderer,
|
||||||
|
link: linkedRowRenderer,
|
||||||
|
boolean: booleanRenderer,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRenderer(schema, editable) {
|
||||||
|
if (renderers[schema.type]) {
|
||||||
|
return renderers[schema.type](schema.options, schema.constraints, editable)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editRowRenderer(params) {
|
||||||
|
const container = document.createElement("div")
|
||||||
|
|
||||||
|
new EditRowPopover({
|
||||||
|
target: container,
|
||||||
|
props: {
|
||||||
|
row: params.data,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
function booleanRenderer(options, constraints) {
|
||||||
|
return params => {
|
||||||
|
let container = document.createElement("input")
|
||||||
|
|
||||||
|
// TODO: implement
|
||||||
|
|
||||||
|
return container
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
return params => {
|
||||||
|
const container = document.createElement("div")
|
||||||
|
|
||||||
|
const attachmentInstance = new AttachmentList({
|
||||||
|
target: container,
|
||||||
|
props: {
|
||||||
|
files: params.value || [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// 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,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
|
// return container
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
function optionsRenderer(options, constraints, editable) {
|
||||||
|
return params => {
|
||||||
|
const container = document.createElement("div")
|
||||||
|
// TODO: show a pill
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
function linkedRowRenderer(options, constraints, editable) {
|
||||||
|
return params => {
|
||||||
|
let container = document.createElement("div")
|
||||||
|
container.style.display = "grid"
|
||||||
|
container.style.placeItems = "center"
|
||||||
|
container.style.height = "100%"
|
||||||
|
|
||||||
|
new RelationshipDisplay({
|
||||||
|
target: container,
|
||||||
|
props: {
|
||||||
|
row: params.data,
|
||||||
|
columnName: params.column.colId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
let cache = {}
|
||||||
|
|
||||||
|
async function fetchTable(id) {
|
||||||
|
const FETCH_TABLE_URL = `/api/tables/${id}`
|
||||||
|
const response = await api.get(FETCH_TABLE_URL)
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTable(tableId) {
|
||||||
|
if (!tableId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (!cache[tableId]) {
|
||||||
|
cache[tableId] = fetchTable(tableId)
|
||||||
|
cache[tableId] = await cache[tableId]
|
||||||
|
}
|
||||||
|
return await cache[tableId]
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
$goto("../backend")
|
$goto("../data")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- routify:options index=false -->
|
<!-- routify:options index=false -->
|
||||||
|
|
|
@ -718,10 +718,10 @@
|
||||||
svelte-flatpickr "^2.4.0"
|
svelte-flatpickr "^2.4.0"
|
||||||
svelte-portal "^1.0.0"
|
svelte-portal "^1.0.0"
|
||||||
|
|
||||||
"@budibase/client@^0.2.4":
|
"@budibase/client@^0.2.5":
|
||||||
version "0.2.4"
|
version "0.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.2.4.tgz#da958faa50c59f6a9c41c692b7a19d6a6ea98bc1"
|
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.2.5.tgz#d4f451384e88277dad16069c1d4742d5010ac1c3"
|
||||||
integrity sha512-MsFbWcsh3t1lyLgTb4UMccjshy6jd3A77lqs1CpXjHr+2LmXwvIriLgruycAvFrtqZzYG+dGe0rWwX0auwaaZw==
|
integrity sha512-EFfy3g44fiHnzm/kqHskeXsbVXWHQbtKe4fPP0q+wwDkp1eP2ri9oJ3kMJg3A1SZPHFGmgeRvSMoLSux+7QhCw==
|
||||||
dependencies:
|
dependencies:
|
||||||
deep-equal "^2.0.1"
|
deep-equal "^2.0.1"
|
||||||
mustache "^4.0.1"
|
mustache "^4.0.1"
|
||||||
|
@ -731,6 +731,13 @@
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/colorpicker/-/colorpicker-1.0.1.tgz#940c180e7ebba0cb0756c4c8ef13f5dfab58e810"
|
resolved "https://registry.yarnpkg.com/@budibase/colorpicker/-/colorpicker-1.0.1.tgz#940c180e7ebba0cb0756c4c8ef13f5dfab58e810"
|
||||||
|
|
||||||
|
"@budibase/svelte-ag-grid@^0.0.13":
|
||||||
|
version "0.0.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@budibase/svelte-ag-grid/-/svelte-ag-grid-0.0.13.tgz#cbb49e2c8770dd9de51bf222423d0dede3f39207"
|
||||||
|
integrity sha512-pLIUsbQ57gFQThu7/MwuPXPTI1AnDrEzw2IHeHvli4VKq7DYcXbkAFs6h8pDPvbFOC6LaiVjRCnsEpEQI1x7og==
|
||||||
|
dependencies:
|
||||||
|
ag-grid-community "^24.0.0"
|
||||||
|
|
||||||
"@cnakazawa/watch@^1.0.3":
|
"@cnakazawa/watch@^1.0.3":
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
|
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
|
||||||
|
@ -1306,6 +1313,11 @@ acorn@^7.1.1:
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
|
||||||
|
|
||||||
|
ag-grid-community@^24.0.0:
|
||||||
|
version "24.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-24.1.0.tgz#1e3cab51211822e08d56f03a491b7c0deaa398e6"
|
||||||
|
integrity sha512-pWnWphuDcejZ8ahf6C734EpCx3XQ6dHEZWMWTlCdHNT0mZBLJ4YKCGACX+ttAEtSX2MGM3G13JncvuratUlYag==
|
||||||
|
|
||||||
ajv@^6.5.5:
|
ajv@^6.5.5:
|
||||||
version "6.12.2"
|
version "6.12.2"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
|
||||||
|
|
Loading…
Reference in New Issue