diff --git a/www/src/components/ColumnDrawer.tsx b/www/src/components/ColumnDrawer.tsx deleted file mode 100644 index d0c84d79..00000000 --- a/www/src/components/ColumnDrawer.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import React, { useState, useEffect } from "react"; -import _camelCase from "lodash/camelCase"; - -import makeStyles from "@material-ui/core/styles/makeStyles"; -import createStyles from "@material-ui/core/styles/createStyles"; -import Drawer from "@material-ui/core/Drawer"; -import List from "@material-ui/core/List"; -import Divider from "@material-ui/core/Divider"; -import ListItem from "@material-ui/core/ListItem"; -import ListItemIcon from "@material-ui/core/ListItemIcon"; -import ListItemText from "@material-ui/core/ListItemText"; -import IconButton from "@material-ui/core/IconButton"; -import TextField from "@material-ui/core/TextField"; - -import AddIcon from "@material-ui/icons/Add"; - -import { FIELDS } from "constants/fields"; - -const useStyles = makeStyles(() => - createStyles({ - list: { - width: 250, - }, - fields: { - paddingLeft: 15, - - paddingRight: 15, - }, - - fullList: { - width: "auto", - }, - }) -); - -// TODO: Create an interface for props -export default function ColumnDrawer(props: any) { - const { addColumn, columns } = props; - const classes = useStyles(); - const [drawerState, toggleDrawer] = useState(false); - const [columnName, setColumnName] = useState(""); - const [fieldName, setFieldName] = useState(""); - useEffect(() => { - setFieldName(_camelCase(columnName)); - }, [columnName]); - const drawer = () => ( -
{ - // toggleDrawer(false); - }} - > - - { - setColumnName(e.target.value); - }} - margin="dense" - id="name" - label="Column Name" - type="text" - fullWidth - /> - { - setFieldName(e.target.value); - }} - margin="dense" - id="field" - label="Field Name" - type="text" - fullWidth - /> - - - - {FIELDS.map((field: any) => ( - { - addColumn(columnName, fieldName, field.type); - }} - key={field.type} - > - {field.icon} - - - ))} - -
- ); - - return ( -
- { - toggleDrawer(true); - }} - > - - - - { - toggleDrawer(false); - }} - > - {drawer()} - -
- ); -} diff --git a/www/src/components/DatePicker/Context.ts b/www/src/components/DatePicker/Context.ts deleted file mode 100644 index 5ca7e683..00000000 --- a/www/src/components/DatePicker/Context.ts +++ /dev/null @@ -1,8 +0,0 @@ -import React, { useContext } from "react"; -import { IDatePicker, DATE_PICKER_EMPTY_STATE } from "./props"; -const DatePickerContext = React.createContext( - DATE_PICKER_EMPTY_STATE -); -export default DatePickerContext; - -export const useDatePicker = () => useContext(DatePickerContext); diff --git a/www/src/components/DatePicker/Dialog.tsx b/www/src/components/DatePicker/Dialog.tsx deleted file mode 100644 index 346c39a7..00000000 --- a/www/src/components/DatePicker/Dialog.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React from "react"; -import clsx from "clsx"; - -import { useDebouncedCallback } from "use-debounce"; - -import { makeStyles, createStyles } from "@material-ui/core"; -import DateRangeIcon from "@material-ui/icons/DateRange"; -import TimeIcon from "@material-ui/icons/Schedule"; - -import { FieldType, DateIcon, DateTimeIcon } from "constants/fields"; -import { DATE_FORMAT, DATE_TIME_FORMAT } from "constants/dates"; - -import DateFnsUtils from "@date-io/date-fns"; -import { - MuiPickersUtilsProvider, - KeyboardDatePicker, - KeyboardDateTimePicker, - DatePickerProps, -} from "@material-ui/pickers"; - -import { useFiretableContext } from "contexts/FiretableContext"; - -const useStyles = makeStyles((theme) => - createStyles({ - root: { - height: "100%", - }, - inputBase: { height: "100%" }, - - inputAdornment: { - height: "100%", - marginLeft: theme.spacing(1) + 1, - marginRight: theme.spacing(0.25), - }, - - input: { - ...theme.typography.body2, - fontSize: "0.75rem", - color: theme.palette.text.secondary, - height: "100%", - padding: theme.spacing(1.5, 0), - }, - - dateTabIcon: { - color: theme.palette.primary.contrastText, - }, - }) -); - -export default function Date({ rowIdx, column, value, onSubmit }: any) { - const classes = useStyles(); - const { dataGridRef } = useFiretableContext(); - - const transformedValue = - value && typeof value !== "number" && "toDate" in value - ? value.toDate() - : null; - - const fieldType = (column as any).type; - const Picker = - fieldType === FieldType.date ? KeyboardDatePicker : KeyboardDateTimePicker; - const Icon = fieldType === FieldType.date ? DateIcon : DateTimeIcon; - - const [handleDateChange] = useDebouncedCallback( - (date) => { - if (isNaN(date?.valueOf() ?? 0)) return; - - onSubmit(date); - if (dataGridRef?.current?.selectCell) - dataGridRef.current.selectCell({ rowIdx, idx: column.idx }); - }, - 500 - ); - - return ( - - e.stopPropagation()} - format={fieldType === FieldType.date ? DATE_FORMAT : DATE_TIME_FORMAT} - fullWidth - clearable - keyboardIcon={} - className={clsx("cell-collapse-padding", classes.root)} - inputVariant="standard" - InputProps={{ - disableUnderline: true, - classes: { root: classes.inputBase, input: classes.input }, - }} - InputAdornmentProps={{ - position: "start", - classes: { root: classes.inputAdornment }, - }} - KeyboardButtonProps={{ - size: "small", - classes: { root: "row-hover-iconButton" }, - }} - DialogProps={{ onClick: (e) => e.stopPropagation() }} - dateRangeIcon={} - timeIcon={} - /> - - ); -} diff --git a/www/src/components/DatePicker/Provider.tsx b/www/src/components/DatePicker/Provider.tsx deleted file mode 100644 index 61a7be52..00000000 --- a/www/src/components/DatePicker/Provider.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { useState, lazy, Suspense } from "react"; - -import { datePickerProps } from "./props"; -const Dialog = lazy( - () => import("./Dialog" /* webpackChunkName: "DatePickerDialog" */) -); -import ConfirmationContext from "./Context"; -interface IConfirmationProviderProps { - children: React.ReactNode; -} - -const ConfirmationProvider: React.FC = ({ - children, -}) => { - const [state, setState] = useState(); - const [open, setOpen] = useState(false); - const handleClose = () => { - setState(undefined); - setOpen(false); - }; - const setDate = (props: datePickerProps) => { - setState(props); - setOpen(true); - }; - return ( - - {children} - - - - - - ); -}; - -export default ConfirmationProvider; diff --git a/www/src/components/DatePicker/index.ts b/www/src/components/DatePicker/index.ts deleted file mode 100644 index b520ae6f..00000000 --- a/www/src/components/DatePicker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useDatePicker } from "./Context"; diff --git a/www/src/components/DatePicker/props.ts b/www/src/components/DatePicker/props.ts deleted file mode 100644 index 7255f5f7..00000000 --- a/www/src/components/DatePicker/props.ts +++ /dev/null @@ -1,24 +0,0 @@ -export type datePickerProps = - | { - title?: string; - customBody?: string; - body?: string; - cancel?: string; - confirm?: string | JSX.Element; - confirmationCommand?: string; - handleConfirm: () => void; - open?: Boolean; - } - | undefined; -export interface IDatePicker { - props?: datePickerProps; - handleClose: () => void; - open: boolean; - setDate: (props: datePickerProps) => void; -} -export const DATE_PICKER_EMPTY_STATE = { - props: undefined, - open: false, - handleClose: () => {}, - setDate: () => {}, -}; diff --git a/www/src/components/SideDrawer/Form/FieldWrapper.tsx b/www/src/components/SideDrawer/Form/FieldWrapper.tsx index 562763d0..43c7b318 100644 --- a/www/src/components/SideDrawer/Form/FieldWrapper.tsx +++ b/www/src/components/SideDrawer/Form/FieldWrapper.tsx @@ -14,7 +14,8 @@ import LockIcon from "@material-ui/icons/Lock"; import ErrorBoundary from "components/ErrorBoundary"; import FieldSkeleton from "./FieldSkeleton"; -import { FieldType, getFieldIcon } from "constants/fields"; +import { FieldType } from "constants/fields"; +import { getFieldProp } from "components/fields"; const useStyles = makeStyles((theme) => createStyles({ @@ -68,7 +69,7 @@ export default function FieldWrapper({ htmlFor={`sidedrawer-field-${name}`} > - {type === "debug" ? : getFieldIcon(type)} + {type === "debug" ? : getFieldProp("icon", type)} {label} diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 66f6b9e5..fbf0198e 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -24,11 +24,11 @@ import TypeChange from "./TypeChange"; import Settings from "./Settings"; import { useFiretableContext } from "contexts/FiretableContext"; -import { FIELDS, FieldType } from "constants/fields"; +import { FieldType } from "constants/fields"; +import { getFieldProp } from "components/fields"; import _find from "lodash/find"; import { Column } from "react-data-grid"; import { PopoverProps } from "@material-ui/core"; -import { getFieldProp } from "components/fields"; const INITIAL_MODAL = { type: "", data: {} }; @@ -218,7 +218,7 @@ export default function ColumnMenu() { { label: `Edit Type: ${getFieldProp("name", column.type)}`, // This is based off the cell type - icon: _find(FIELDS, { type: column.type })?.icon, + icon: getFieldProp("icon", column.type), onClick: () => { setModal({ type: ModalStates.typeChange, data: { column } }); }, diff --git a/www/src/components/Wizards/Column.tsx b/www/src/components/Wizards/Column.tsx index 762234c8..704f970e 100644 --- a/www/src/components/Wizards/Column.tsx +++ b/www/src/components/Wizards/Column.tsx @@ -10,7 +10,8 @@ import { } from "@material-ui/core"; import { fade } from "@material-ui/core/styles"; -import { FieldType, getFieldIcon } from "constants/fields"; +import { FieldType } from "constants/fields"; +import { getFieldProp } from "components/fields"; const useStyles = makeStyles((theme) => createStyles({ @@ -88,7 +89,7 @@ export default function Column({ {...props} className={clsx(classes.root, active && classes.active, props.className)} > - {type && {getFieldIcon(type)}} + {type && {getFieldProp("icon", type)}} createStyles({ diff --git a/www/src/components/fields/File/index.tsx b/www/src/components/fields/File/index.tsx index ae0bacd7..16aaf1b0 100644 --- a/www/src/components/fields/File/index.tsx +++ b/www/src/components/fields/File/index.tsx @@ -27,3 +27,5 @@ export const config: IFieldConfig = { SideDrawerField, }; export default config; + +export { FileIcon }; diff --git a/www/src/components/fields/Id/index.tsx b/www/src/components/fields/Id/index.tsx index b5cad6c6..64c2ccc2 100644 --- a/www/src/components/fields/Id/index.tsx +++ b/www/src/components/fields/Id/index.tsx @@ -15,7 +15,7 @@ const SideDrawerField = lazy( export const config: IFieldConfig = { type: FieldType.id, - name: "Id", + name: "ID", dataType: "undefined", initialValue: undefined, icon: , diff --git a/www/src/components/fields/Image/SideDrawerField.tsx b/www/src/components/fields/Image/SideDrawerField.tsx index 543666b7..979925aa 100644 --- a/www/src/components/fields/Image/SideDrawerField.tsx +++ b/www/src/components/fields/Image/SideDrawerField.tsx @@ -21,7 +21,7 @@ import AddIcon from "@material-ui/icons/AddAPhoto"; import DeleteIcon from "@material-ui/icons/Delete"; import OpenIcon from "@material-ui/icons/OpenInNewOutlined"; -import { IMAGE_MIME_TYPES } from "constants/fields"; +import { IMAGE_MIME_TYPES } from "."; import Thumbnail from "components/Thumbnail"; import { useConfirmation } from "components/ConfirmationDialog"; diff --git a/www/src/constants/fields.ts b/www/src/constants/fields.ts new file mode 100644 index 00000000..ace2ca77 --- /dev/null +++ b/www/src/constants/fields.ts @@ -0,0 +1,42 @@ +// Define field type strings used in Firetable column config +export enum FieldType { + // TEXT + shortText = "SIMPLE_TEXT", + longText = "LONG_TEXT", + email = "EMAIL", + phone = "PHONE_NUMBER", + url = "URL", + // NUMERIC + checkbox = "CHECK_BOX", + number = "NUMBER", + percentage = "PERCENTAGE", + rating = "RATING", + slider = "SLIDER", + color = "COLOR", + // DATE & TIME + date = "DATE", + dateTime = "DATE_TIME", + duration = "DURATION", + // FILE + image = "IMAGE", + file = "FILE", + // SELECT + singleSelect = "SINGLE_SELECT", + multiSelect = "MULTI_SELECT", + // CONNECTION + subTable = "SUB_TABLE", + connectTable = "DOCUMENT_SELECT", + connectService = "SERVICE_SELECT", + // CODE + json = "JSON", + code = "CODE", + richText = "RICH_TEXT", + // CLOUD FUNCTION + action = "ACTION", + derivative = "DERIVATIVE", + aggregate = "AGGREGATE", + // FIRETABLE + user = "USER", + id = "ID", + last = "LAST", +} diff --git a/www/src/constants/fields.tsx b/www/src/constants/fields.tsx deleted file mode 100644 index de4b90c0..00000000 --- a/www/src/constants/fields.tsx +++ /dev/null @@ -1,264 +0,0 @@ -import React from "react"; -import propEq from "ramda/es/propEq"; -import find from "ramda/es/find"; - -import ShortTextIcon from "@material-ui/icons/ShortText"; -import LongTextIcon from "@material-ui/icons/Notes"; -import EmailIcon from "@material-ui/icons/Mail"; -import PhoneIcon from "@material-ui/icons/Phone"; - -import CheckboxIcon from "@material-ui/icons/CheckBox"; -import NumberIcon from "assets/icons/Number"; -import PercentageIcon from "assets/icons/Percentage"; - -import DateIcon from "@material-ui/icons/Today"; -import DateTimeIcon from "@material-ui/icons/AccessTime"; -import DurationIcon from "@material-ui/icons/Timer"; - -import UrlIcon from "@material-ui/icons/Link"; -import RatingIcon from "@material-ui/icons/StarBorder"; - -import ImageIcon from "@material-ui/icons/PhotoSizeSelectActual"; -import FileIcon from "@material-ui/icons/AttachFile"; - -import SingleSelectIcon from "@material-ui/icons/FormatListBulleted"; -import MultiSelectIcon from "assets/icons/MultiSelect"; - -import SubTableIcon from "assets/icons/SubTable"; -import ConnectTableIcon from "assets/icons/ConnectTable"; -import ConnectServiceIcon from "@material-ui/icons/Http"; - -import JsonIcon from "assets/icons/Json"; -import CodeIcon from "@material-ui/icons/Code"; -import RichTextIcon from "@material-ui/icons/TextFormat"; - -import ActionIcon from "assets/icons/Action"; -import DerivativeIcon from "assets/icons/Derivative"; -import AggregateIcon from "@material-ui/icons/Layers"; - -import ColorIcon from "@material-ui/icons/Colorize"; -import SliderIcon from "assets/icons/Slider"; - -import UserIcon from "@material-ui/icons/Person"; -import IdIcon from "assets/icons/Id"; - -export { - ShortTextIcon, - LongTextIcon, - EmailIcon, - PhoneIcon, - CheckboxIcon, - NumberIcon, - PercentageIcon, - DateIcon, - DateTimeIcon, - DurationIcon, - UrlIcon, - RatingIcon, - ImageIcon, - FileIcon, - SingleSelectIcon, - MultiSelectIcon, - SubTableIcon, - ConnectTableIcon, - ConnectServiceIcon, - JsonIcon, - CodeIcon, - RichTextIcon, - ActionIcon, - DerivativeIcon, - AggregateIcon, - ColorIcon, - SliderIcon, - UserIcon, - IdIcon, -}; - -// Define field type strings used in Firetable column config -export enum FieldType { - // TEXT - shortText = "SIMPLE_TEXT", - longText = "LONG_TEXT", - email = "EMAIL", - phone = "PHONE_NUMBER", - url = "URL", - // NUMERIC - checkbox = "CHECK_BOX", - number = "NUMBER", - percentage = "PERCENTAGE", - rating = "RATING", - slider = "SLIDER", - color = "COLOR", - // DATE & TIME - date = "DATE", - dateTime = "DATE_TIME", - duration = "DURATION", - // FILE - image = "IMAGE", - file = "FILE", - // SELECT - singleSelect = "SINGLE_SELECT", - multiSelect = "MULTI_SELECT", - // CONNECTION - subTable = "SUB_TABLE", - connectTable = "DOCUMENT_SELECT", - connectService = "SERVICE_SELECT", - // CODE - json = "JSON", - code = "CODE", - richText = "RICH_TEXT", - // CLOUD FUNCTION - action = "ACTION", - derivative = "DERIVATIVE", - aggregate = "AGGREGATE", - // FIRETABLE - user = "USER", - id = "ID", - last = "LAST", -} - -export const FIELDS = [ - { icon: , name: "Short Text", type: FieldType.shortText }, - { icon: , name: "Long Text", type: FieldType.longText }, - { icon: , name: "Email", type: FieldType.email }, - { icon: , name: "Phone", type: FieldType.phone }, - - { icon: , name: "Checkbox", type: FieldType.checkbox }, - { icon: , name: "Number", type: FieldType.number }, - { icon: , name: "Percentage", type: FieldType.percentage }, - - { icon: , name: "Date", type: FieldType.date }, - { icon: , name: "Time & Date", type: FieldType.dateTime }, - { icon: , name: "Duration", type: FieldType.duration }, - - { icon: , name: "URL", type: FieldType.url }, - { icon: , name: "Rating", type: FieldType.rating }, - - { icon: , name: "Image", type: FieldType.image }, - { icon: , name: "File", type: FieldType.file }, - - { - icon: , - name: "Single Select", - type: FieldType.singleSelect, - }, - { - icon: , - name: "Multi Select", - type: FieldType.multiSelect, - }, - - { - icon: , - name: "Sub-Table", - type: FieldType.subTable, - }, - { - icon: , - name: "Connect Table", - type: FieldType.connectTable, - }, - { - icon: , - name: "Connect Service", - type: FieldType.connectService, - }, - - { icon: , name: "JSON", type: FieldType.json }, - { icon: , name: "Code", type: FieldType.code }, - { icon: , name: "Rich Text", type: FieldType.richText }, - - { icon: , name: "Action", type: FieldType.action }, - { icon: , name: "Derivative", type: FieldType.derivative }, - { icon: , name: "Aggregate", type: FieldType.aggregate }, - - { icon: , name: "Color", type: FieldType.color }, - { icon: , name: "Slider", type: FieldType.slider }, - - { icon: , name: "User", type: FieldType.user }, - { icon: , name: "ID", type: FieldType.id }, -]; - -export const FIELD_TYPE_DESCRIPTIONS = { - [FieldType.shortText]: "Small amount of text, such as names and taglines.", - [FieldType.longText]: - "Large amount of text, such as sentences and paragraphs.", - [FieldType.email]: "Email address. Firetable does not validate emails.", - [FieldType.phone]: - "Phone numbers stored as text. Firetable does not validate phone numbers.", - - [FieldType.checkbox]: "Either checked or unchecked. Unchecked by default.", - [FieldType.number]: "Numeric data.", - [FieldType.percentage]: "Percentage stored as a number between 0 and 1.", - - [FieldType.date]: - "Date displayed and input as YYYY/MM/DD or input using a picker module.", - [FieldType.dateTime]: - "Time and Date can be written as YYYY/MM/DD hh:mm (am/pm) or input using a picker module.", - [FieldType.duration]: "Duration calculated from two timestamps.", - - [FieldType.url]: "Web address. Firetable does not validate URLs.", - [FieldType.rating]: - "Rating displayed as stars from 0 to configurable number of stars. Default: 5 stars.", - - [FieldType.image]: - "Image file uploaded to Firebase Storage. Supports JPEG, PNG, SVG, GIF, WebP.", - [FieldType.file]: - "File uploaded to Firebase Storage. Supports any file type.", - - [FieldType.singleSelect]: - "Dropdown selector with searchable options and radio button behavior. Optionally allows users to input custom values. Max selection: 1 option.", - [FieldType.multiSelect]: - "Dropdown selector with searchable options and check box behavior. Optionally allows users to input custom values. Max selection: all options.", - - [FieldType.subTable]: - "Creates a sub-table. Also displays number of rows inside the sub-table. Max sub-table levels: 100.", - [FieldType.connectTable]: - "Connects to an existing table to fetch a snapshot of values from a row. Requires Algolia integration.", - [FieldType.connectService]: - "Select a value from a list of external web service results.", - - [FieldType.json]: "JSON object editable with a visual JSON editor.", - [FieldType.code]: "Raw code editable with Monaco Editor.", - [FieldType.richText]: "Rich text editor with predefined HTML text styles.", - - [FieldType.action]: - "A button with a pre-defined action. Triggers a Cloud Function. 3 different states: Disabled, Enabled, Active (Clicked). Supports Undo and Redo.", - [FieldType.derivative]: - "Value derived from the rest of the row’s values. Displayed using any other field type. Requires Cloud Function setup.", - [FieldType.aggregate]: - "Value aggregated from a specified sub-table of the row. Displayed using any other field type. Requires Cloud Function setup.", - - [FieldType.color]: "Visual color picker. Supports Hex, RGBA, HSLA.", - [FieldType.slider]: "Slider with adjustable range. Returns a numeric value.", - - [FieldType.user]: "Displays the _ft_updatedBy field for editing history.", - [FieldType.id]: "Displays the row’s document ID. Cannot be sorted.", - [FieldType.last]: "Internally used to display last column with row actions.", -}; - -/** - * Returns icon associated with field type - * @param fieldType - */ -export const getFieldIcon = (fieldType: FieldType) => { - const field: any = find(propEq("type", fieldType))(FIELDS); - return field.icon; -}; - -/** - * Returns `true` if it receives an existing fieldType - * @param fieldType - */ -export const isFieldType = (fieldType: any) => { - const fieldTypes = FIELDS.map((field) => field.type); - return fieldTypes.includes(fieldType); -}; - -export const IMAGE_MIME_TYPES = [ - "image/jpeg", - "image/png", - "image/svg+xml", - "image/gif", - "image/webp", -];