mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
create columns,column settings flags toggles setup
This commit is contained in:
15
ROADMAP.md
15
ROADMAP.md
@@ -18,7 +18,7 @@
|
||||
- Create columns (fields) ✅
|
||||
- Create rows(documents) ✅
|
||||
- Edit cells ✅
|
||||
- Authenicate ✅
|
||||
- Authenticate ✅
|
||||
- Delete rows ✅
|
||||
|
||||
## MVP
|
||||
@@ -27,12 +27,12 @@
|
||||
|
||||
- single select(string)
|
||||
- [https://material-ui.com/components/chips/#chip-array] Multiple select(array of strings)
|
||||
- date(Firebase timestamp)
|
||||
- time(Firebase timestamp)
|
||||
- date(Firebase timestamp)✅
|
||||
- time(Firebase timestamp)✅
|
||||
- file(firebase storage url string)
|
||||
- image(firebase storage url string)
|
||||
- single select reference(DocRefrence)
|
||||
- mulit select reference(DocRefrence)
|
||||
- single select reference(DocReference)
|
||||
- multi select reference(DocReference)
|
||||
- rating ✅
|
||||
|
||||
### Functionality:
|
||||
@@ -44,10 +44,11 @@
|
||||
- Edit tables
|
||||
- Hide tables
|
||||
- Fixed column
|
||||
- resizable column ✅
|
||||
- keyboard Navigation:
|
||||
- Up key to move to the cell above ✅
|
||||
- Down key to move to the cell bellow, if last cell create a new row ✅
|
||||
- Tab to go to the next cell
|
||||
- Tab to go to the next cell ✅
|
||||
- column / table Create/edit validation
|
||||
|
||||
## V1
|
||||
@@ -64,7 +65,7 @@
|
||||
- Sort rows
|
||||
- Locked columns
|
||||
- Table view only mode
|
||||
- Subcollection tables
|
||||
- SubCollection tables
|
||||
- Permissions
|
||||
- Duplicate columns
|
||||
- Filters:
|
||||
|
||||
@@ -4,13 +4,13 @@ import MuiRating from "@material-ui/lab/Rating";
|
||||
// TODO: Create an interface for props
|
||||
|
||||
interface Props {
|
||||
value: number | null;
|
||||
value: number;
|
||||
row: any;
|
||||
onSubmit: Function;
|
||||
//fieldType: FieldType;
|
||||
}
|
||||
const Rating = (props: Props) => {
|
||||
const { value, row, onSubmit } = props;
|
||||
|
||||
return (
|
||||
<MuiRating
|
||||
// TODO: make it unique for each
|
||||
|
||||
@@ -13,6 +13,8 @@ import URLIcon from "@material-ui/icons/Explore";
|
||||
import NumberIcon from "@material-ui/icons/Looks3";
|
||||
import propEq from "ramda/es/propEq";
|
||||
import find from "ramda/es/find";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
export enum FieldType {
|
||||
simpleText = "SIMPLE_TEXT",
|
||||
longText = "LONG_TEXT",
|
||||
@@ -46,3 +48,31 @@ export const FIELDS = [
|
||||
export const getFieldIcon = (type: FieldType) => {
|
||||
return find(propEq("type", type))(FIELDS).icon;
|
||||
};
|
||||
|
||||
export const isFieldType = (fieldType: any) => {
|
||||
const fieldTypes = FIELDS.map(field => field.type);
|
||||
return fieldTypes.includes(fieldType);
|
||||
};
|
||||
|
||||
export const FieldsDropDown = (value: FieldType | null, onChange: any) => {
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
inputProps={{
|
||||
name: "type",
|
||||
id: "type",
|
||||
}}
|
||||
>
|
||||
{FIELDS.map(
|
||||
(field: { icon: JSX.Element; name: string; type: FieldType }) => {
|
||||
return (
|
||||
<MenuItem id={`select-field-${field.type}`} value={field.type}>
|
||||
<>{field.name}</>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import FormHelperText from "@material-ui/core/FormHelperText";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import Select from "@material-ui/core/Select";
|
||||
|
||||
import Popper from "@material-ui/core/Popper";
|
||||
import Fade from "@material-ui/core/Fade";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import ClickAwayListener from "@material-ui/core/ClickAwayListener";
|
||||
import { createStyles, Theme, makeStyles } from "@material-ui/core/styles";
|
||||
import { createStyles, makeStyles } from "@material-ui/core/styles";
|
||||
import { TextField, Grid } from "@material-ui/core";
|
||||
import { FIELDS } from "../Fields";
|
||||
import { FieldsDropDown, isFieldType } from "../Fields";
|
||||
import ToggleButton from "@material-ui/lab/ToggleButton";
|
||||
import ToggleButtonGroup from "@material-ui/lab/ToggleButtonGroup";
|
||||
|
||||
import LockIcon from "@material-ui/icons/Lock";
|
||||
import LockOpenIcon from "@material-ui/icons/LockOpen";
|
||||
import VisibilityIcon from "@material-ui/icons/Visibility";
|
||||
import VisibilityOffIcon from "@material-ui/icons/VisibilityOff";
|
||||
import FormatItalicIcon from "@material-ui/icons/FormatItalic";
|
||||
import FormatUnderlinedIcon from "@material-ui/icons/FormatUnderlined";
|
||||
import FormatColorFillIcon from "@material-ui/icons/FormatColorFill";
|
||||
|
||||
const useStyles = makeStyles(Theme =>
|
||||
createStyles({
|
||||
container: {
|
||||
padding: 10,
|
||||
padding: 15,
|
||||
},
|
||||
typography: {
|
||||
padding: 1,
|
||||
@@ -41,17 +52,29 @@ const useStyles = makeStyles(Theme =>
|
||||
selectEmpty: {
|
||||
marginTop: Theme.spacing(2),
|
||||
},
|
||||
toggleGrouped: {
|
||||
margin: Theme.spacing(0.5),
|
||||
border: "none",
|
||||
padding: Theme.spacing(0, 1),
|
||||
"&:not(:first-child)": {
|
||||
borderRadius: Theme.shape.borderRadius,
|
||||
},
|
||||
"&:first-child": {
|
||||
borderRadius: Theme.shape.borderRadius,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const HeaderPopper = (props: any) => {
|
||||
const { anchorEl, column, handleClose } = props;
|
||||
console.log(column);
|
||||
const { anchorEl, column, handleClose, actions } = props;
|
||||
const [values, setValues] = React.useState({
|
||||
age: "",
|
||||
name: "hai",
|
||||
type: null,
|
||||
name: "",
|
||||
});
|
||||
console.log(props);
|
||||
const [flags, setFlags] = React.useState(() => [""]);
|
||||
const classes = useStyles();
|
||||
|
||||
function handleChange(
|
||||
event: React.ChangeEvent<{ name?: string; value: unknown }>
|
||||
) {
|
||||
@@ -60,10 +83,45 @@ const HeaderPopper = (props: any) => {
|
||||
[event.target.name as string]: event.target.value,
|
||||
}));
|
||||
}
|
||||
console.log(column);
|
||||
const setValue = (key: string, value: any) => {
|
||||
setValues(oldValues => ({
|
||||
...oldValues,
|
||||
[key]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (column && !column.isNew)
|
||||
setValues(oldValues => ({
|
||||
...oldValues,
|
||||
name: column.name,
|
||||
type: column.type,
|
||||
key: column.key,
|
||||
isNew: column.isNew,
|
||||
}));
|
||||
}, [column]);
|
||||
const onClickAway = (event: any) => {
|
||||
const dropDownClicked = isFieldType(event.target.dataset.value);
|
||||
if (!dropDownClicked) {
|
||||
handleClose();
|
||||
}
|
||||
};
|
||||
const handleToggle = (
|
||||
event: React.MouseEvent<HTMLElement>,
|
||||
newFlags: string[]
|
||||
) => {
|
||||
setFlags(newFlags);
|
||||
};
|
||||
|
||||
const createNewColumn = () => {
|
||||
const { name, type } = values;
|
||||
actions.add(name, type);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
if (column) {
|
||||
return (
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<ClickAwayListener onClickAway={onClickAway}>
|
||||
<Popper
|
||||
id={`id-${column.name}`}
|
||||
open={!!anchorEl}
|
||||
@@ -74,26 +132,51 @@ const HeaderPopper = (props: any) => {
|
||||
<Fade {...TransitionProps} timeout={350}>
|
||||
<Paper className={classes.container}>
|
||||
<Grid container direction="column">
|
||||
<TextField label="Column name" defaultValue={column.name} />
|
||||
<ToggleButtonGroup
|
||||
size="small"
|
||||
value={flags}
|
||||
className={classes.toggleGrouped}
|
||||
onChange={handleToggle}
|
||||
arial-label="column settings"
|
||||
>
|
||||
<ToggleButton value="editable" aria-label="bold">
|
||||
{flags.includes("editable") ? (
|
||||
<LockOpenIcon />
|
||||
) : (
|
||||
<LockIcon />
|
||||
)}
|
||||
</ToggleButton>
|
||||
<ToggleButton value="visible" aria-label="italic">
|
||||
{flags.includes("visible") ? (
|
||||
<VisibilityIcon />
|
||||
) : (
|
||||
<VisibilityOffIcon />
|
||||
)}
|
||||
</ToggleButton>
|
||||
<ToggleButton value="freeze" aria-label="underlined">
|
||||
<FormatUnderlinedIcon />
|
||||
</ToggleButton>
|
||||
<ToggleButton value="resize" aria-label="color">
|
||||
<FormatColorFillIcon />
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
|
||||
<TextField
|
||||
label="Column name"
|
||||
name="name"
|
||||
defaultValue={values.name}
|
||||
// onChange={handleChange}
|
||||
onChange={e => {
|
||||
setValue("name", e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<FormControl className={classes.formControl}>
|
||||
<InputLabel htmlFor="age-simple">Field Type</InputLabel>
|
||||
<Select
|
||||
value={column.type}
|
||||
onChange={handleChange}
|
||||
inputProps={{
|
||||
name: "age",
|
||||
id: "age-simple",
|
||||
}}
|
||||
>
|
||||
{FIELDS.map((field: any) => {
|
||||
return (
|
||||
<MenuItem value={field.type}>
|
||||
{field.icon} {field.name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<Button>Add</Button>
|
||||
<InputLabel htmlFor="Field-select">Field Type</InputLabel>
|
||||
{FieldsDropDown(values.type, handleChange)}
|
||||
{column.isNew && (
|
||||
<Button onClick={createNewColumn}>Add</Button>
|
||||
)}
|
||||
<Button color="secondary" onClick={handleClose}>
|
||||
cancel
|
||||
</Button>
|
||||
|
||||
@@ -67,7 +67,13 @@ const formatter = (fieldType: FieldType, key: string) => {
|
||||
return DateFormatter(key, fieldType);
|
||||
case FieldType.rating:
|
||||
return (props: any) => {
|
||||
return <Rating {...props} onSubmit={onSubmit(key)} />;
|
||||
return (
|
||||
<Rating
|
||||
{...props}
|
||||
onSubmit={onSubmit(key)}
|
||||
value={typeof props.value === "number" ? props.value : 0}
|
||||
/>
|
||||
);
|
||||
};
|
||||
case FieldType.checkBox:
|
||||
return (props: any) => {
|
||||
@@ -112,23 +118,31 @@ function Table(props: any) {
|
||||
console.log(args);
|
||||
};
|
||||
const headerRenderer = (props: any) => {
|
||||
switch (props.column.key) {
|
||||
const { column } = props;
|
||||
switch (column.key) {
|
||||
case "new":
|
||||
return (
|
||||
<Button onClick={handleClick(props)} className={classes.header}>
|
||||
{props.column.name}
|
||||
</Button>
|
||||
<div className={classes.header}>
|
||||
<Button
|
||||
onClick={handleClick(props)}
|
||||
style={{ width: column.width }}
|
||||
>
|
||||
{column.name}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<div className={classes.header}>
|
||||
<Button
|
||||
style={{ width: column.width }}
|
||||
className={classes.headerButton}
|
||||
onClick={handleClick(props)}
|
||||
aria-label="edit"
|
||||
>
|
||||
{getFieldIcon(props.column.type)}
|
||||
{props.column.name} <EditIcon />
|
||||
{props.column.name}
|
||||
{/* <EditIcon /> */}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
@@ -148,6 +162,7 @@ function Table(props: any) {
|
||||
...column,
|
||||
}));
|
||||
columns.push({
|
||||
isNew: true,
|
||||
key: "new",
|
||||
name: "Add column",
|
||||
width: 160,
|
||||
@@ -174,6 +189,7 @@ function Table(props: any) {
|
||||
handleClose={handleCloseHeader}
|
||||
anchorEl={anchorEl}
|
||||
column={header && header.column}
|
||||
actions={tableActions.column}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect } from "react";
|
||||
import useDoc, { DocActions } from "../useDoc";
|
||||
import { FieldType } from "../../components/Fields";
|
||||
import _camelCase from "lodash/camelCase";
|
||||
const useTableConfig = (tablePath: string) => {
|
||||
const [tableConfigState, documentDispatch] = useDoc({
|
||||
path: `${tablePath}/_FIRETABLE_`,
|
||||
@@ -14,8 +15,10 @@ const useTableConfig = (tablePath: string) => {
|
||||
const setTable = (table: string) => {
|
||||
documentDispatch({ path: `${table}/_FIRETABLE_`, columns: [], doc: null });
|
||||
};
|
||||
const add = (name: string, key: string, type: FieldType) => {
|
||||
const add = (name: string, type: FieldType) => {
|
||||
//TODO: validation
|
||||
const { columns } = tableConfigState;
|
||||
const key = _camelCase(name);
|
||||
documentDispatch({
|
||||
action: DocActions.update,
|
||||
data: { columns: [...columns, { name, key, type }] },
|
||||
|
||||
Reference in New Issue
Block a user