-
-
Row height
-
- {#each rowSizeOptions as option}
-
changeRowHeight(option.size)}
- >
- {option.label}
-
- {/each}
-
-
-
-
Column width
-
- {#each columnSizeOptions as option}
-
columns.actions.changeAllColumnWidths(option.size)}
- selected={option.selected}
- >
- {option.label}
-
- {/each}
- {#if custom}
-
Custom
- {/if}
-
+
+
+
+ Size
+
+
+
+
Row height
+
+ {#each rowSizeOptions as option}
+
changeRowHeight(option.size)}
+ >
+ {option.label}
+
+ {/each}
-
+
+
Column width
+
+ {#each columnSizeOptions as option}
+
columns.actions.changeAllColumnWidths(option.size)}
+ selected={option.selected}
+ >
+ {option.label}
+
+ {/each}
+ {#if custom}
+
Custom
+ {/if}
+
+
+
+ {/if}
+
diff --git a/packages/builder/src/components/backend/DataTable/buttons/grid/GridViewCalculationButton.svelte b/packages/builder/src/components/backend/DataTable/buttons/grid/GridViewCalculationButton.svelte
index 87c77a1457..f6ef6e6099 100644
--- a/packages/builder/src/components/backend/DataTable/buttons/grid/GridViewCalculationButton.svelte
+++ b/packages/builder/src/components/backend/DataTable/buttons/grid/GridViewCalculationButton.svelte
@@ -1,15 +1,15 @@
-
- Configure calculations{count ? `: ${count}` : ""}
-
+
+
+
+ Configure calculations{count ? `: ${count}` : ""}
+
+
-
-
- {#if calculations.length}
-
- {#each calculations as calc, idx}
-
{idx === 0 ? "Calculate" : "and"} the
-
-
of
-
-
deleteCalc(idx)}
- color="var(--spectrum-global-color-gray-700)"
- />
- {/each}
- Group by
-
-
-
+ {#if calculations.length}
+
+ {#each calculations as calc, idx}
+
{idx === 0 ? "Calculate" : "and"} the
+
+
of
+
+
deleteCalc(idx)}
+ color="var(--spectrum-global-color-gray-700)"
+ />
+ {/each}
+ Group by
+
+
- {/if}
-
-
+
-
-
+ icon="Add"
+ on:click={addCalc}
+ disabled={calculations.length >= 5}
+ >
+ Add calculation
+
+
+
+
+
+ Save
+
+
diff --git a/packages/builder/src/components/backend/DataTable/modals/ExportModal.test.js b/packages/builder/src/components/backend/DataTable/modals/ExportModal.test.js
deleted file mode 100644
index 4927f51a8d..0000000000
--- a/packages/builder/src/components/backend/DataTable/modals/ExportModal.test.js
+++ /dev/null
@@ -1,243 +0,0 @@
-import { it, expect, describe, vi } from "vitest"
-import { render, screen } from "@testing-library/svelte"
-import "@testing-library/jest-dom"
-
-import ExportModal from "./ExportModal.svelte"
-import { utils } from "@budibase/shared-core"
-
-const labelLookup = utils.filterValueToLabel()
-
-const rowText = filter => {
- let readableField = filter.field.split(":")[1]
- let rowLabel = labelLookup[filter.operator]
- let value = Array.isArray(filter.value)
- ? JSON.stringify(filter.value)
- : filter.value
- return `${readableField}${rowLabel}${value}`.trim()
-}
-
-const defaultFilters = [
- {
- onEmptyFilter: "all",
- },
-]
-
-vi.mock("svelte", async () => {
- return {
- getContext: () => {
- return {
- hide: vi.fn(),
- cancel: vi.fn(),
- }
- },
- createEventDispatcher: vi.fn(),
- onDestroy: vi.fn(),
- tick: vi.fn(),
- }
-})
-
-vi.mock("api", async () => {
- return {
- API: {
- exportView: vi.fn(),
- exportRows: vi.fn(),
- },
- }
-})
-
-describe("Export Modal", () => {
- it("show default messaging with no export config specified", () => {
- render(ExportModal, {
- props: {},
- })
-
- expect(screen.getByTestId("export-all-rows")).toBeVisible()
- expect(screen.getByTestId("export-all-rows")).toHaveTextContent(
- "Exporting all rows"
- )
-
- expect(screen.queryByTestId("export-config-table")).toBe(null)
- })
-
- it("indicate that a filter is being applied to the export", () => {
- const propsCfg = {
- filters: [
- {
- id: "MOQkMx9p9",
- field: "1:Cost",
- operator: "rangeHigh",
- value: "100",
- valueType: "Value",
- type: "number",
- noValue: false,
- },
- ...defaultFilters,
- ],
- }
-
- render(ExportModal, {
- props: propsCfg,
- })
-
- expect(propsCfg.filters[0].field).toBe("1:Cost")
-
- expect(screen.getByTestId("filters-applied")).toBeVisible()
- expect(screen.getByTestId("filters-applied").textContent).toBe(
- "Filters applied"
- )
-
- const ele = screen.queryByTestId("export-config-table")
- expect(ele).toBeVisible()
-
- const rows = ele.getElementsByClassName("spectrum-Table-row")
-
- expect(rows.length).toBe(1)
- let rowTextContent = rowText(propsCfg.filters[0])
-
- //"CostLess than or equal to100"
- expect(rows[0].textContent?.trim()).toEqual(rowTextContent)
- })
-
- it("Show only selected row messaging if rows are supplied", () => {
- const propsCfg = {
- filters: [
- {
- id: "MOQkMx9p9",
- field: "1:Cost",
- operator: "rangeHigh",
- value: "100",
- valueType: "Value",
- type: "number",
- noValue: false,
- },
- ...defaultFilters,
- ],
- sorting: {
- sortColumn: "Cost",
- sortOrder: "descending",
- },
- selectedRows: [
- {
- _id: "ro_ta_bb_expenses_57d5f6fe1b6640d8bb22b15f5eae62cd",
- },
- {
- _id: "ro_ta_bb_expenses_99ce5760a53a430bab4349cd70335a07",
- },
- ],
- }
-
- render(ExportModal, {
- props: propsCfg,
- })
-
- expect(screen.queryByTestId("export-config-table")).toBeNull()
- expect(screen.queryByTestId("filters-applied")).toBeNull()
-
- expect(screen.queryByTestId("exporting-n-rows")).toBeVisible()
- expect(screen.queryByTestId("exporting-n-rows").textContent).toEqual(
- "2 rows will be exported"
- )
- })
-
- it("Show only the configured sort when no filters are specified", () => {
- const propsCfg = {
- filters: [...defaultFilters],
- sorting: {
- sortColumn: "Cost",
- sortOrder: "descending",
- },
- }
- render(ExportModal, {
- props: propsCfg,
- })
-
- expect(screen.queryByTestId("export-config-table")).toBeVisible()
- const ele = screen.queryByTestId("export-config-table")
- const rows = ele.getElementsByClassName("spectrum-Table-row")
-
- expect(rows.length).toBe(1)
- expect(rows[0].textContent?.trim()).toEqual(
- `${propsCfg.sorting.sortColumn}Order By${propsCfg.sorting.sortOrder}`
- )
- })
-
- it("Display all currently configured filters and applied sort", () => {
- const propsCfg = {
- filters: [
- {
- id: "MOQkMx9p9",
- field: "1:Cost",
- operator: "rangeHigh",
- value: "100",
- valueType: "Value",
- type: "number",
- noValue: false,
- },
- {
- id: "2ot-aB0gE",
- field: "2:Expense Tags",
- operator: "contains",
- value: ["Equipment", "Services"],
- valueType: "Value",
- type: "array",
- noValue: false,
- },
- ...defaultFilters,
- ],
- sorting: {
- sortColumn: "Payment Due",
- sortOrder: "ascending",
- },
- }
-
- render(ExportModal, {
- props: propsCfg,
- })
-
- const ele = screen.queryByTestId("export-config-table")
- expect(ele).toBeVisible()
-
- const rows = ele.getElementsByClassName("spectrum-Table-row")
- expect(rows.length).toBe(3)
-
- let rowTextContent1 = rowText(propsCfg.filters[0])
- expect(rows[0].textContent?.trim()).toEqual(rowTextContent1)
-
- let rowTextContent2 = rowText(propsCfg.filters[1])
- expect(rows[1].textContent?.trim()).toEqual(rowTextContent2)
-
- expect(rows[2].textContent?.trim()).toEqual(
- `${propsCfg.sorting.sortColumn}Order By${propsCfg.sorting.sortOrder}`
- )
- })
-
- it("show only the valid, configured download formats", () => {
- const propsCfg = {
- formats: ["badger", "json"],
- }
-
- render(ExportModal, {
- props: propsCfg,
- })
-
- let ele = screen.getByTestId("format-select")
- expect(ele).toBeVisible()
-
- let formatDisplay = ele.getElementsByTagName("button")[0]
-
- expect(formatDisplay.textContent.trim()).toBe("JSON")
- })
-
- it("Load the default format config when no explicit formats are configured", () => {
- render(ExportModal, {
- props: {},
- })
-
- let ele = screen.getByTestId("format-select")
- expect(ele).toBeVisible()
-
- let formatDisplay = ele.getElementsByTagName("button")[0]
-
- expect(formatDisplay.textContent.trim()).toBe("CSV")
- })
-})
diff --git a/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte b/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte
deleted file mode 100644
index 1696c6ba03..0000000000
--- a/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
- Import rows to an existing table from a CSV or JSON file. Only columns from
- the file which exist in the table will be imported.
-
-
- CSV or JSON file to import
-
-
-
diff --git a/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte b/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte
index f1d85a6a30..ce966d0daa 100644
--- a/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte
@@ -4,7 +4,7 @@
BBReferenceFieldSubType,
SourceName,
} from "@budibase/types"
- import { Select, Toggle, Multiselect } from "@budibase/bbui"
+ import { Select, Toggle, Multiselect, Label, Layout } from "@budibase/bbui"
import { DB_TYPE_INTERNAL } from "constants/backend"
import { API } from "api"
import { parseFile } from "./utils"
@@ -140,84 +140,91 @@
}
-
-
- 0}>
- {#if loading}
- loading...
- {:else if error}
- error: {error}
- {:else if fileName}
- {fileName}
- {:else}
- Upload
- {/if}
-
-
-{#if fileName && Object.keys(validation).length === 0}
- No valid fields, try another file
-{:else if rows.length > 0 && !error}
-
- {#each Object.keys(validation) as name}
-
- {name}
- option.label}
- getOptionValue={option => option.value}
- disabled
- />
-
- {validation[name] ? "Success" : "Failure"}
-
-
- {/each}
-
-
-
- {#if datasource?.source !== SourceName.SQL_SERVER}
- (identifierFields = [])}
- thin
- text="Update existing rows"
- />
- {/if}
- {#if updateExistingRows}
- {#if tableType === DB_TYPE_INTERNAL}
-
+
+ CSV or JSON file to import
+
+
- {:else}
-
Rows will be updated based on the table's primary key.
+
0}>
+ {#if loading}
+ loading...
+ {:else if error}
+ error: {error}
+ {:else if fileName}
+ {fileName}
+ {:else}
+ Upload
+ {/if}
+
+
+
+
+ {#if fileName && Object.keys(validation).length === 0}
+ No valid fields - please try another file.
+ {:else if fileName && rows.length > 0 && !error}
+
+ {#each Object.keys(validation) as name}
+
+ {name}
+ option.label}
+ getOptionValue={option => option.value}
+ disabled
+ />
+
+ {validation[name] ? "Success" : "Failure"}
+
+
+ {/each}
+
+
+ {#if datasource?.source !== SourceName.SQL_SERVER}
+ (identifierFields = [])}
+ thin
+ text="Update existing rows"
+ />
+ {/if}
+ {#if updateExistingRows}
+ {#if tableType === DB_TYPE_INTERNAL}
+
+ {:else}
+ Rows will be updated based on the table's primary key.
+ {/if}
+ {/if}
+ {#if invalidColumns.length > 0}
+
+
+ The following columns are present in the data you wish to import, but
+ do not match the schema of this table and will be ignored:
+
+
+ {#each invalidColumns as column}
+ - {column}
+ {/each}
+
+
{/if}
{/if}
- {#if invalidColumns.length > 0}
-
- The following columns are present in the data you wish to import, but do
- not match the schema of this table and will be ignored.
-
-
- {#each invalidColumns as column}
- {column}
- {/each}
-
- {/if}
-{/if}
+
diff --git a/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte b/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte
index 5804dc3172..1694ec8b0e 100644
--- a/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/TableDataImport.svelte
@@ -1,5 +1,5 @@
-
-
- 0}>
- {#if error}
- Error: {error}
- {:else if fileName}
- {fileName}
- {:else}
- Upload
- {/if}
-
-
-{#if rawRows.length > 0 && !error}
-
- {#each Object.entries(schema) as [name, column]}
-
-
{column.name}
-
handleChange(name, e)}
- options={Object.values(typeOptions)}
- placeholder={null}
- getOptionLabel={option => option.label}
- getOptionValue={option => option.value}
- />
-
- {#if validation[column.name]}
- Success
- {:else}
- Failure
- {#if errors[column.name]}
-
+
+
+
+ Create a Table from a CSV or JSON file (Optional)
+
+
+
+ 0}>
+ {#if error}
+ Error: {error}
+ {:else if fileName}
+ {fileName}
+ {:else}
+ Upload
+ {/if}
+
+
+
+
+ {#if rawRows.length > 0 && !error}
+
+ {#each Object.entries(schema) as [name, column]}
+
+ {column.name}
+ handleChange(name, e)}
+ options={Object.values(typeOptions)}
+ placeholder={null}
+ getOptionLabel={option => option.label}
+ getOptionValue={option => option.value}
+ />
+
+ {#if validation[column.name]}
+ Success
+ {:else}
+ Failure
+ {#if errors[column.name]}
+
+ {/if}
{/if}
- {/if}
-
- deleteColumn(column.name)}
- />
-
- {/each}
-
-
+
+ deleteColumn(column.name)}
+ />
+
+ {/each}
+
-
-{/if}
+ {/if}
+
diff --git a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte
index 8a5484e2b2..5596ade573 100644
--- a/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/modals/CreateTableModal.svelte
@@ -1,13 +1,7 @@