mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
232 lines
7.3 KiB
TypeScript
232 lines
7.3 KiB
TypeScript
import { lazy, Suspense, createElement, useState } from "react";
|
||
import { useAtom } from "jotai";
|
||
|
||
import Checkbox from "@mui/material/Checkbox";
|
||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||
import { Typography, TextField, MenuItem, ListItemText } from "@mui/material";
|
||
|
||
import { getFieldProp } from "@src/components/fields";
|
||
import FieldSkeleton from "@src/components/SideDrawer/FieldSkeleton";
|
||
import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper";
|
||
import { FieldType } from "@src/constants/fields";
|
||
import { WIKI_LINKS } from "@src/constants/externalLinks";
|
||
|
||
/* eslint-disable import/no-webpack-loader-syntax */
|
||
import defaultValueDefs from "!!raw-loader!./defaultValue.d.ts";
|
||
import {
|
||
projectScope,
|
||
compatibleRowyRunVersionAtom,
|
||
projectSettingsAtom,
|
||
} from "@src/atoms/projectScope";
|
||
import { ColumnConfig } from "@src/types/table";
|
||
|
||
const CodeEditorComponent = lazy(
|
||
() =>
|
||
import("@src/components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||
);
|
||
|
||
const diagnosticsOptions = {
|
||
noSemanticValidation: false,
|
||
noSyntaxValidation: false,
|
||
noSuggestionDiagnostics: true,
|
||
};
|
||
|
||
interface ICodeEditorProps {
|
||
type: FieldType;
|
||
column: ColumnConfig;
|
||
handleChange: (key: string) => (update: string | undefined) => void;
|
||
}
|
||
|
||
function CodeEditor({ type, column, handleChange }: ICodeEditorProps) {
|
||
const [compatibleRowyRunVersion] = useAtom(
|
||
compatibleRowyRunVersionAtom,
|
||
projectScope
|
||
);
|
||
|
||
const functionBodyOnly = compatibleRowyRunVersion!({ maxVersion: "1.3.10" });
|
||
const returnType = getFieldProp("dataType", type) ?? "any";
|
||
|
||
let dynamicValueFn = "";
|
||
if (functionBodyOnly) {
|
||
dynamicValueFn = column.config?.defaultValue?.script || "";
|
||
} else if (column.config?.defaultValue?.dynamicValueFn) {
|
||
dynamicValueFn = column.config?.defaultValue?.dynamicValueFn;
|
||
} else if (column.config?.defaultValue?.script) {
|
||
dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth})=>{
|
||
${column.config?.defaultValue.script}
|
||
}`;
|
||
} else {
|
||
dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth})=>{
|
||
// Write your default value code here
|
||
// for example:
|
||
// generate random hex color
|
||
// const color = "#" + Math.floor(Math.random() * 16777215).toString(16);
|
||
// return color;
|
||
// checkout the documentation for more info: https://docs.rowy.io/how-to/default-values#dynamic
|
||
}`;
|
||
}
|
||
|
||
return (
|
||
<CodeEditorComponent
|
||
value={dynamicValueFn}
|
||
diagnosticsOptions={functionBodyOnly ? undefined : diagnosticsOptions}
|
||
extraLibs={[
|
||
defaultValueDefs.replace(
|
||
`"PLACEHOLDER_OUTPUT_TYPE"`,
|
||
`${returnType} | Promise<${returnType}>`
|
||
),
|
||
]}
|
||
onChange={handleChange(
|
||
functionBodyOnly ? "defaultValue.script" : "defaultValue.dynamicValueFn"
|
||
)}
|
||
/>
|
||
);
|
||
}
|
||
|
||
export interface IDefaultValueInputProps {
|
||
handleChange: (key: string) => (update: any) => void;
|
||
column: ColumnConfig;
|
||
}
|
||
|
||
export default function DefaultValueInput({
|
||
handleChange,
|
||
column,
|
||
}: IDefaultValueInputProps) {
|
||
const [projectSettings] = useAtom(projectSettingsAtom, projectScope);
|
||
|
||
const _type =
|
||
column.type !== FieldType.derivative
|
||
? column.type
|
||
: column.config?.renderFieldType ?? FieldType.shortText;
|
||
const [localValue, setLocalValue] = useState(
|
||
column.config?.defaultValue?.value ?? getFieldProp("initialValue", _type)
|
||
);
|
||
|
||
const customFieldInput = getFieldProp("SideDrawerField", _type);
|
||
|
||
return (
|
||
<>
|
||
<TextField
|
||
select
|
||
label="Default value type"
|
||
value={column.config?.defaultValue?.type ?? "undefined"}
|
||
onChange={(e) => handleChange("defaultValue.type")(e.target.value)}
|
||
fullWidth
|
||
sx={{ mb: 1 }}
|
||
>
|
||
<MenuItem value="undefined">
|
||
<ListItemText
|
||
primary="Undefined"
|
||
secondary="No default value. The field will not appear in the row’s corresponding Firestore document by default."
|
||
/>
|
||
</MenuItem>
|
||
<MenuItem value="null">
|
||
<ListItemText
|
||
primary="Null"
|
||
secondary={
|
||
<>
|
||
Initialise as <code>null</code>.
|
||
</>
|
||
}
|
||
/>
|
||
</MenuItem>
|
||
<MenuItem value="static">
|
||
<ListItemText
|
||
primary="Static"
|
||
secondary="Set a specific default value for all cells in this column."
|
||
/>
|
||
</MenuItem>
|
||
<MenuItem
|
||
value="dynamic"
|
||
disabled={!projectSettings.rowyRunUrl}
|
||
sx={{
|
||
"&.Mui-disabled": { opacity: 1, color: "text.disabled" },
|
||
"&.Mui-disabled .MuiListItemText-secondary": {
|
||
color: "text.disabled",
|
||
},
|
||
}}
|
||
>
|
||
<ListItemText
|
||
primary={
|
||
projectSettings.rowyRunUrl ? (
|
||
"Dynamic"
|
||
) : (
|
||
<>
|
||
Dynamic —{" "}
|
||
<Typography color="error" variant="inherit" component="span">
|
||
Requires Rowy Run setup
|
||
</Typography>
|
||
</>
|
||
)
|
||
}
|
||
secondary="Write code to set the default value using Rowy Run"
|
||
/>
|
||
</MenuItem>
|
||
</TextField>
|
||
{(!column.config?.defaultValue ||
|
||
column.config?.defaultValue.type === "undefined") && (
|
||
<>
|
||
<FormControlLabel
|
||
value="required"
|
||
label={
|
||
<>
|
||
Make this column required
|
||
<Typography
|
||
variant="caption"
|
||
color="text.secondary"
|
||
display="block"
|
||
>
|
||
The row will not be created or updated unless all required
|
||
values are set.
|
||
</Typography>
|
||
</>
|
||
}
|
||
control={
|
||
<Checkbox
|
||
checked={column.config?.required}
|
||
onChange={(e) => handleChange("required")(e.target.checked)}
|
||
name="required"
|
||
/>
|
||
}
|
||
/>
|
||
</>
|
||
)}
|
||
{column.config?.defaultValue?.type === "static" &&
|
||
customFieldInput &&
|
||
createElement(customFieldInput, {
|
||
column,
|
||
_rowy_ref: {},
|
||
value: localValue,
|
||
onChange: setLocalValue,
|
||
onSubmit: () => handleChange("defaultValue.value")(localValue),
|
||
disabled: false,
|
||
})}
|
||
|
||
{column.config?.defaultValue?.type === "dynamic" && (
|
||
<>
|
||
<CodeEditorHelper
|
||
docLink={WIKI_LINKS.howToDefaultValues}
|
||
additionalVariables={[
|
||
{
|
||
key: "row",
|
||
description: `row has the value of doc.data() it has type definitions using this table's schema, but you can access any field in the document.`,
|
||
},
|
||
{
|
||
key: "ref",
|
||
description: `reference object that represents the reference to the current row in firestore db (ie: doc.ref).`,
|
||
},
|
||
]}
|
||
/>
|
||
<Suspense fallback={<FieldSkeleton height={100} />}>
|
||
<CodeEditor
|
||
column={column}
|
||
type={column.type}
|
||
handleChange={handleChange}
|
||
/>
|
||
</Suspense>
|
||
</>
|
||
)}
|
||
</>
|
||
);
|
||
}
|