diff --git a/packages/bbui/src/Form/Core/DatePicker.svelte b/packages/bbui/src/Form/Core/DatePicker.svelte index ad39136142..7ce15292be 100644 --- a/packages/bbui/src/Form/Core/DatePicker.svelte +++ b/packages/bbui/src/Form/Core/DatePicker.svelte @@ -71,6 +71,7 @@ timeOnly, enableTime, time24hr, + disabled, } const handleChange = event => { diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index 4314f6e99c..3f2509f19b 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -16,7 +16,7 @@ export let columns = null const component = getContext("component") - const { styleable, API, builderStore } = getContext("sdk") + const { styleable, API, builderStore, notificationStore } = getContext("sdk") $: columnWhitelist = columns?.map(col => col.name) $: schemaOverrides = getSchemaOverrides(columns) @@ -52,6 +52,8 @@ showControls={false} allowExpandRows={false} allowSchemaChanges={false} + notifySuccess={notificationStore.actions.success} + notifyError={notificationStore.actions.error} /> diff --git a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte index c80b12cf1a..a27c31bbe5 100644 --- a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte @@ -1,7 +1,7 @@ diff --git a/packages/frontend-core/src/components/grid/stores/columns.js b/packages/frontend-core/src/components/grid/stores/columns.js index 664e67950e..21458eaefb 100644 --- a/packages/frontend-core/src/components/grid/stores/columns.js +++ b/packages/frontend-core/src/components/grid/stores/columns.js @@ -35,10 +35,20 @@ export const createStores = () => { [] ) + // Checks if we have a certain column by name + const hasColumn = column => { + const $columns = get(columns) + const $sticky = get(stickyColumn) + return $columns.some(col => col.name === column) || $sticky?.name === column + } + return { columns: { ...columns, subscribe: enrichedColumns.subscribe, + actions: { + hasColumn, + }, }, stickyColumn, visibleColumns, @@ -121,6 +131,7 @@ export const deriveStores = context => { columns: { ...columns, actions: { + ...columns.actions, saveChanges, saveTable, changePrimaryDisplay, diff --git a/packages/frontend-core/src/components/grid/stores/config.js b/packages/frontend-core/src/components/grid/stores/config.js index 2fe9bafa91..cdf71e161b 100644 --- a/packages/frontend-core/src/components/grid/stores/config.js +++ b/packages/frontend-core/src/components/grid/stores/config.js @@ -13,6 +13,8 @@ export const createStores = context => { const initialRowHeight = getProp("initialRowHeight") const schemaOverrides = getProp("schemaOverrides") const columnWhitelist = getProp("columnWhitelist") + const notifySuccess = getProp("notifySuccess") + const notifyError = getProp("notifyError") return { config, @@ -23,5 +25,7 @@ export const createStores = context => { initialRowHeight, schemaOverrides, columnWhitelist, + notifySuccess, + notifyError, } } diff --git a/packages/frontend-core/src/components/grid/stores/index.js b/packages/frontend-core/src/components/grid/stores/index.js index 588b568c8e..2a52b55f59 100644 --- a/packages/frontend-core/src/components/grid/stores/index.js +++ b/packages/frontend-core/src/components/grid/stores/index.js @@ -14,9 +14,11 @@ import * as Clipboard from "./clipboard" import * as Config from "./config" import * as Sort from "./sort" import * as Filter from "./filter" +import * as Notifications from "./notifications" const DependencyOrderedStores = [ Config, + Notifications, Sort, Filter, Bounds, diff --git a/packages/frontend-core/src/components/grid/stores/notifications.js b/packages/frontend-core/src/components/grid/stores/notifications.js new file mode 100644 index 0000000000..4e8b49414d --- /dev/null +++ b/packages/frontend-core/src/components/grid/stores/notifications.js @@ -0,0 +1,23 @@ +import { notifications as BBUINotifications } from "@budibase/bbui" +import { derived } from "svelte/store" + +export const createStores = context => { + const { notifySuccess, notifyError } = context + + // Normally we would not derive a store in "createStores" as it should be + // dependency free, but in this case it's safe as we only depend on grid props + // which are guaranteed to be first in the dependency chain + const notifications = derived( + [notifySuccess, notifyError], + ([$notifySuccess, $notifyError]) => { + return { + success: $notifySuccess || BBUINotifications.success, + error: $notifyError || BBUINotifications.error, + } + } + ) + + return { + notifications, + } +} diff --git a/packages/frontend-core/src/components/grid/stores/rows.js b/packages/frontend-core/src/components/grid/stores/rows.js index d348d5caa5..736863378f 100644 --- a/packages/frontend-core/src/components/grid/stores/rows.js +++ b/packages/frontend-core/src/components/grid/stores/rows.js @@ -1,6 +1,5 @@ import { writable, derived, get } from "svelte/store" import { fetchData } from "../../../fetch/fetchData" -import { notifications } from "@budibase/bbui" import { NewRowID, RowPageSize } from "../lib/constants" import { tick } from "svelte" @@ -71,6 +70,7 @@ export const deriveStores = context => { previousFocusedRowId, hasNextPage, error, + notifications, } = context const instanceLoaded = writable(false) const fetch = writable(null) @@ -203,10 +203,23 @@ export const deriveStores = context => { // state, storing error messages against relevant cells const handleValidationError = (rowId, error) => { if (error?.json?.validationErrors) { - // Normal validation error + // Normal validation errors const keys = Object.keys(error.json.validationErrors) const $columns = get(columns) + + // Filter out missing columns from columns that we have + let erroredColumns = [] + let missingColumns = [] for (let column of keys) { + if (columns.actions.hasColumn(column)) { + erroredColumns.push(column) + } else { + missingColumns.push(column) + } + } + + // Process errors for columns that we have + for (let column of erroredColumns) { validation.actions.setError( `${rowId}-${column}`, `${column} ${error.json.validationErrors[column]}` @@ -221,8 +234,16 @@ export const deriveStores = context => { }) } } + + // Notify about missing columns + for (let column of missingColumns) { + get(notifications).error(`${column} is required but is missing`) + } + // Focus the first cell with an error - focusedCellId.set(`${rowId}-${keys[0]}`) + if (erroredColumns.length) { + focusedCellId.set(`${rowId}-${erroredColumns[0]}`) + } } else { // Some other error - just update the current cell validation.actions.setError(get(focusedCellId), error?.message || "Error") @@ -250,7 +271,7 @@ export const deriveStores = context => { } // Refresh row to ensure data is in the correct format - notifications.success("Row created successfully") + get(notifications).success("Row created successfully") return newRow } catch (error) { if (bubble) {