1
0
Fork 0
mirror of synced 2024-09-12 23:43:09 +12:00

Merge branch 'master' into feat/budi-8123-single-user

This commit is contained in:
Adria Navarro 2024-05-13 13:33:03 +02:00 committed by GitHub
commit a36c46ea90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 85 additions and 43 deletions

View file

@ -12,6 +12,7 @@
OptionSelectDnD, OptionSelectDnD,
Layout, Layout,
AbsTooltip, AbsTooltip,
ProgressCircle,
} from "@budibase/bbui" } from "@budibase/bbui"
import { import {
SWITCHABLE_TYPES, SWITCHABLE_TYPES,
@ -251,11 +252,11 @@
} }
async function saveColumn() { async function saveColumn() {
savingColumn = true
if (errors?.length) { if (errors?.length) {
return return
} }
savingColumn = true
let saveColumn = cloneDeep(editableColumn) let saveColumn = cloneDeep(editableColumn)
delete saveColumn.fieldId delete saveColumn.fieldId
@ -288,6 +289,8 @@
} }
} catch (err) { } catch (err) {
notifications.error(`Error saving column: ${err.message}`) notifications.error(`Error saving column: ${err.message}`)
} finally {
savingColumn = false
} }
} }
@ -734,7 +737,20 @@
<Button quiet warning text on:click={confirmDelete}>Delete</Button> <Button quiet warning text on:click={confirmDelete}>Delete</Button>
{/if} {/if}
<Button secondary newStyles on:click={cancelEdit}>Cancel</Button> <Button secondary newStyles on:click={cancelEdit}>Cancel</Button>
<Button disabled={invalid} newStyles cta on:click={saveColumn}>Save</Button> <Button
disabled={invalid || savingColumn}
newStyles
cta
on:click={saveColumn}
>
{#if savingColumn}
<div class="save-loading">
<ProgressCircle overBackground={true} size="S" />
</div>
{:else}
Save
{/if}
</Button>
</div> </div>
<Modal bind:this={jsonSchemaModal}> <Modal bind:this={jsonSchemaModal}>
<JSONSchemaModal <JSONSchemaModal
@ -799,4 +815,9 @@
cursor: pointer; cursor: pointer;
color: var(--spectrum-global-color-gray-900); color: var(--spectrum-global-color-gray-900);
} }
.save-loading {
display: flex;
justify-content: center;
}
</style> </style>

View file

@ -1,6 +1,7 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import DataCell from "../cells/DataCell.svelte" import DataCell from "../cells/DataCell.svelte"
import { getCellID } from "../lib/utils"
export let row export let row
export let top = false export let top = false
@ -38,7 +39,7 @@
on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))} on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))}
> >
{#each $visibleColumns as column, columnIdx} {#each $visibleColumns as column, columnIdx}
{@const cellId = `${row._id}-${column.name}`} {@const cellId = getCellID(row._id, column.name)}
<DataCell <DataCell
{cellId} {cellId}
{column} {column}

View file

@ -7,6 +7,7 @@
import { GutterWidth, NewRowID } from "../lib/constants" import { GutterWidth, NewRowID } from "../lib/constants"
import GutterCell from "../cells/GutterCell.svelte" import GutterCell from "../cells/GutterCell.svelte"
import KeyboardShortcut from "./KeyboardShortcut.svelte" import KeyboardShortcut from "./KeyboardShortcut.svelte"
import { getCellID } from "../lib/utils"
const { const {
hoveredRowId, hoveredRowId,
@ -70,7 +71,7 @@
// Select the first cell if possible // Select the first cell if possible
if (firstColumn) { if (firstColumn) {
$focusedCellId = `${savedRow._id}-${firstColumn.name}` $focusedCellId = getCellID(savedRow._id, firstColumn.name)
} }
} }
isAdding = false isAdding = false
@ -118,7 +119,7 @@
visible = true visible = true
$hoveredRowId = NewRowID $hoveredRowId = NewRowID
if (firstColumn) { if (firstColumn) {
$focusedCellId = `${NewRowID}-${firstColumn.name}` $focusedCellId = getCellID(NewRowID, firstColumn.name)
} }
// Attach key listener // Attach key listener
@ -194,7 +195,7 @@
{/if} {/if}
</GutterCell> </GutterCell>
{#if $stickyColumn} {#if $stickyColumn}
{@const cellId = `${NewRowID}-${$stickyColumn.name}`} {@const cellId = getCellID(NewRowID, $stickyColumn.name)}
<DataCell <DataCell
{cellId} {cellId}
rowFocused rowFocused

View file

@ -8,6 +8,7 @@
import { GutterWidth, BlankRowID } from "../lib/constants" import { GutterWidth, BlankRowID } from "../lib/constants"
import GutterCell from "../cells/GutterCell.svelte" import GutterCell from "../cells/GutterCell.svelte"
import KeyboardShortcut from "./KeyboardShortcut.svelte" import KeyboardShortcut from "./KeyboardShortcut.svelte"
import { getCellID } from "../lib/utils"
const { const {
rows, rows,
@ -71,7 +72,7 @@
{@const rowSelected = !!$selectedRows[row._id]} {@const rowSelected = !!$selectedRows[row._id]}
{@const rowHovered = $hoveredRowId === row._id} {@const rowHovered = $hoveredRowId === row._id}
{@const rowFocused = $focusedRow?._id === row._id} {@const rowFocused = $focusedRow?._id === row._id}
{@const cellId = `${row._id}-${$stickyColumn?.name}`} {@const cellId = getCellID(row._id, $stickyColumn?.name)}
<div <div
class="row" class="row"
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)} on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}

View file

@ -1,6 +1,23 @@
import { helpers } from "@budibase/shared-core" import { helpers } from "@budibase/shared-core"
import { TypeIconMap } from "../../../constants" import { TypeIconMap } from "../../../constants"
// we can't use "-" for joining the ID/field, as this can be present in the ID or column name
// using something very unusual to avoid this problem
const JOINING_CHARACTER = "‽‽"
export const parseCellID = rowId => {
if (!rowId) {
return undefined
}
const parts = rowId.split(JOINING_CHARACTER)
const field = parts.pop()
return { id: parts.join(JOINING_CHARACTER), field }
}
export const getCellID = (rowId, fieldName) => {
return `${rowId}${JOINING_CHARACTER}${fieldName}`
}
export const getColor = (idx, opacity = 0.3) => { export const getColor = (idx, opacity = 0.3) => {
if (idx == null || idx === -1) { if (idx == null || idx === -1) {
idx = 0 idx = 0

View file

@ -2,6 +2,7 @@
import { getContext, onMount } from "svelte" import { getContext, onMount } from "svelte"
import { debounce } from "../../../utils/utils" import { debounce } from "../../../utils/utils"
import { NewRowID } from "../lib/constants" import { NewRowID } from "../lib/constants"
import { getCellID, parseCellID } from "../lib/utils"
const { const {
rows, rows,
@ -154,7 +155,7 @@
if (!firstColumn) { if (!firstColumn) {
return return
} }
focusedCellId.set(`${firstRow._id}-${firstColumn.name}`) focusedCellId.set(getCellID(firstRow._id, firstColumn.name))
} }
// Changes the focused cell by moving it left or right to a different column // Changes the focused cell by moving it left or right to a different column
@ -163,8 +164,7 @@
return return
} }
const cols = $visibleColumns const cols = $visibleColumns
const split = $focusedCellId.split("-") const { id, field: columnName } = parseCellID($focusedCellId)
const columnName = split[1]
let newColumnName let newColumnName
if (columnName === $stickyColumn?.name) { if (columnName === $stickyColumn?.name) {
const index = delta - 1 const index = delta - 1
@ -178,7 +178,7 @@
} }
} }
if (newColumnName) { if (newColumnName) {
$focusedCellId = `${split[0]}-${newColumnName}` $focusedCellId = getCellID(id, newColumnName)
} }
} }
@ -189,8 +189,8 @@
} }
const newRow = $rows[$focusedRow.__idx + delta] const newRow = $rows[$focusedRow.__idx + delta]
if (newRow) { if (newRow) {
const split = $focusedCellId.split("-") const { field } = parseCellID($focusedCellId)
$focusedCellId = `${newRow._id}-${split[1]}` $focusedCellId = getCellID(newRow._id, field)
} }
} }

View file

@ -3,6 +3,7 @@
import { getContext } from "svelte" import { getContext } from "svelte"
import { NewRowID } from "../lib/constants" import { NewRowID } from "../lib/constants"
import GridPopover from "./GridPopover.svelte" import GridPopover from "./GridPopover.svelte"
import { getCellID } from "../lib/utils"
const { const {
focusedRow, focusedRow,
@ -41,7 +42,7 @@
const newRow = await rows.actions.duplicateRow($focusedRow) const newRow = await rows.actions.duplicateRow($focusedRow)
if (newRow) { if (newRow) {
const column = $stickyColumn?.name || $columns[0].name const column = $stickyColumn?.name || $columns[0].name
$focusedCellId = `${newRow._id}-${column}` $focusedCellId = getCellID(newRow._id, column)
} }
} }

View file

@ -1,6 +1,7 @@
import { writable, derived, get } from "svelte/store" import { writable, derived, get } from "svelte/store"
import { fetchData } from "../../../fetch" import { fetchData } from "../../../fetch"
import { NewRowID, RowPageSize } from "../lib/constants" import { NewRowID, RowPageSize } from "../lib/constants"
import { getCellID, parseCellID } from "../lib/utils"
import { tick } from "svelte" import { tick } from "svelte"
import { Helpers } from "@budibase/bbui" import { Helpers } from "@budibase/bbui"
@ -206,7 +207,7 @@ export const createActions = context => {
// If the server doesn't reply with a valid error, assume that the source // If the server doesn't reply with a valid error, assume that the source
// of the error is the focused cell's column // of the error is the focused cell's column
if (!error?.json?.validationErrors && errorString) { if (!error?.json?.validationErrors && errorString) {
const focusedColumn = get(focusedCellId)?.split("-")[1] const { field: focusedColumn } = parseCellID(get(focusedCellId))
if (focusedColumn) { if (focusedColumn) {
error = { error = {
json: { json: {
@ -245,7 +246,7 @@ export const createActions = context => {
} }
// Set error against the cell // Set error against the cell
validation.actions.setError( validation.actions.setError(
`${rowId}-${column}`, getCellID(rowId, column),
Helpers.capitalise(err) Helpers.capitalise(err)
) )
// Ensure the column is visible // Ensure the column is visible
@ -265,7 +266,7 @@ export const createActions = context => {
// Focus the first cell with an error // Focus the first cell with an error
if (erroredColumns.length) { if (erroredColumns.length) {
focusedCellId.set(`${rowId}-${erroredColumns[0]}`) focusedCellId.set(getCellID(rowId, erroredColumns[0]))
} }
} else { } else {
get(notifications).error(errorString || "An unknown error occurred") get(notifications).error(errorString || "An unknown error occurred")
@ -571,9 +572,10 @@ export const initialise = context => {
return return
} }
// Stop if we changed row // Stop if we changed row
const oldRowId = id.split("-")[0] const split = parseCellID(id)
const oldColumn = id.split("-")[1] const oldRowId = split.id
const newRowId = get(focusedCellId)?.split("-")[0] const oldColumn = split.field
const { id: newRowId } = parseCellID(get(focusedCellId))
if (oldRowId !== newRowId) { if (oldRowId !== newRowId) {
return return
} }

View file

@ -1,6 +1,7 @@
import { writable, derived, get } from "svelte/store" import { writable, derived, get } from "svelte/store"
import { tick } from "svelte" import { tick } from "svelte"
import { Padding, GutterWidth, FocusedCellMinOffset } from "../lib/constants" import { Padding, GutterWidth, FocusedCellMinOffset } from "../lib/constants"
import { parseCellID } from "../lib/utils"
export const createStores = () => { export const createStores = () => {
const scroll = writable({ const scroll = writable({
@ -176,7 +177,7 @@ export const initialise = context => {
// Ensure horizontal position is viewable // Ensure horizontal position is viewable
// Check horizontal position of columns next // Check horizontal position of columns next
const $visibleColumns = get(visibleColumns) const $visibleColumns = get(visibleColumns)
const columnName = $focusedCellId?.split("-")[1] const { field: columnName } = parseCellID($focusedCellId)
const column = $visibleColumns.find(col => col.name === columnName) const column = $visibleColumns.find(col => col.name === columnName)
if (!column) { if (!column) {
return return

View file

@ -7,6 +7,7 @@ import {
MediumRowHeight, MediumRowHeight,
NewRowID, NewRowID,
} from "../lib/constants" } from "../lib/constants"
import { parseCellID } from "../lib/utils"
export const createStores = context => { export const createStores = context => {
const { props } = context const { props } = context
@ -25,7 +26,7 @@ export const createStores = context => {
const focusedRowId = derived( const focusedRowId = derived(
focusedCellId, focusedCellId,
$focusedCellId => { $focusedCellId => {
return $focusedCellId?.split("-")[0] return parseCellID($focusedCellId)?.id
}, },
null null
) )
@ -72,7 +73,7 @@ export const deriveStores = context => {
const focusedRow = derived( const focusedRow = derived(
[focusedCellId, rowLookupMap, rows], [focusedCellId, rowLookupMap, rows],
([$focusedCellId, $rowLookupMap, $rows]) => { ([$focusedCellId, $rowLookupMap, $rows]) => {
const rowId = $focusedCellId?.split("-")[0] const rowId = parseCellID($focusedCellId)?.id
// Edge case for new rows // Edge case for new rows
if (rowId === NewRowID) { if (rowId === NewRowID) {
@ -152,7 +153,7 @@ export const initialise = context => {
const hasRow = rows.actions.hasRow const hasRow = rows.actions.hasRow
// Check selected cell // Check selected cell
const selectedRowId = $focusedCellId?.split("-")[0] const selectedRowId = parseCellID($focusedCellId)?.id
if (selectedRowId && !hasRow(selectedRowId)) { if (selectedRowId && !hasRow(selectedRowId)) {
focusedCellId.set(null) focusedCellId.set(null)
} }

View file

@ -1,4 +1,5 @@
import { writable, get, derived } from "svelte/store" import { writable, get, derived } from "svelte/store"
import { getCellID, parseCellID } from "../lib/utils"
// Normally we would break out actions into the explicit "createActions" // Normally we would break out actions into the explicit "createActions"
// function, but for validation all these actions are pure so can go into // function, but for validation all these actions are pure so can go into
@ -12,7 +13,7 @@ export const createStores = () => {
Object.entries($validation).forEach(([key, error]) => { Object.entries($validation).forEach(([key, error]) => {
// Extract row ID from all errored cell IDs // Extract row ID from all errored cell IDs
if (error) { if (error) {
map[key.split("-")[0]] = true map[parseCellID(key).id] = true
} }
}) })
return map return map
@ -53,10 +54,10 @@ export const initialise = context => {
const $stickyColumn = get(stickyColumn) const $stickyColumn = get(stickyColumn)
validation.update(state => { validation.update(state => {
$columns.forEach(column => { $columns.forEach(column => {
state[`${id}-${column.name}`] = null state[getCellID(id, column.name)] = null
}) })
if ($stickyColumn) { if ($stickyColumn) {
state[`${id}-${$stickyColumn.name}`] = null state[getCellID(id, stickyColumn.name)] = null
} }
return state return state
}) })

View file

@ -386,9 +386,11 @@ class GoogleSheetsIntegration implements DatasourcePlus {
} }
buildRowObject(headers: string[], values: string[], rowNumber: number) { buildRowObject(headers: string[], values: string[], rowNumber: number) {
const rowObject: { rowNumber: number; [key: string]: any } = { rowNumber } const rowObject: { rowNumber: number } & Row = {
rowNumber,
_id: rowNumber.toString(),
}
for (let i = 0; i < headers.length; i++) { for (let i = 0; i < headers.length; i++) {
rowObject._id = rowNumber
rowObject[headers[i]] = values[i] rowObject[headers[i]] = values[i]
} }
return rowObject return rowObject
@ -445,14 +447,6 @@ class GoogleSheetsIntegration implements DatasourcePlus {
} }
} }
// clear out deleted columns
for (let key of sheet.headerValues) {
if (!Object.keys(table.schema).includes(key)) {
const idx = updatedHeaderValues.indexOf(key)
updatedHeaderValues.splice(idx, 1)
}
}
try { try {
await sheet.setHeaderRow(updatedHeaderValues) await sheet.setHeaderRow(updatedHeaderValues)
} catch (err) { } catch (err) {
@ -473,7 +467,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
} }
} }
async create(query: { sheet: string; row: any }) { async create(query: { sheet: string; row: Row }) {
try { try {
await this.connect() await this.connect()
const sheet = this.client.sheetsByTitle[query.sheet] const sheet = this.client.sheetsByTitle[query.sheet]
@ -489,7 +483,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
} }
} }
async createBulk(query: { sheet: string; rows: any[] }) { async createBulk(query: { sheet: string; rows: Row[] }) {
try { try {
await this.connect() await this.connect()
const sheet = this.client.sheetsByTitle[query.sheet] const sheet = this.client.sheetsByTitle[query.sheet]

View file

@ -129,10 +129,11 @@ describe("Google Sheets Integration", () => {
}) })
expect(sheet.loadHeaderRow).toHaveBeenCalledTimes(1) expect(sheet.loadHeaderRow).toHaveBeenCalledTimes(1)
expect(sheet.setHeaderRow).toHaveBeenCalledTimes(1) expect(sheet.setHeaderRow).toHaveBeenCalledTimes(1)
expect(sheet.setHeaderRow).toHaveBeenCalledWith(["name"]) expect(sheet.setHeaderRow).toHaveBeenCalledWith([
"name",
// No undefined are sent "description",
expect((sheet.setHeaderRow as any).mock.calls[0][0]).toHaveLength(1) "location",
])
}) })
}) })