diff --git a/src/components/fields/Formula/DisplayCell.tsx b/src/components/fields/Formula/DisplayCell.tsx
index ddea15d3..79760e32 100644
--- a/src/components/fields/Formula/DisplayCell.tsx
+++ b/src/components/fields/Formula/DisplayCell.tsx
@@ -5,11 +5,16 @@ import { getDisplayCell } from "./util";
export default function Formula(props: IDisplayCellProps) {
const { result, error } = useFormula({
row: props.row,
+ listenerFields: props.column.config?.listenerFields || [],
formulaFn: props.column.config?.formulaFn,
});
const type = props.column.config?.renderFieldType;
const DisplayCell = getDisplayCell(type);
+ if (error) {
+ return <>Error>;
+ }
+
return ;
}
diff --git a/src/components/fields/Formula/Settings.tsx b/src/components/fields/Formula/Settings.tsx
index 36d21e91..cb907a8c 100644
--- a/src/components/fields/Formula/Settings.tsx
+++ b/src/components/fields/Formula/Settings.tsx
@@ -7,19 +7,19 @@ import {
Typography,
Stack,
FormHelperText,
+ Tooltip,
} from "@mui/material";
import FieldSkeleton from "@src/components/SideDrawer/FieldSkeleton";
import { useAtom } from "jotai";
-import {
- tableColumnsOrderedAtom,
- tableRowsAtom,
- tableScope,
-} from "@src/atoms/tableScope";
-import { useFormula } from "./useFormula";
-import { listenerFieldTypes, outputFieldTypes, typeDefs } from "./util";
+import { tableColumnsOrderedAtom, tableScope } from "@src/atoms/tableScope";
+import { defaultFn, listenerFieldTypes, outputFieldTypes } from "./util";
import MultiSelect from "@rowy/multiselect";
import FieldsDropdown from "@src/components/ColumnModals/FieldsDropdown";
+import { getFieldProp } from "..";
+
+/* eslint-disable import/no-webpack-loader-syntax */
+import formulaDefs from "!!raw-loader!./formula.d.ts";
const CodeEditor = lazy(
() =>
@@ -28,39 +28,13 @@ const CodeEditor = lazy(
export default function Settings({
config,
- fieldName,
onChange,
onBlur,
errors,
}: ISettingsProps) {
const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope);
- const [tableRows] = useAtom(tableRowsAtom, tableScope);
- const { error, result, loading } = useFormula({
- row: tableRows[0],
- formulaFn: config.formulaFn,
- });
-
- // if (error && !config?.error) {
- // onChange("error")(error.message);
- // }
- // if (!error && config?.error) {
- // onChange("error")(undefined);
- // }
-
- // if (loading) {
- // console.log("loading");
- // }
-
- // if (error) {
- // console.log(error);
- // }
-
- const formulaFn =
- config?.formulaFn ??
- `// Write your formula code here
-// for example:
-// return column1 + column2;
-// checkout the documentation for more info: https://docs.rowy.io/field-types/formula`;
+ const returnType = getFieldProp("dataType", config.renderFieldType) ?? "any";
+ const formulaFn = config?.formulaFn ? config.formulaFn : defaultFn;
return (
@@ -70,7 +44,7 @@ export default function Settings({
label="Listener fields"
options={tableColumnsOrdered
.filter((c) => listenerFieldTypes.includes(c.type))
- .map((c) => c.name)}
+ .map((c) => ({ label: c.name, value: c.key }))}
value={config.listenerFields ?? []}
onChange={onChange("listenerFields")}
TextFieldProps={{
@@ -130,52 +104,26 @@ export default function Settings({
spacing={1}
style={{ flexGrow: 1, marginTop: -8, marginLeft: 0 }}
>
- {/* {Object.values(previewColumns).map((column) => (
-
-
- {column.fieldName}
-
-
- ))} */}
+
+
+ row
+
+
}>
`
+ ),
+ ]}
onChange={useDebouncedCallback(onChange("formulaFn"), 300)}
/>
- {/*
- Preview:
-
-
-
- |
-
- {Object.entries(previewColumns).map(
- ([field, { name, type, key }]) => (
-
-
- |
-
- )
- )}
-
- */}
);
}
diff --git a/src/components/fields/Formula/formula.d.ts b/src/components/fields/Formula/formula.d.ts
new file mode 100644
index 00000000..90f9351d
--- /dev/null
+++ b/src/components/fields/Formula/formula.d.ts
@@ -0,0 +1,8 @@
+type FormulaContext = {
+ row: Row;
+ // ref: FirebaseFirestore.DocumentReference;
+ // storage: firebasestorage.Storage;
+ // db: FirebaseFirestore.Firestore;
+};
+
+type Formula = (context: FormulaContext) => "PLACEHOLDER_OUTPUT_TYPE";
diff --git a/src/components/fields/Formula/useFormula.tsx b/src/components/fields/Formula/useFormula.tsx
index 48a2d9e8..f33bab43 100644
--- a/src/components/fields/Formula/useFormula.tsx
+++ b/src/components/fields/Formula/useFormula.tsx
@@ -3,13 +3,15 @@ import { TableRow } from "@src/types/table";
import { useAtom } from "jotai";
import { pick, zipObject } from "lodash-es";
import { useEffect, useMemo, useState } from "react";
-import { useDeepCompareMemoize } from "./util";
+import { listenerFieldTypes, useDeepCompareMemoize } from "./util";
export const useFormula = ({
row,
+ listenerFields,
formulaFn,
}: {
row: TableRow;
+ listenerFields: string[];
formulaFn: string;
}) => {
const [result, setResult] = useState(null);
@@ -17,7 +19,9 @@ export const useFormula = ({
const [loading, setLoading] = useState(false);
const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope);
- const availableColumns = tableColumnsOrdered.map((c) => c.key);
+ const availableColumns = tableColumnsOrdered
+ .filter((c) => listenerFieldTypes.includes(c.type))
+ .map((c) => c.key);
const availableFields = useMemo(
() => ({
@@ -30,17 +34,22 @@ export const useFormula = ({
[row, availableColumns]
);
+ const listeners = useMemo(
+ () => pick(availableFields, listenerFields),
+ [availableFields, listenerFields]
+ );
+
useEffect(() => {
setLoading(true);
const worker = new Worker(new URL("./worker.ts", import.meta.url), {
- type: "classic",
+ type: "module",
});
const timeout = setTimeout(() => {
setError(new Error("Timeout"));
setLoading(false);
worker.terminate();
- }, 1000);
+ }, 10000);
worker.onmessage = ({ data: { result, error } }: any) => {
worker.terminate();
@@ -53,8 +62,9 @@ export const useFormula = ({
clearInterval(timeout);
};
+ const functionBody = formulaFn.replace(/^.*=>\s*{/, "").replace(/}$/, "");
worker.postMessage({
- formulaFn: formulaFn,
+ formulaFn: functionBody,
row: availableFields,
});
@@ -63,7 +73,7 @@ export const useFormula = ({
clearInterval(timeout);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [useDeepCompareMemoize(availableFields), formulaFn]);
+ }, [useDeepCompareMemoize(listeners), formulaFn]);
return { result, error, loading };
};
diff --git a/src/components/fields/Formula/util.tsx b/src/components/fields/Formula/util.tsx
index 6dd04db4..8fda4b07 100644
--- a/src/components/fields/Formula/util.tsx
+++ b/src/components/fields/Formula/util.tsx
@@ -47,7 +47,6 @@ export const listenerFieldTypes = Object.values(FieldType).filter(
FieldType.connectTable,
FieldType.connector,
FieldType.subTable,
- FieldType.reference,
FieldType.last,
].includes(type)
);
@@ -74,32 +73,13 @@ export const outputFieldTypes = Object.values(FieldType).filter(
].includes(type)
);
-export const typeDefs = (type: FieldType) => {
- switch (type) {
- case FieldType.shortText:
- case FieldType.longText:
- case FieldType.richText:
- case FieldType.email:
- case FieldType.phone:
- case FieldType.url:
- case FieldType.singleSelect:
- return "string | undefined";
- case FieldType.multiSelect:
- return "Array | undefined";
- case FieldType.number:
- case FieldType.rating:
- case FieldType.slider:
- case FieldType.percentage:
- return "number | undefined";
- case FieldType.checkbox:
- return "boolean | undefined";
- case FieldType.date:
- case FieldType.dateTime:
- case FieldType.duration:
- return "{ seconds: number; nanoseconds: number; }";
- }
- return "any";
-};
+export const defaultFn = `const formula:Formula = async ({ row })=> {
+ // Write your formula code here
+ // for example:
+ // return row.a + row.b;
+ // checkout the documentation for more info: https://docs.rowy.io/field-types/formula
+}
+`;
export const getDisplayCell = (type: FieldType) => {
switch (type) {
diff --git a/src/components/fields/Formula/worker.ts b/src/components/fields/Formula/worker.ts
index 1dab169c..57c03265 100644
--- a/src/components/fields/Formula/worker.ts
+++ b/src/components/fields/Formula/worker.ts
@@ -1,19 +1,20 @@
-import { ContentSaveCogOutline } from "mdi-material-ui";
-
onmessage = async ({ data }) => {
try {
const { formulaFn, row } = data;
- console.dir(row);
- const AsyncFunction = (async (x: any) => x).constructor as any;
- // eslint-disable-next-line no-new-func
- // const result = await new AsyncFunction("row", formulaFn)(row);
+
+ const AsyncFunction = async function () {}.constructor as any;
const fn = new AsyncFunction("row", formulaFn);
const result = await fn(row);
+ await new Promise((resolve) => setTimeout(() => resolve(50), 3000)).then(
+ (res) => console.log(res)
+ );
console.log(result);
postMessage({ result });
} catch (error: any) {
console.error("error: ", error);
- postMessage({ error: new Error(error) });
+ postMessage({
+ error: new Error("Something went wrong. Check console logs."),
+ });
} finally {
// eslint-disable-next-line no-restricted-globals
self.close();