这是indexloc提供的服务,不要输入任何密码
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/components/fields/Array/DisplayCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { IDisplayCellProps } from "@src/components/fields/types";
import { Link } from "react-router-dom";

import { IconButton, Stack, useTheme } from "@mui/material";
import OpenIcon from "@mui/icons-material/OpenInBrowser";

export default function Array({ value }: IDisplayCellProps) {
const theme = useTheme();

if (!value) {
return null;
}

return (
<div
style={{
width: "100%",
maxHeight: "100%",
whiteSpace: "pre-wrap",
lineHeight: theme.typography.body2.lineHeight,
fontFamily: theme.typography.fontFamilyMono,
}}
>
{JSON.stringify(value, null, 4)}
</div>
);
}
7 changes: 7 additions & 0 deletions src/components/fields/Array/Settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ISettingsProps } from "@src/components/fields/types";

const Settings = (props: ISettingsProps) => {
return null;
};

export default Settings;
233 changes: 233 additions & 0 deletions src/components/fields/Array/SideDrawerField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import { ISideDrawerFieldProps } from "@src/components/fields/types";

import {
Stack,
Box,
Button,
Select,
MenuItem,
FormControlLabel,
TextField,
Switch,
Chip,
Badge,
} from "@mui/material";
import AddIcon from "@mui/icons-material/Add";
import ClearIcon from "@mui/icons-material/Clear";

import JSONField from "@src/components/fields/Json/SideDrawerField";
import CodeEditor from "@src/components/CodeEditor";

function ArrayFieldInput({
onChange,
value,
disabled,
id,
}: {
onChange: (value: any) => void;
value: any;
disabled: boolean;
id: string;
}) {
switch (typeof value) {
case "bigint":
case "number": {
return (
<TextField
onChange={(e) => onChange(+e.target.value)}
type="number"
placeholder="Enter value"
disabled={disabled}
id={id}
/>
);
}

case "string": {
return (
<TextField
onChange={(e) => onChange(e.target.value)}
type="text"
placeholder="Enter value"
disabled={disabled}
id={id}
/>
);
}

case "boolean": {
return (
<Switch
checked={!!value}
onChange={(e) => onChange(e.target.checked)}
disabled={disabled}
id={id}
/>
);
}

case "object": {
return (
<Box sx={{ overflow: "auto", width: "100%" }}>
<CodeEditor
defaultLanguage="json"
value={JSON.stringify(value) || "{\n \n}"}
onChange={(v) => {
try {
if (v) onChange(JSON.parse(v));
} catch (e) {
console.log(`Failed to parse JSON: ${e}`);
}
}}
Comment on lines +72 to +81
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be used to add array of objects

/>
</Box>
);
}

default:
return null;
}
}

export default function ArraySideDrawerField({
column,
value,
onChange,
onSubmit,
disabled,
...props
}: ISideDrawerFieldProps) {
const handleNewField = () => {
onChange([...(value || []), ""]);
onSubmit();
};

const handleChange = (newValue: any, indexUpdated: number) => {
onChange(
[...(value || [])].map((v: any, i) => {
if (i === indexUpdated) {
return newValue;
}

return v;
})
);

onSubmit();
};

const handleChangeType = (newType: any, indexUpdated: number) => {
console.log(newType, indexUpdated);

onChange(
[...(value || [])].map((v: any, i) => {
if (i === indexUpdated) {
switch (newType) {
case "boolean": {
return true;
}
case "number": {
return 0;
}
case "string": {
return "";
}
case "object": {
return {};
}
}
}

return v;
})
);

onSubmit();
};

const handleClearField = () => {
onChange([]);
onSubmit();
};

if (!value || Array.isArray(value)) {
return (
<Stack spacing={2}>
{(value || []).map((v: any, index: number) => {
return (
<Stack
key={`array-index-${index}-field`}
spacing={1}
alignItems="start"
direction="row"
>
<FormControlLabel
sx={{ ml: 1 }}
control={
<Select
size="small"
labelId={`index-${index}-type`}
id={`index-${index}-type`}
value={typeof v}
disabled={disabled}
sx={{ width: 100 }}
onChange={(e) => handleChangeType(e.target.value, index)}
label="Type"
>
<MenuItem value="string">String</MenuItem>
<MenuItem value="number">Number</MenuItem>
<MenuItem value="boolean">Boolean</MenuItem>
<MenuItem value="object">JSON</MenuItem>
</Select>
}
label={index === 0 ? "Type" : null}
labelPlacement="top"
/>

<FormControlLabel
sx={{ width: "100%", overflow: "hidden" }}
control={
<ArrayFieldInput
value={v}
id={`index-${index}-value`}
disabled={disabled}
onChange={(newValue) => handleChange(newValue, index)}
/>
}
label={index === 0 ? "Value" : null}
labelPlacement="top"
/>
</Stack>
);
})}

<Button
sx={{ mt: 1, width: "fit-content" }}
onClick={handleNewField}
variant="contained"
color="primary"
startIcon={<AddIcon />}
>
Add field
</Button>
</Stack>
);
}

return (
<Stack>
<Box component="pre" my="0">
{JSON.stringify(value, null, 4)}
</Box>
<Button
sx={{ mt: 1, width: "fit-content" }}
onClick={handleClearField}
variant="text"
color="warning"
startIcon={<ClearIcon />}
>
Clear field
</Button>
</Stack>
);
}
33 changes: 33 additions & 0 deletions src/components/fields/Array/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { lazy } from "react";
import DataArrayIcon from "@mui/icons-material/DataArray";

import { IFieldConfig, FieldType } from "@src/components/fields/types";
import withRenderTableCell from "@src/components/Table/TableCell/withRenderTableCell";

import DisplayCell from "./DisplayCell";

const SideDrawerField = lazy(
() =>
import("./SideDrawerField" /* webpackChunkName: "SideDrawerField-Array" */)
);
const Settings = lazy(
() => import("./Settings" /* webpackChunkName: "Settings-Array" */)
);
export const config: IFieldConfig = {
type: FieldType.array,
name: "Array",
group: "Code",
dataType: "object",
initialValue: undefined,
initializable: true,
icon: <DataArrayIcon />,
settings: Settings,
description:
"Connects to a sub-table in the current row. Also displays number of rows inside the sub-table. Max sub-table depth: 100.",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need description

TableCell: withRenderTableCell(DisplayCell, SideDrawerField, "popover", {
popoverProps: { PaperProps: { sx: { p: 1, minWidth: "200px" } } },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with the popover approach because the sub-table approach opens a Modal from the bottom, and thus the user loses the context of the row since he has to close the modal to see the row and the Modal breaks the flow, IMO Popover approach seems to be simple steps to go with. Let me know I can use modal in case this isn't what we want

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can try embedding the table component inside the popover, however providing a way to configure the column schema might be more challenging

}),
SideDrawerField,
requireConfiguration: true,
};
export default config;
2 changes: 2 additions & 0 deletions src/components/fields/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import CreatedAt from "./CreatedAt";
import UpdatedAt from "./UpdatedAt";
import User from "./User";
import Id from "./Id";
import Array from "./Array";
import { ColumnConfig } from "@src/types/table";

// Export field configs in order for FieldsDropdown
Expand Down Expand Up @@ -81,6 +82,7 @@ export const FIELDS: IFieldConfig[] = [
Json,
Code,
Markdown,
Array,
/** CLOUD FUNCTION */
Action,
Derivative,
Expand Down
1 change: 1 addition & 0 deletions src/constants/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export enum FieldType {
json = "JSON",
code = "CODE",
markdown = "MARKDOWN",
array = "ARRAYS",
// CLOUD FUNCTION
action = "ACTION",
derivative = "DERIVATIVE",
Expand Down