Implement and Add SideDrawerField for Formula Field (#1225)

* Implement and Add SideDrawerField for Formula Field

* Modify Formula SideDrawerField to use already calculated value

* fix unneccessary db update on formula calculations

---------

Co-authored-by: Han Tuerker <burhan.tuerker@gmail.com>
This commit is contained in:
mnmt7
2023-05-02 04:59:02 +05:30
committed by GitHub
parent b8c231ae62
commit 2715a8094a
10 changed files with 102 additions and 10 deletions

View File

@@ -386,7 +386,9 @@ export const updateFieldAtom = atom(
);
if (!row) throw new Error("Could not find row");
const isLocalRow = Boolean(find(tableRowsLocal, ["_rowy_ref.path", path]));
const isLocalRow =
fieldName.startsWith("_rowy_formulaValue_") ||
Boolean(find(tableRowsLocal, ["_rowy_ref.path", path]));
const update: Partial<TableRow> = {};
@@ -467,6 +469,14 @@ export const updateFieldAtom = atom(
deleteFields: deleteField ? [fieldName] : [],
});
// TODO(han): Formula field persistence
// const config = find(tableColumnsOrdered, (c) => {
// const [, key] = fieldName.split("_rowy_formulaValue_");
// return c.key === key;
// });
// if(!config.persist) return;
if (fieldName.startsWith("_rowy_formulaValue")) return;
// If it has no missingRequiredFields, also write to db
// And write entire row to handle the case where it doesnt exist in db yet
if (missingRequiredFields.length === 0) {

View File

@@ -6,6 +6,7 @@ import FieldWrapper from "./FieldWrapper";
import { IFieldConfig } from "@src/components/fields/types";
import { getFieldProp } from "@src/components/fields";
import { ColumnConfig, TableRowRef } from "@src/types/table";
import { TableRow } from "@src/types/table";
export interface IMemoizedFieldProps {
field: ColumnConfig;
@@ -16,6 +17,7 @@ export interface IMemoizedFieldProps {
isDirty: boolean;
onDirty: (fieldName: string) => void;
onSubmit: (fieldName: string, value: any) => void;
row: TableRow;
}
export const MemoizedField = memo(
@@ -28,6 +30,7 @@ export const MemoizedField = memo(
isDirty,
onDirty,
onSubmit,
row,
...props
}: IMemoizedFieldProps) {
const [localValue, setLocalValue, localValueRef] = useStateRef(value);
@@ -40,11 +43,7 @@ export const MemoizedField = memo(
onSubmit(field.fieldName, localValueRef.current);
}, [field.fieldName, localValueRef, onSubmit]);
// Derivative/aggregate field support
let type = field.type;
if (field.config && field.config.renderFieldType) {
type = field.config.renderFieldType;
}
const fieldComponent: IFieldConfig["SideDrawerField"] = getFieldProp(
"SideDrawerField",
@@ -78,6 +77,7 @@ export const MemoizedField = memo(
},
onSubmit: handleSubmit,
disabled,
row,
})}
</FieldWrapper>
);

View File

@@ -130,6 +130,7 @@ export default function SideDrawerFields({ row }: ISideDrawerFieldsProps) {
onDirty={onDirty}
onSubmit={onSubmit}
isDirty={dirtyField === field.key}
row={row}
/>
))}

View File

@@ -11,7 +11,7 @@ import DragIndicatorOutlinedIcon from "@mui/icons-material/DragIndicatorOutlined
import DeleteIcon from "@mui/icons-material/DeleteOutline";
import { FieldType, ISideDrawerFieldProps } from "@src/components/fields/types";
import { TableRowRef } from "@src/types/table";
import { TableRow, TableRowRef } from "@src/types/table";
import AddButton from "./AddButton";
import { getPseudoColumn } from "./utils";
@@ -29,6 +29,7 @@ function ArrayFieldInput({
onRemove,
onSubmit,
id,
row,
}: {
index: number;
onRemove: (index: number) => void;
@@ -37,6 +38,7 @@ function ArrayFieldInput({
onSubmit: () => void;
_rowy_ref: TableRowRef;
id: string;
row: TableRow;
}) {
const typeDetected = detectType(value);
@@ -80,6 +82,7 @@ function ArrayFieldInput({
column={getPseudoColumn(typeDetected, index, value)}
value={value}
_rowy_ref={_rowy_ref}
row={row}
/>
</Stack>
<Box
@@ -174,6 +177,7 @@ export default function ArraySideDrawerField({
onRemove={handleRemove}
index={index}
onSubmit={onSubmit}
row={props.row}
/>
))}
{provided.placeholder}

View File

@@ -6,6 +6,7 @@ import { defaultFn, getDisplayCell } from "./util";
export default function Formula(props: IDisplayCellProps) {
const { result, error, loading } = useFormula({
column: props.column,
row: props.row,
ref: props._rowy_ref,
listenerFields: props.column.config?.listenerFields || [],

View File

@@ -0,0 +1,46 @@
import { ISideDrawerFieldProps } from "@src/components/fields/types";
import { IFieldConfig } from "@src/components/fields/types";
import { getFieldProp } from "@src/components/fields";
import { isEmpty } from "lodash-es";
import { createElement } from "react";
export default function Formula({
column,
onChange,
onSubmit,
_rowy_ref,
onDirty,
row,
}: ISideDrawerFieldProps) {
const value = row[`_rowy_formulaValue_${column.key}`];
let type = column.type;
if (column.config && column.config.renderFieldType) {
type = column.config.renderFieldType;
}
const fieldComponent: IFieldConfig["SideDrawerField"] = getFieldProp(
"SideDrawerField",
type
);
// Should not reach this state
if (isEmpty(fieldComponent)) {
console.error("Could not find SideDrawerField component", column);
return null;
}
return (
<>
{createElement(fieldComponent, {
column,
_rowy_ref,
value,
onDirty,
onChange,
onSubmit,
disabled: true,
row,
})}
</>
);
}

View File

@@ -1,9 +1,16 @@
import { lazy } from "react";
import FormulaIcon from "@mui/icons-material/Functions";
import { IFieldConfig, FieldType } from "@src/components/fields/types";
import withRenderTableCell from "@src/components/Table/TableCell/withRenderTableCell";
import DisplayCell from "./DisplayCell";
import Settings, { settingsValidator } from "./Settings";
const SideDrawerField = lazy(
() =>
import(
"./SideDrawerField" /* webpackChunkName: "SideDrawerField-Formula" */
)
);
export const config: IFieldConfig = {
type: FieldType.formula,
@@ -16,7 +23,7 @@ export const config: IFieldConfig = {
TableCell: withRenderTableCell(DisplayCell as any, null, undefined, {
usesRowData: true,
}),
SideDrawerField: () => null as any,
SideDrawerField,
settings: Settings,
settingsValidator: settingsValidator,
requireConfiguration: true,

View File

@@ -1,9 +1,13 @@
import { useEffect, useMemo, useState } from "react";
import { pick, zipObject } from "lodash-es";
import { useAtom } from "jotai";
import { useAtom, useSetAtom } from "jotai";
import { TableRow, TableRowRef } from "@src/types/table";
import { tableColumnsOrderedAtom, tableScope } from "@src/atoms/tableScope";
import { TableRow, TableRowRef, ColumnConfig } from "@src/types/table";
import {
tableColumnsOrderedAtom,
tableScope,
updateFieldAtom,
} from "@src/atoms/tableScope";
import {
listenerFieldTypes,
@@ -12,11 +16,13 @@ import {
} from "./util";
export const useFormula = ({
column,
row,
ref,
listenerFields,
formulaFn,
}: {
column: ColumnConfig;
row: TableRow;
ref: TableRowRef;
listenerFields: string[];
@@ -78,5 +84,14 @@ export const useFormula = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [useDeepCompareMemoize(listeners), formulaFn]);
const updateField = useSetAtom(updateFieldAtom, tableScope);
useEffect(() => {
updateField({
path: row._rowy_ref.path,
fieldName: `_rowy_formulaValue_${column.key}`,
value: result,
});
}, [result, column.key, row._rowy_ref.path, updateField]);
return { result, error, loading };
};

View File

@@ -92,6 +92,8 @@ export interface ISideDrawerFieldProps<T = any> {
/** Field locked. Do NOT check `column.locked` */
disabled: boolean;
row: TableRow
}
export interface ISettingsProps {

View File

@@ -52,6 +52,12 @@ export const omitRowyFields = <T = Record<string, any>>(row: T) => {
delete shallowClonedRow["_rowy_missingRequiredFields"];
delete shallowClonedRow["_rowy_new"];
Object.keys(shallowClonedRow).forEach((key) => {
if (key.startsWith("_rowy_formulaValue_")) {
delete shallowClonedRow[key];
}
});
return shallowClonedRow as T;
};