From 14efdda823f604b2054c799ce7ca0ce385dbef34 Mon Sep 17 00:00:00 2001 From: Anton Kulyk Date: Thu, 16 Jun 2022 15:40:27 +0100 Subject: [PATCH 1/4] Add `database_required` to `Field` class --- frontend/src/metabase-lib/lib/metadata/Field.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/metabase-lib/lib/metadata/Field.ts b/frontend/src/metabase-lib/lib/metadata/Field.ts index ac11d50174d27..a6585472faf98 100644 --- a/frontend/src/metabase-lib/lib/metadata/Field.ts +++ b/frontend/src/metabase-lib/lib/metadata/Field.ts @@ -48,6 +48,7 @@ class FieldInner extends Base { name: string; description: string | null; semantic_type: string | null; + database_required: boolean; fingerprint?: FieldFingerprint; base_type: string | null; table?: Table; From 0567777e76fe1089c53d7be3244534914efae694 Mon Sep 17 00:00:00 2001 From: Anton Kulyk Date: Thu, 16 Jun 2022 15:47:27 +0100 Subject: [PATCH 2/4] Handle required PK columns in writeback forms --- .../writeback/containers/WritebackForm.tsx | 8 ++++---- frontend/src/metabase/writeback/utils.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/frontend/src/metabase/writeback/containers/WritebackForm.tsx b/frontend/src/metabase/writeback/containers/WritebackForm.tsx index 1f0414346d4e3..ed32c52c04c0c 100644 --- a/frontend/src/metabase/writeback/containers/WritebackForm.tsx +++ b/frontend/src/metabase/writeback/containers/WritebackForm.tsx @@ -8,6 +8,7 @@ import { TYPE } from "metabase/lib/types"; import Field from "metabase-lib/lib/metadata/Field"; import Table from "metabase-lib/lib/metadata/Table"; +import { isEditableField } from "../utils"; import CategoryFieldPicker from "./CategoryFieldPicker"; export interface WritebackFormProps { @@ -56,10 +57,9 @@ function getFieldTypeProps(field: Field) { } function WritebackForm({ table, row, onSubmit, ...props }: WritebackFormProps) { - const editableFields = useMemo( - () => table.fields.filter(field => field.id && !field.isPK()), - [table], - ); + const editableFields = useMemo(() => table.fields.filter(isEditableField), [ + table, + ]); const form = useMemo(() => { return { diff --git a/frontend/src/metabase/writeback/utils.ts b/frontend/src/metabase/writeback/utils.ts index d2bc00f687f33..6c743ff396ad9 100644 --- a/frontend/src/metabase/writeback/utils.ts +++ b/frontend/src/metabase/writeback/utils.ts @@ -1,6 +1,7 @@ import { getTemplateTagParameterTarget } from "metabase/parameters/utils/cards"; import Database from "metabase-lib/lib/metadata/Database"; +import Field from "metabase-lib/lib/metadata/Field"; import { Database as IDatabase } from "metabase-types/types/Database"; import { DashCard } from "metabase-types/types/Dashboard"; @@ -17,6 +18,23 @@ export const isDatabaseWritebackEnabled = (database?: IDatabase | null) => export const isWritebackSupported = (database?: Database | null) => !!database?.hasFeature(DB_WRITEBACK_FEATURE); +export const isEditableField = (field: Field) => { + const isRealField = typeof field.id === "number"; + if (!isRealField) { + // Filters out custom, aggregated columns, etc. + return false; + } + + if (field.isPK()) { + // Most of the time PKs are auto-generated, + // but there are rare cases when they're not + // In this case they're marked as `database_required` + return field.database_required; + } + + return true; +}; + export const isActionButtonDashCard = (dashCard: DashCard) => dashCard.visualization_settings?.virtual_card?.display === "action-button"; From 804ee0cd776f21d1d1be93b20b1dfdd38b4c19c4 Mon Sep 17 00:00:00 2001 From: Anton Kulyk Date: Thu, 16 Jun 2022 15:47:54 +0100 Subject: [PATCH 3/4] Show "(required)" label next to field titles --- .../src/metabase/writeback/containers/WritebackForm.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/metabase/writeback/containers/WritebackForm.tsx b/frontend/src/metabase/writeback/containers/WritebackForm.tsx index ed32c52c04c0c..1f728f33c54bd 100644 --- a/frontend/src/metabase/writeback/containers/WritebackForm.tsx +++ b/frontend/src/metabase/writeback/containers/WritebackForm.tsx @@ -66,9 +66,15 @@ function WritebackForm({ table, row, onSubmit, ...props }: WritebackFormProps) { fields: editableFields.map(field => { const fieldIndex = table.fields.findIndex(f => f.id === field.id); const initialValue = row ? row[fieldIndex] : undefined; + + let title = field.displayName(); + if (field.database_required) { + title += " (" + t`required` + ")"; + } + return { name: field.name, - title: field.displayName(), + title, description: field.description, initial: initialValue, ...getFieldTypeProps(field), From 05e61d72928106dd90c888a4d5e013320b6dd5a1 Mon Sep 17 00:00:00 2001 From: Anton Kulyk Date: Thu, 16 Jun 2022 15:48:18 +0100 Subject: [PATCH 4/4] Validate required writeback form fields --- .../writeback/containers/WritebackForm.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frontend/src/metabase/writeback/containers/WritebackForm.tsx b/frontend/src/metabase/writeback/containers/WritebackForm.tsx index 1f728f33c54bd..e8ee28b08998a 100644 --- a/frontend/src/metabase/writeback/containers/WritebackForm.tsx +++ b/frontend/src/metabase/writeback/containers/WritebackForm.tsx @@ -3,6 +3,7 @@ import { t } from "ttag"; import Form from "metabase/containers/Form"; +import validate from "metabase/lib/validate"; import { TYPE } from "metabase/lib/types"; import Field from "metabase-lib/lib/metadata/Field"; @@ -56,6 +57,18 @@ function getFieldTypeProps(field: Field) { return { type: "input" }; } +function getFieldValidationProp(field: Field) { + let validator = validate as any; + + if (field.database_required) { + validator = validator.required(); + } + + return { + validate: validator, + }; +} + function WritebackForm({ table, row, onSubmit, ...props }: WritebackFormProps) { const editableFields = useMemo(() => table.fields.filter(isEditableField), [ table, @@ -78,6 +91,7 @@ function WritebackForm({ table, row, onSubmit, ...props }: WritebackFormProps) { description: field.description, initial: initialValue, ...getFieldTypeProps(field), + ...getFieldValidationProp(field), }; }), };