Merge pull request #168 from AntlerVC/develop

Develop
This commit is contained in:
Shams
2020-08-23 15:37:41 +10:00
committed by GitHub
42 changed files with 1324 additions and 1475 deletions

View File

@@ -7,6 +7,8 @@ Cloud.
![Commit](https://img.shields.io/github/last-commit/AntlerVC/firetable?color=%23ed4747)
[![Discord Shield](https://discordapp.com/api/guilds/746329234720686132/widget.png?style=shield)](https://discord.gg/Vdshr9E)
### Firetable UI
Supports fields such as images, files, single/multi select, in addition to

View File

@@ -16,7 +16,7 @@ program.version("0.4.0");
const systemHealthCheck = async () => {
const versions = await terminal.getRequiredVersions();
const requiredApps = ["node", "git", "yarn", "firebase"];
requiredApps.forEach((app) => {
requiredApps.forEach(app => {
if (versions[app] === "") {
throw new Error(
chalk.red(

View File

@@ -5,7 +5,7 @@ const Spinner = CLI.Spinner;
// firetable app Regex │ firetable-app.*
function execute(command, callback) {
exec(command, function (error, stdout, stderr) {
exec(command, function(error, stdout, stderr) {
//console.log({ error, stdout, stderr });
callback(stdout);
});
@@ -17,10 +17,10 @@ module.exports.getRequiredVersions = () =>
"Checking the versions of required system packages, please wait..."
);
checkingVersionsStatus.start();
execute("git --version", function (git) {
execute("node --version", function (node) {
execute("yarn --version", function (yarn) {
execute("firebase --version", function (firebase) {
execute("git --version", function(git) {
execute("node --version", function(node) {
execute("yarn --version", function(yarn) {
execute("firebase --version", function(firebase) {
checkingVersionsStatus.stop();
resolve({
node: node ? node.match(/[0-9]*\.[0-9]*\.[0-9]/)[0] : "",
@@ -36,9 +36,9 @@ module.exports.getRequiredVersions = () =>
});
});
module.exports.getGitUser = function (callback) {
execute("git config --global user.name", function (name) {
execute("git config --global user.email", function (email) {
module.exports.getGitUser = function(callback) {
execute("git config --global user.name", function(name) {
execute("git config --global user.email", function(email) {
callback({
name: name.replace("\n", ""),
email: email.replace("\n", ""),
@@ -53,23 +53,23 @@ module.exports.cloneFiretable = () =>
"cloning the firetable repository, please wait..."
);
cloningStatus.start();
execute("git clone https://github.com/AntlerVC/firetable.git", function () {
execute("git clone https://github.com/AntlerVC/firetable.git", function() {
cloningStatus.stop();
const installingPackagesStatus = new Spinner("installing packages");
installingPackagesStatus.start();
execute("cd firetable/www;yarn;", function (results) {
execute("cd firetable/www;yarn;", function(results) {
installingPackagesStatus.stop();
resolve(results);
});
});
});
module.exports.setFiretableENV = (envVariables) =>
module.exports.setFiretableENV = envVariables =>
new Promise((resolve, reject) => {
const status = new Spinner("setting environment variables, please wait...");
status.start();
const command = `cd firetable/www;node createDotEnv ${envVariables.projectId} ${envVariables.firebaseWebApiKey} ${envVariables.algoliaAppId} ${envVariables.algoliaSearchKey}`;
execute(command, function () {
execute(command, function() {
status.stop();
resolve(true);
});
@@ -85,8 +85,8 @@ module.exports.setFirebaseHostingTarget = (
status.start();
const command = `cd ${directory};echo '{}' > .firebaserc;yarn target ${hostingTarget} --project ${projectId}`;
execute(command, function () {
execute(`firebase use ${projectId}`, function () {
execute(command, function() {
execute(`firebase use ${projectId}`, function() {
status.stop();
resolve(true);
});
@@ -101,7 +101,7 @@ module.exports.deployToFirebaseHosting = (
const status = new Spinner("deploying to firebase hosting, please wait...");
status.start();
const command = `cd ${directory};firebase deploy --project ${projectId} --only hosting`;
execute(command, function (results) {
execute(command, function(results) {
if (results.includes("Error:")) {
throw new Error(results);
}
@@ -110,20 +110,20 @@ module.exports.deployToFirebaseHosting = (
});
});
module.exports.startFiretableLocally = (directory) =>
module.exports.startFiretableLocally = directory =>
new Promise((resolve, reject) => {
const status = new Spinner("Starting firetable locally, please wait...");
status.start();
execute(`cd ${directory};yarn local`, function () {
execute(`cd ${directory};yarn local`, function() {
status.stop();
resolve(true);
});
});
module.exports.installFiretableAppPackages = (directory) =>
module.exports.installFiretableAppPackages = directory =>
new Promise((resolve, reject) => {
const status = new Spinner("Installing firetable app packages...");
status.start();
execute(`cd ${directory};yarn`, function () {
execute(`cd ${directory};yarn`, function() {
status.stop();
resolve(true);
});
@@ -134,7 +134,7 @@ module.exports.buildFiretable = (directory = "firetable/www") =>
"Building firetable, this one might take a while \u{1F602}..."
);
status.start();
execute(`cd ${directory};yarn build`, function () {
execute(`cd ${directory};yarn build`, function() {
status.stop();
resolve(true);
});
@@ -144,7 +144,7 @@ module.exports.getFirebaseProjects = () =>
new Promise((resolve, reject) => {
const status = new Spinner("Getting your firebase projects...");
status.start();
execute(`firebase projects:list`, function (results) {
execute(`firebase projects:list`, function(results) {
status.stop();
//console.log(results);
if (results.includes("Failed to authenticate")) {
@@ -155,13 +155,11 @@ module.exports.getFirebaseProjects = () =>
});
});
module.exports.getExistingFiretableApp = (projectId) =>
module.exports.getExistingFiretableApp = projectId =>
new Promise((resolve, reject) => {
const status = new Spinner("Checking for existing firetable web app...");
status.start();
execute(`firebase apps:list WEB --project ${projectId}`, function (
results
) {
execute(`firebase apps:list WEB --project ${projectId}`, function(results) {
status.stop();
const firetableApp = results.match(/│ firetable-app.*/);
if (firetableApp) {
@@ -172,31 +170,31 @@ module.exports.getExistingFiretableApp = (projectId) =>
});
});
module.exports.createFiretableWebApp = (projectId) =>
module.exports.createFiretableWebApp = projectId =>
new Promise((resolve, reject) => {
const status = new Spinner(`Creating a firetable web app in ${projectId}`);
status.start();
execute(
`firebase apps:create --project ${projectId} web firetable-app`,
function (results) {
function(results) {
status.stop();
resolve(results.match(/(?<=ID: ).*/)[0]);
}
);
});
module.exports.getFiretableWebAppConfig = (webAppId) =>
module.exports.getFiretableWebAppConfig = webAppId =>
new Promise((resolve, reject) => {
const status = new Spinner(`getting your web app config`);
status.start();
execute(`firebase apps:sdkconfig WEB ${webAppId}`, function (results) {
execute(`firebase apps:sdkconfig WEB ${webAppId}`, function(results) {
status.stop();
const config = results.match(/{(.*)([\s\S]*)}/)[0];
resolve(config);
});
});
module.exports.createFirebaseAppConfigFile = (config) =>
module.exports.createFirebaseAppConfigFile = config =>
new Promise((resolve, reject) => {
const status = new Spinner(`creatING firebase config file.`);
status.start();
@@ -205,7 +203,7 @@ module.exports.createFirebaseAppConfigFile = (config) =>
/\n/g,
""
)}' > config.ts`,
function (results) {
function(results) {
status.stop();
resolve(results);
}

View File

@@ -30,7 +30,7 @@ const excludePaths =
export const FT_compressedThumbnail = functions.storage
.object()
.onFinalize(async (object) => {
.onFinalize(async object => {
// Log file name, size, and content type for monitoring
console.log(object.name, object.size, object.contentType);

View File

@@ -74,7 +74,7 @@ const syncDocSnapshot = async (
const snapshotDocPath = snapshot.ref.path;
const oldSnapshot = _.find(oldSnapshotsArray, { docPath: snapshotDocPath });
const updatedSnapshotsArray = oldSnapshotsArray.filter((item) => {
const updatedSnapshotsArray = oldSnapshotsArray.filter(item => {
console.log({ snapshotDocPath, item });
return item.docPath !== snapshotDocPath;
});
@@ -155,7 +155,7 @@ const syncDocOnUpdate = (config: {
* returns 2 different trigger functions (onCreate,onUpdate) in an object
* @param config configuration object
*/
const snapshotSyncFnsGenerator = (config) =>
const snapshotSyncFnsGenerator = config =>
Object.entries({
onUpdate: config.onUpdate
? functions.firestore

View File

@@ -3,28 +3,16 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@antlerengineering/components": "^0.4.1",
"@antlerengineering/multiselect": "^0.3.14",
"@date-io/date-fns": "1.x",
"@material-ui/core": "^4.9.13",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.52",
"@material-ui/lab": "^4.0.0-alpha.56",
"@material-ui/pickers": "^3.2.10",
"@mdi/js": "^4.9.95",
"@monaco-editor/react": "^3.5.5",
"@tinymce/tinymce-react": "^3.4.0",
"@types/backbone": "^1.4.1",
"@types/cash": "^0.0.3",
"@types/chroma-js": "^2.0.0",
"@types/dompurify": "^2.0.1",
"@types/file-saver": "^2.0.1",
"@types/lodash": "^4.14.138",
"@types/node": "12.7.4",
"@types/ramda": "^0.26.21",
"@types/react": "^16.9.2",
"@types/react-color": "^3.0.1",
"@types/react-div-100vh": "^0.3.0",
"@types/react-dom": "16.9.0",
"@types/react-router-dom": "^4.3.5",
"ace-builds": "^1.4.11",
"algoliasearch": "^4.1.0",
"chroma-js": "^2.1.0",
@@ -33,9 +21,6 @@
"dompurify": "^2.0.8",
"file-saver": "^2.0.2",
"firebase": "^6.6.0",
"formik": "^2.1.4",
"formik-material-ui": "^2.0.0-beta.1",
"formik-material-ui-pickers": "^0.0.8",
"grapesjs-react": "^2.0.2",
"hotkeys-js": "^3.7.2",
"json-format": "^1.0.1",
@@ -51,6 +36,7 @@
"react-div-100vh": "^0.3.8",
"react-dom": "^16.9.0",
"react-dropzone": "^10.1.8",
"react-hook-form": "^6.5.0",
"react-image": "^4.0.3",
"react-json-view": "^1.19.1",
"react-router-dom": "^5.0.1",
@@ -93,7 +79,16 @@
]
},
"devDependencies": {
"@material-ui/codemod": "^4.3.0",
"@types/chroma-js": "^2.0.0",
"@types/dompurify": "^2.0.1",
"@types/file-saver": "^2.0.1",
"@types/lodash": "^4.14.138",
"@types/ramda": "^0.26.21",
"@types/react": "^16.9.2",
"@types/react-color": "^3.0.1",
"@types/react-div-100vh": "^0.3.0",
"@types/react-dom": "16.9.0",
"@types/react-router-dom": "^4.3.5",
"firebase-tools": "^7.16.1",
"husky": "^3.0.5",
"prettier": "^1.18.2",

View File

@@ -4,22 +4,30 @@ import _isEqual from "lodash/isEqual";
import _pick from "lodash/pick";
import _omitBy from "lodash/omitBy";
import _isUndefined from "lodash/isUndefined";
import _reduce from "lodash/reduce";
import { FormikErrors } from "formik";
import { Values } from ".";
import { Control, useWatch } from "react-hook-form";
import { Values } from "./utils";
import { useAppContext } from "contexts/appContext";
import { useFiretableContext, firetableUser } from "contexts/firetableContext";
export interface IAutosaveProps {
values: Values;
errors: FormikErrors<Values>;
control: Control;
defaultValues: Values;
docRef: firebase.firestore.DocumentReference;
}
export default function Autosave({ values, errors }: IAutosaveProps) {
export default function Autosave({
control,
defaultValues,
docRef,
}: IAutosaveProps) {
const { currentUser } = useAppContext();
const { tableState, sideDrawerRef } = useFiretableContext();
const values = useWatch({ control });
const getEditables = value =>
_pick(
value,
@@ -41,21 +49,29 @@ export default function Autosave({ values, errors }: IAutosaveProps) {
useEffect(() => {
if (!row || !row.ref) return;
if (_isEqual(getEditables(row), debouncedValue)) return;
if (row.ref.id !== values.ref.id) return;
if (row.ref.id !== docRef.id) return;
// Get only fields that have changed and
// Remove undefined value to prevent Firestore crash
const updatedValues = _omitBy(debouncedValue, _isUndefined);
const updatedValues = _omitBy(
_omitBy(debouncedValue, _isUndefined),
(value, key) => _isEqual(value, row[key])
);
console.log(updatedValues);
if (Object.keys(updatedValues).length === 0) return;
const _ft_updatedAt = new Date();
const _ft_updatedBy = firetableUser(currentUser);
row.ref.update({
...updatedValues,
_ft_updatedAt,
updatedAt: _ft_updatedAt,
_ft_updatedBy,
updatedBy: _ft_updatedBy,
});
row.ref
.update({
...updatedValues,
_ft_updatedAt,
updatedAt: _ft_updatedAt,
_ft_updatedBy,
updatedBy: _ft_updatedBy,
})
.then(() => console.log("Updated row", row.ref.id, updatedValues));
}, [debouncedValue]);
return null;

View File

@@ -1,24 +0,0 @@
import React from "react";
import { ErrorMessage as FormikErrorMessage, ErrorMessageProps } from "formik";
import { makeStyles, createStyles, FormHelperText } from "@material-ui/core";
const useStyles = makeStyles(theme =>
createStyles({
root: { marginTop: theme.spacing(0.5) },
})
);
export default function ErrorMessage(props: ErrorMessageProps) {
const classes = useStyles();
return (
<FormikErrorMessage {...props}>
{msg => (
<FormHelperText error className={classes.root}>
{msg}
</FormHelperText>
)}
</FormikErrorMessage>
);
}

View File

@@ -96,7 +96,7 @@ export default function FieldWrapper({
component="a"
href={`https://console.firebase.google.com/project/${
process.env.REACT_APP_FIREBASE_PROJECT_ID
}/database/firestore/data~2F${(debugText as string).replace(
}/firestore/data~2F${(debugText as string).replace(
/\//g,
"~2F"
)}`}

View File

@@ -1,5 +1,6 @@
import React, { useContext, useState } from "react";
import { FieldProps } from "formik";
import { Controller, useWatch } from "react-hook-form";
import { IFieldProps } from "../utils";
import {
createStyles,
@@ -40,85 +41,104 @@ const useStyles = makeStyles(theme =>
})
);
function Action({
field,
form,
editable,
config,
}: FieldProps<any> & { config: { callableName: string }; editable?: boolean }) {
export interface IActionProps extends IFieldProps {
config: { callableName: string };
}
function Action({ control, name, docRef, editable, config }: IActionProps) {
const classes = useStyles();
const { ref, ...docData } = form.values;
const docData = useWatch({ control });
const [isRunning, setIsRunning] = useState(false);
const snack = useContext(SnackContext);
const handleRun = () => {
setIsRunning(true);
cloudFunction(
config.callableName,
{
ref: { path: ref.path, id: ref.id },
row: sanitiseRowData(Object.assign({}, docData)),
},
response => {
const { message, cellValue } = response.data;
setIsRunning(false);
snack.open({ message, severity: "success" });
if (cellValue) form.setFieldValue(field.name, cellValue);
},
error => {
console.error("ERROR", config.callableName, error);
setIsRunning(false);
snack.open({ message: JSON.stringify(error), severity: "error" });
}
);
};
const hasRan = field.value && field.value.status;
const disabled = editable === false;
return (
<Grid
container
alignItems="center"
wrap="nowrap"
className={classes.root}
spacing={2}
>
<Grid item xs className={classes.labelGridItem}>
<Grid container alignItems="center" className={classes.labelContainer}>
<Typography variant="body1" className={classes.label}>
{hasRan && isUrl(field.value.status) ? (
<a
href={field.value.status}
target="_blank"
rel="noopener noreferrer"
>
{field.value.status}
</a>
) : hasRan ? (
field.value.status
) : (
sanitiseCallableName(config.callableName)
)}
</Typography>
</Grid>
</Grid>
<Grid item>
<Fab
onClick={handleRun}
disabled={isRunning || !!(hasRan && !field.value.redo) || disabled}
>
{isRunning ? (
<CircularProgress color="secondary" size={24} thickness={4.6} />
) : hasRan ? (
<RefreshIcon />
) : (
<PlayIcon />
)}
</Fab>
</Grid>
</Grid>
return (
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
const handleRun = () => {
setIsRunning(true);
console.log("RUN");
cloudFunction(
config.callableName,
{
ref: { path: docRef.path, id: docRef.id },
row: sanitiseRowData(Object.assign({}, docData)),
},
response => {
const { message, cellValue } = response.data;
setIsRunning(false);
snack.open({ message, severity: "success" });
if (cellValue) onChange(cellValue);
},
error => {
console.error("ERROR", config.callableName, error);
setIsRunning(false);
snack.open({ message: JSON.stringify(error), severity: "error" });
}
);
};
const hasRan = value && value.status;
return (
<Grid
container
alignItems="center"
wrap="nowrap"
className={classes.root}
spacing={2}
>
<Grid item xs className={classes.labelGridItem}>
<Grid
container
alignItems="center"
className={classes.labelContainer}
>
<Typography variant="body1" className={classes.label}>
{hasRan && isUrl(value.status) ? (
<a
href={value.status}
target="_blank"
rel="noopener noreferrer"
>
{value.status}
</a>
) : hasRan ? (
value.status
) : (
sanitiseCallableName(config.callableName)
)}
</Typography>
</Grid>
</Grid>
<Grid item>
<Fab
onClick={handleRun}
disabled={isRunning || !!(hasRan && !value.redo) || disabled}
>
{isRunning ? (
<CircularProgress
color="secondary"
size={24}
thickness={4.6}
/>
) : hasRan ? (
<RefreshIcon />
) : (
<PlayIcon />
)}
</Fab>
</Grid>
</Grid>
);
}}
/>
);
}

View File

@@ -1,15 +1,15 @@
import React from "react";
import { Field } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import {
makeStyles,
createStyles,
ButtonBase,
FormControlLabel,
Switch,
SwitchProps as MuiSwitchProps,
} from "@material-ui/core";
import { Switch } from "formik-material-ui";
import ErrorMessage from "../ErrorMessage";
const useStyles = makeStyles(theme =>
createStyles({
@@ -39,33 +39,54 @@ const useStyles = makeStyles(theme =>
})
);
export interface ICheckboxProps extends MuiSwitchProps {
name: string;
export interface ICheckboxProps
extends IFieldProps,
Omit<MuiSwitchProps, "name"> {
label?: React.ReactNode;
editable?: boolean;
}
export default function Checkbox({ label, ...props }: ICheckboxProps) {
export default function Checkbox({
control,
docRef,
label,
name,
editable,
...props
}: ICheckboxProps) {
const classes = useStyles();
return (
<>
<ButtonBase className={classes.buttonBase}>
<FormControlLabel
control={
<Field
component={Switch}
color="primary"
{...props}
type="checkbox"
/>
}
label={label}
labelPlacement="start"
classes={{ root: classes.formControlLabel, label: classes.label }}
/>
</ButtonBase>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onChange(event.target.checked);
};
<ErrorMessage name={props.name} />
</>
const handleClick = () => onChange(!value);
return (
<ButtonBase className={classes.buttonBase} onClick={handleClick}>
<FormControlLabel
control={
<Switch
color="secondary"
{...props}
checked={value}
onChange={handleChange}
onBlur={onBlur}
disabled={editable === false}
/>
}
label={label}
labelPlacement="start"
classes={{ root: classes.formControlLabel, label: classes.label }}
/>
</ButtonBase>
);
}}
/>
);
}

View File

@@ -1,12 +1,12 @@
import React, { useState, useEffect, useRef } from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-javascript";
import "ace-builds/src-noconflict/theme-monokai";
import "ace-builds/src-noconflict/theme-github";
import { makeStyles, createStyles, Button } from "@material-ui/core";
import ErrorMessage from "../ErrorMessage";
import CornerResizeIcon from "assets/icons/CornerResize";
const useStyles = makeStyles(theme =>
@@ -35,17 +35,23 @@ const useStyles = makeStyles(theme =>
})
);
export default function Code({ form, field }: FieldProps) {
export interface IControlledCodeProps {
onChange: (...event: any[]) => void;
onBlur: () => void;
value: any;
}
function ControlledCode({ onChange, onBlur, value }: IControlledCodeProps) {
const classes = useStyles();
const [localValue, setLocalValue] = useState(field.value);
const [localValue, setLocalValue] = useState(value);
useEffect(() => {
if (field.value !== localValue) setLocalValue(field.value);
}, [field.value]);
if (value !== localValue) setLocalValue(value);
}, [value]);
const autoSave = false;
const handleChange = autoSave
? value => form.setFieldValue(field.name, value)
? value => onChange(value)
: value => setLocalValue(value);
const editor = useRef<AceEditor>(null);
@@ -58,11 +64,9 @@ export default function Code({ form, field }: FieldProps) {
<>
<div className={classes.editorWrapper} onMouseUp={handleResize}>
<AceEditor
key={`${form.initialValues.id}-${field.name}`}
placeholder="Type code here…"
mode="javascript"
theme="github"
name={field.name}
//onLoad={this.onLoad}
onChange={handleChange}
fontSize={13}
@@ -71,7 +75,7 @@ export default function Code({ form, field }: FieldProps) {
showGutter
highlightActiveLine
showPrintMargin
value={autoSave ? field.value : localValue}
value={autoSave ? value : localValue}
setOptions={{
enableBasicAutocompletion: false,
enableLiveAutocompletion: false,
@@ -85,19 +89,25 @@ export default function Code({ form, field }: FieldProps) {
<CornerResizeIcon className={classes.resizeIcon} />
</div>
{!autoSave && field.value !== localValue && (
{!autoSave && value !== localValue && (
<Button
onClick={() => {
form.setFieldValue(field.name, localValue);
}}
onClick={() => onChange(localValue)}
className={classes.saveButton}
variant="contained"
>
Save Changes
</Button>
)}
<ErrorMessage name={field.name} />
</>
);
}
export default function Code({ control, docRef, name, ...props }: IFieldProps) {
return (
<Controller
control={control}
name={name}
render={renderProps => <ControlledCode {...props} {...renderProps} />}
/>
);
}

View File

@@ -1,5 +1,6 @@
import React, { useState } from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { ChromePicker } from "react-color";
import {
@@ -18,7 +19,16 @@ const useStyles = makeStyles(theme =>
cursor: "pointer",
textAlign: "left",
borderRadius: theme.shape.borderRadius,
backgroundColor:
theme.palette.type === "light"
? "rgba(0, 0, 0, 0.09)"
: "rgba(255, 255, 255, 0.09)",
margin: 0,
width: "100%",
padding: theme.spacing(0, 0.75),
},
colorIndicator: {
width: 20,
height: 20,
@@ -30,51 +40,52 @@ const useStyles = makeStyles(theme =>
})
);
export interface IColorProps extends FieldProps {}
export default function Color({ field, form }: IColorProps) {
export default function Color({ control, name }: IFieldProps) {
const classes = useStyles();
const [showPicker, setShowPicker] = useState(false);
const toggleOpen = () => setShowPicker(s => !s);
const handleChangeComplete = color => {
form.setFieldValue(field.name, color);
};
return (
<>
<Grid
container
alignItems="center"
spacing={1}
className={classes.root}
onClick={toggleOpen}
component={ButtonBase}
>
<Grid item>
<div
className={classes.colorIndicator}
style={{ backgroundColor: field.value.hex }}
/>
</Grid>
<Grid item xs>
<Typography
variant="body1"
color={field.value.hex ? "textPrimary" : "textSecondary"}
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => (
<>
<Grid
container
alignItems="center"
spacing={1}
className={classes.root}
onClick={() => {
toggleOpen();
onBlur();
}}
component={ButtonBase}
focusRipple
>
{field.value.hex ?? "Choose a color…"}
</Typography>
</Grid>
</Grid>
<Grid item>
<div
className={classes.colorIndicator}
style={{ backgroundColor: value?.hex }}
/>
</Grid>
<Collapse in={showPicker}>
<ChromePicker
color={field.value.rgb}
onChangeComplete={handleChangeComplete}
/>
</Collapse>
</>
<Grid item xs>
<Typography
variant="body1"
color={value?.hex ? "textPrimary" : "textSecondary"}
>
{value?.hex ?? "Choose a color…"}
</Typography>
</Grid>
</Grid>
<Collapse in={showPicker}>
<ChromePicker color={value?.rgb} onChangeComplete={onChange} />
</Collapse>
</>
)}
/>
);
}

View File

@@ -1,63 +1,76 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { useTheme, Grid, Chip } from "@material-ui/core";
import ConnectTableSelect, {
ConnectTableValue,
IConnectTableSelectProps,
} from "components/ConnectTableSelect";
export interface IConnectTableProps
extends IFieldProps,
Partial<IConnectTableSelectProps> {}
export default function ConnectTable({
field,
form,
control,
docRef,
name,
editable,
...props
}: FieldProps<ConnectTableValue[]> & IConnectTableSelectProps) {
}: IConnectTableProps) {
const theme = useTheme();
const handleDelete = (hit: any) => () => {
// if (multiple)
form.setFieldValue(
field.name,
field.value.filter(v => v.snapshot.objectID !== hit.objectID)
);
// else form.setFieldValue(field.name, []);
};
const disabled = editable === false;
return (
<>
{!disabled && (
<ConnectTableSelect
{...props}
value={field.value}
onChange={value => form.setFieldValue(field.name, value)}
TextFieldProps={{
fullWidth: true,
error: !!(form.touched[field.name] && form.errors[field.name]),
helperText:
(form.touched[field.name] && form.errors[field.name]) || "",
onBlur: () => form.setFieldTouched(field.name),
}}
/>
)}
{Array.isArray(field.value) && (
<Grid container spacing={1} style={{ marginTop: theme.spacing(1) }}>
{field.value.map(({ snapshot }) => (
<Grid item key={snapshot.objectID}>
<Chip
component="li"
size="medium"
label={props.config?.primaryKeys
?.map((key: string) => snapshot[key])
.join(" ")}
onDelete={disabled ? undefined : handleDelete(snapshot)}
return (
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
const handleDelete = (hit: any) => () => {
// if (multiple)
onChange(value.filter(v => v.snapshot.objectID !== hit.objectID));
// else form.setFieldValue(field.name, []);
};
return (
<>
{!disabled && (
<ConnectTableSelect
{...(props as any)}
value={value}
onChange={onChange}
TextFieldProps={{
fullWidth: true,
onBlur,
}}
/>
</Grid>
))}
</Grid>
)}
</>
)}
{Array.isArray(value) && (
<Grid
container
spacing={1}
style={{ marginTop: theme.spacing(1) }}
>
{value.map(({ snapshot }) => (
<Grid item key={snapshot.objectID}>
<Chip
component="li"
size="medium"
label={props.config?.primaryKeys
?.map((key: string) => snapshot[key])
.join(" ")}
onDelete={disabled ? undefined : handleDelete(snapshot)}
/>
</Grid>
))}
</Grid>
)}
</>
);
}}
/>
);
}

View File

@@ -1,42 +1,66 @@
import React from "react";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { useTheme } from "@material-ui/core";
import { KeyboardDatePicker } from "@material-ui/pickers";
import {
fieldToKeyboardDatePicker,
KeyboardDatePicker,
KeyboardDatePickerProps,
} from "formik-material-ui-pickers";
} from "@material-ui/pickers";
import { DATE_FORMAT } from "constants/dates";
export default function DatePicker(props: KeyboardDatePickerProps) {
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
import DateFnsUtils from "@date-io/date-fns";
export interface IDatePickerProps
extends IFieldProps,
Omit<KeyboardDatePickerProps, "name" | "onChange" | "value"> {}
export default function DatePicker({
control,
docRef,
name,
...props
}: IDatePickerProps) {
const theme = useTheme();
let transformedValue = null;
if (props.field.value && "toDate" in props.field.value)
transformedValue = props.field.value.toDate();
else if (props.field.value !== undefined)
transformedValue = props.field.value;
const handleChange = (date: Date | null) => {
if (isNaN(date?.valueOf() ?? 0)) return;
props.form.setFieldValue(props.field.name, date);
};
return (
<KeyboardDatePicker
variant="inline"
inputVariant="filled"
fullWidth
margin="none"
format={DATE_FORMAT}
placeholder={DATE_FORMAT}
InputAdornmentProps={{ style: { marginRight: theme.spacing(-1) } }}
{...fieldToKeyboardDatePicker(props)}
value={transformedValue}
onChange={handleChange}
label=""
hiddenLabel
id={`sidedrawer-field-${props.field.name}`}
/>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
let transformedValue = null;
if (value && "toDate" in value) transformedValue = value.toDate();
else if (value !== undefined) transformedValue = value;
const handleChange = (date: Date | null) => {
if (isNaN(date?.valueOf() ?? 0)) return;
onChange(date);
};
return (
<KeyboardDatePicker
variant="inline"
inputVariant="filled"
fullWidth
margin="none"
format={DATE_FORMAT}
placeholder={DATE_FORMAT}
InputAdornmentProps={{
style: { marginRight: theme.spacing(-1) },
}}
{...props}
value={transformedValue}
onChange={handleChange}
onBlur={onBlur}
label=""
hiddenLabel
id={`sidedrawer-field-${name}`}
/>
);
}}
/>
</MuiPickersUtilsProvider>
);
}

View File

@@ -1,45 +1,69 @@
import React from "react";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { useTheme } from "@material-ui/core";
import { KeyboardDateTimePicker } from "@material-ui/pickers";
import {
fieldToKeyboardDateTimePicker,
KeyboardDateTimePicker,
KeyboardDateTimePickerProps,
} from "formik-material-ui-pickers";
} from "@material-ui/pickers";
import { DATE_TIME_FORMAT } from "constants/dates";
import AccessTimeIcon from "@material-ui/icons/AccessTime";
export default function DateTimePicker(props: KeyboardDateTimePickerProps) {
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
import DateFnsUtils from "@date-io/date-fns";
export interface IDateTimePickerProps
extends IFieldProps,
Omit<KeyboardDateTimePickerProps, "name" | "onChange" | "value"> {}
export default function DateTimePicker({
control,
docRef,
name,
...props
}: IDateTimePickerProps) {
const theme = useTheme();
let transformedValue = null;
if (props.field.value && "toDate" in props.field.value)
transformedValue = props.field.value.toDate();
else if (props.field.value !== undefined)
transformedValue = props.field.value;
const handleChange = (date: Date | null) => {
if (isNaN(date?.valueOf() ?? 0)) return;
props.form.setFieldValue(props.field.name, date);
};
return (
<KeyboardDateTimePicker
variant="inline"
inputVariant="filled"
fullWidth
margin="none"
format={DATE_TIME_FORMAT}
placeholder={DATE_TIME_FORMAT}
InputAdornmentProps={{ style: { marginRight: theme.spacing(-1) } }}
keyboardIcon={<AccessTimeIcon />}
{...fieldToKeyboardDateTimePicker(props)}
value={transformedValue}
onChange={handleChange}
label=""
hiddenLabel
id={`sidedrawer-field-${props.field.name}`}
/>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
let transformedValue = null;
if (value && "toDate" in value) transformedValue = value.toDate();
else if (value !== undefined) transformedValue = value;
const handleChange = (date: Date | null) => {
if (isNaN(date?.valueOf() ?? 0)) return;
onChange(date);
};
return (
<KeyboardDateTimePicker
variant="inline"
inputVariant="filled"
fullWidth
margin="none"
format={DATE_TIME_FORMAT}
placeholder={DATE_TIME_FORMAT}
InputAdornmentProps={{
style: { marginRight: theme.spacing(-1) },
}}
keyboardIcon={<AccessTimeIcon />}
{...props}
value={transformedValue}
onChange={handleChange}
onBlur={onBlur}
label=""
hiddenLabel
id={`sidedrawer-field-${name}`}
/>
);
}}
/>
</MuiPickersUtilsProvider>
);
}

View File

@@ -1,6 +1,7 @@
import React, { useCallback, useState } from "react";
import clsx from "clsx";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { useDropzone } from "react-dropzone";
import useUploader, { FileValue } from "hooks/useFiretable/useUploader";
@@ -19,7 +20,6 @@ import {
import UploadIcon from "assets/icons/Upload";
import { FileIcon } from "constants/fields";
import ErrorMessage from "../ErrorMessage";
import Confirmation from "components/Confirmation";
const useStyles = makeStyles(theme =>
@@ -55,17 +55,21 @@ const useStyles = makeStyles(theme =>
})
);
export interface IFileUploaderProps extends FieldProps {
editable?: boolean;
docRef?: firebase.firestore.DocumentReference;
export interface IControlledFileUploaderProps
extends Pick<IFieldProps, "editable" | "docRef" | "name"> {
onChange: (...event: any[]) => void;
onBlur: () => void;
value: any;
}
export default function FileUploader({
form,
field,
export function ControlledFileUploader({
onChange,
onBlur,
value,
name,
docRef,
editable,
}: IFileUploaderProps) {
}: IControlledFileUploaderProps) {
const classes = useStyles();
const { uploaderState, upload, deleteUpload } = useUploader();
@@ -81,25 +85,25 @@ export default function FileUploader({
if (docRef && file) {
upload({
docRef,
fieldName: field.name,
fieldName: name,
files: [file],
previousValue: field.value ?? [],
previousValue: value ?? [],
onComplete: newValue => {
form.setFieldValue(field.name, newValue);
onChange(newValue);
setLocalFile("");
},
});
setLocalFile(file.name);
}
},
[docRef, field.value]
[docRef, value]
);
const handleDelete = (index: number) => {
const newValue = [...field.value];
const newValue = [...value];
const toBeDeleted = newValue.splice(index, 1);
toBeDeleted.length && deleteUpload(toBeDeleted[0]);
form.setFieldValue(field.name, newValue);
onChange(newValue);
};
const { getRootProps, getInputProps, isDragActive } = useDropzone({
@@ -117,7 +121,7 @@ export default function FileUploader({
)}
{...getRootProps()}
>
<input id={`sidedrawer-field-${field.name}`} {...getInputProps()} />
<input id={`sidedrawer-field-${name}`} {...getInputProps()} />
<UploadIcon />
<Typography variant="body1" color="textSecondary">
Upload file
@@ -126,8 +130,8 @@ export default function FileUploader({
)}
<Grid container spacing={1} className={classes.chipList}>
{Array.isArray(field.value) &&
field.value.map((file: FileValue, i) => (
{Array.isArray(value) &&
value.map((file: FileValue, i) => (
<Grid item key={file.name} className={classes.chipGridItem}>
<Confirmation
message={{
@@ -166,8 +170,18 @@ export default function FileUploader({
</Grid>
)}
</Grid>
<ErrorMessage name={field.name} />
</>
);
}
export default function FileUploader({ control, name, ...props }: IFieldProps) {
return (
<Controller
control={control}
name={name}
render={renderProps => (
<ControlledFileUploader {...props} name={name} {...renderProps} />
)}
/>
);
}

View File

@@ -1,6 +1,7 @@
import React, { useCallback, useState } from "react";
import clsx from "clsx";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { useDropzone } from "react-dropzone";
import useUploader from "hooks/useFiretable/useUploader";
@@ -20,7 +21,6 @@ import AddIcon from "@material-ui/icons/AddAPhoto";
import DeleteIcon from "@material-ui/icons/Delete";
import OpenIcon from "@material-ui/icons/OpenInNewOutlined";
import ErrorMessage from "../ErrorMessage";
import Confirmation from "components/Confirmation";
import { IMAGE_MIME_TYPES } from "constants/fields";
import Thumbnail from "components/Thumbnail";
@@ -110,17 +110,21 @@ const useStyles = makeStyles(theme =>
})
);
export interface IImageUploaderProps extends FieldProps {
docRef?: firebase.firestore.DocumentReference;
editable?: boolean;
export interface IControlledImageUploaderProps
extends Pick<IFieldProps, "docRef" | "editable" | "name"> {
onChange: (...event: any[]) => void;
onBlur: () => void;
value: any;
}
export default function ImageUploader({
form,
field,
export function ControlledImageUploader({
onChange,
onBlur,
value,
name,
editable,
docRef,
}: IImageUploaderProps) {
}: IControlledImageUploaderProps) {
const disabled = editable === false;
const classes = useStyles();
@@ -137,25 +141,25 @@ export default function ImageUploader({
if (docRef && imageFile) {
upload({
docRef,
fieldName: field.name,
fieldName: name,
files: [imageFile],
previousValue: field.value ?? [],
previousValue: value ?? [],
onComplete: newValue => {
form.setFieldValue(field.name, newValue);
onChange(newValue);
setLocalImage("");
},
});
setLocalImage(URL.createObjectURL(imageFile));
}
},
[docRef, field.value]
[docRef, value]
);
const handleDelete = (index: number) => {
const newValue = [...field.value];
const newValue = [...value];
const toBeDeleted = newValue.splice(index, 1);
toBeDeleted.length && deleteUpload(toBeDeleted[0]);
form.setFieldValue(field.name, newValue);
onChange(newValue);
};
const { getRootProps, getInputProps, isDragActive } = useDropzone({
@@ -174,7 +178,7 @@ export default function ImageUploader({
)}
{...getRootProps()}
>
<input id={`sidedrawer-field-${field.name}`} {...getInputProps()} />
<input id={`sidedrawer-field-${name}`} {...getInputProps()} />
<AddIcon />
<Typography variant="body1" color="inherit">
{isDragActive ? "Drop your image here" : "Upload image"}
@@ -183,8 +187,8 @@ export default function ImageUploader({
)}
<Grid container spacing={1} className={classes.imagesContainer}>
{Array.isArray(field.value) &&
field.value.map((image, i) => (
{Array.isArray(value) &&
value.map((image, i) => (
<Grid item key={image.downloadURL}>
{disabled ? (
<Tooltip title="Click to open">
@@ -271,8 +275,21 @@ export default function ImageUploader({
</Grid>
)}
</Grid>
<ErrorMessage name={field.name} />
</>
);
}
export default function ImageUploader({
control,
name,
...props
}: IFieldProps) {
return (
<Controller
control={control}
name={name}
render={renderProps => (
<ControlledImageUploader {...props} name={name} {...renderProps} />
)}
/>
);
}

View File

@@ -1,5 +1,6 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import ReactJson from "react-json-view";
import { makeStyles, createStyles, useTheme } from "@material-ui/core";
@@ -32,45 +33,54 @@ const isValidJson = (val: any) => {
return true;
};
export default function JsonEditor({ form, field }: FieldProps) {
export default function JsonEditor({ control, name }: IFieldProps) {
const classes = useStyles();
const theme = useTheme();
const handleEdit = edit => {
form.setFieldValue(field.name, edit.updated_src);
};
return (
<div className={classes.root}>
<ReactJson
src={isValidJson(field.value) ? field.value : {}}
onEdit={handleEdit}
onAdd={handleEdit}
onDelete={handleEdit}
theme={{
base00: "rgba(0, 0, 0, 0)",
base01: theme.palette.background.default,
base02: theme.palette.divider,
base03: "#93a1a1",
base04: theme.palette.text.disabled,
base05: theme.palette.text.secondary,
base06: "#073642",
base07: theme.palette.text.primary,
base08: "#d33682",
base09: "#cb4b16",
base0A: "#dc322f",
base0B: "#859900",
base0C: "#6c71c4",
base0D: theme.palette.text.secondary,
base0E: "#2aa198",
base0F: "#268bd2",
}}
iconStyle="triangle"
style={{
fontFamily: "SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace",
backgroundColor: "transparent",
}}
/>
</div>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
const handleEdit = edit => {
onChange(edit.updated_src);
};
return (
<div className={classes.root}>
<ReactJson
src={isValidJson(value) ? value : {}}
onEdit={handleEdit}
onAdd={handleEdit}
onDelete={handleEdit}
theme={{
base00: "rgba(0, 0, 0, 0)",
base01: theme.palette.background.default,
base02: theme.palette.divider,
base03: "#93a1a1",
base04: theme.palette.text.disabled,
base05: theme.palette.text.secondary,
base06: "#073642",
base07: theme.palette.text.primary,
base08: "#d33682",
base09: "#cb4b16",
base0A: "#dc322f",
base0B: "#859900",
base0C: "#6c71c4",
base0D: theme.palette.text.secondary,
base0E: "#2aa198",
base0F: "#268bd2",
}}
iconStyle="triangle"
style={{
fontFamily:
"SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace",
backgroundColor: "transparent",
}}
/>
</div>
);
}}
/>
);
}

View File

@@ -1,67 +1,84 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { useTheme, Grid } from "@material-ui/core";
import MultiSelectA, { MultiSelectProps } from "@antlerengineering/multiselect";
import MultiSelect_, { MultiSelectProps } from "@antlerengineering/multiselect";
import FormattedChip from "components/FormattedChip";
export type IMultiSelectProps = IFieldProps &
Omit<
MultiSelectProps<string>,
"name" | "multiple" | "value" | "onChange" | "options"
> & {
config?: { options: string[] };
};
export default function MultiSelect({
field,
form,
control,
name,
docRef,
editable,
config,
...props
}: FieldProps<string[]> &
MultiSelectProps<string> & {
config: { options: string[] };
editable?: boolean;
}) {
}: IMultiSelectProps) {
const theme = useTheme();
const handleDelete = (index: number) => () => {
const newValues = [...field.value];
newValues.splice(index, 1);
form.setFieldValue(field.name, newValues);
};
return (
<>
<MultiSelectA
{...props}
options={config.options ?? []}
multiple
value={field.value ? field.value : []}
onChange={value => form.setFieldValue(field.name, value)}
disabled={editable === false}
TextFieldProps={{
label: "",
hiddenLabel: true,
error: !!(form.touched[field.name] && form.errors[field.name]),
helperText:
(form.touched[field.name] && form.errors[field.name]) || "",
onBlur: () => form.setFieldTouched(field.name),
}}
searchable
freeText={false}
/>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
const handleDelete = (index: number) => () => {
const newValues = [...value];
newValues.splice(index, 1);
onChange(newValues);
};
{field.value && Array.isArray(field.value) && (
<Grid container spacing={1} style={{ marginTop: theme.spacing(1) }}>
{field.value.map(
(item, i) =>
item?.length > 0 && (
<Grid item key={item}>
<FormattedChip
size="medium"
label={item}
onDelete={editable !== false ? handleDelete(i) : undefined}
/>
</Grid>
)
)}
</Grid>
)}
</>
return (
<>
<MultiSelect_
{...props}
options={config?.options ?? []}
multiple
value={value ? value : []}
onChange={onChange}
disabled={editable === false}
TextFieldProps={{
label: "",
hiddenLabel: true,
onBlur,
}}
searchable
freeText={false}
/>
{value && Array.isArray(value) && (
<Grid
container
spacing={1}
style={{ marginTop: theme.spacing(1) }}
>
{value.map(
(item, i) =>
item?.length > 0 && (
<Grid item key={item}>
<FormattedChip
size="medium"
label={item}
onDelete={
editable !== false ? handleDelete(i) : undefined
}
/>
</Grid>
)
)}
</Grid>
)}
</>
);
}}
/>
);
}

View File

@@ -1,5 +1,6 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { makeStyles, createStyles, Typography } from "@material-ui/core";
import { resultColorsScale } from "util/color";
@@ -41,27 +42,35 @@ const useStyles = makeStyles(theme =>
})
);
export default function Percentage({ field }: FieldProps) {
export default function Percentage({ control, name }: IFieldProps) {
const classes = useStyles();
if (!field.value)
return (
<div className={classes.root}>
<div className={classes.resultColor} style={{ opacity: 1 }} />
</div>
);
return (
<div className={classes.root}>
<div
className={classes.resultColor}
style={{
backgroundColor: resultColorsScale(field.value as number).hex(),
}}
/>
<Typography variant="body1" className={classes.value}>
{Math.round(field.value * 100)}%
</Typography>
</div>
<Controller
control={control}
name={name}
render={({ value }) => {
if (!value)
return (
<div className={classes.root}>
<div className={classes.resultColor} style={{ opacity: 1 }} />
</div>
);
return (
<div className={classes.root}>
<div
className={classes.resultColor}
style={{
backgroundColor: resultColorsScale(value as number).hex(),
}}
/>
<Typography variant="body1" className={classes.value}>
{Math.round(value * 100)}%
</Typography>
</div>
);
}}
/>
);
}

View File

@@ -1,82 +0,0 @@
import React from "react";
import {
makeStyles,
createStyles,
FormControl,
FormControlLabel,
Radio as MuiRadio,
Divider,
} from "@material-ui/core";
import { RadioGroup, RadioGroupProps } from "formik-material-ui";
import Label from "../Label";
import ErrorMessage from "../ErrorMessage";
const useStyles = makeStyles(theme =>
createStyles({
root: { display: "flex" },
formControlLabel: {
padding: theme.spacing(1.25, 0),
marginLeft: theme.spacing(1),
},
divider: { marginLeft: theme.spacing(5) },
})
);
export interface IRadioProps extends RadioGroupProps {
options: (string | { value: string; label: React.ReactNode })[];
label?: React.ReactNode;
}
export default function Radio({ options, label, ...props }: IRadioProps) {
const classes = useStyles();
return (
<FormControl component="fieldset" className={classes.root}>
<Label
error={
!!(
props.form.errors[props.field.name] &&
props.form.touched[props.field.name]
)
}
>
{label}
</Label>
<RadioGroup {...props}>
{options.map(item => {
let option: { label: React.ReactNode; value: string } = {
label: "",
value: "",
};
if (typeof item === "object") option = item;
if (typeof item === "string") option = { label: item, value: item };
return (
<React.Fragment key={option.value}>
<FormControlLabel
key={option.value}
value={option.value}
label={option.label}
control={
<MuiRadio
//disabled={isSubmitting}
/>
}
classes={{ label: classes.formControlLabel }}
//disabled={isSubmitting}
/>
<Divider className={classes.divider} />
</React.Fragment>
);
})}
</RadioGroup>
<ErrorMessage name={props.field.name} />
</FormControl>
);
}

View File

@@ -1,12 +1,11 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { makeStyles, createStyles, Grid } from "@material-ui/core";
import { Rating as MuiRating } from "@material-ui/lab";
import StarBorderIcon from "@material-ui/icons/StarBorder";
import ErrorMessage from "../ErrorMessage";
const useStyles = makeStyles(theme =>
createStyles({
root: {
@@ -27,32 +26,30 @@ const useStyles = makeStyles(theme =>
})
);
export interface IRatingProps extends FieldProps {
editable?: boolean;
}
export default function Rating(props: IRatingProps) {
export default function Rating({ control, name, editable }: IFieldProps) {
const classes = useStyles();
return (
<>
<Grid container alignItems="center" className={classes.root}>
<MuiRating
disabled={props.editable === false}
name={props.field.name}
id={`sidedrawer-field-${props.field.name}`}
value={typeof props.field.value === "number" ? props.field.value : 0}
onChange={(event, newValue) => {
props.form.setFieldValue(props.field.name, newValue);
}}
emptyIcon={<StarBorderIcon fontSize="inherit" />}
classes={{ root: classes.rating, iconEmpty: classes.iconEmpty }}
// TODO: Make this customisable in column settings
max={4}
/>
</Grid>
<ErrorMessage name={props.field.name} />
</>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => (
<Grid container alignItems="center" className={classes.root}>
<MuiRating
disabled={editable === false}
name={name}
id={`sidedrawer-field-${name}`}
value={typeof value === "number" ? value : 0}
onChange={(event, newValue) => {
onChange(newValue);
}}
emptyIcon={<StarBorderIcon fontSize="inherit" />}
classes={{ root: classes.rating, iconEmpty: classes.iconEmpty }}
// TODO: Make this customisable in column settings
max={4}
/>
</Grid>
)}
/>
);
}

View File

@@ -1,16 +1,17 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import _RichText from "components/RichText";
import ErrorMessage from "../ErrorMessage";
export default function RichText({ form, field }: FieldProps) {
const handleChange = value => form.setFieldValue(field.name, value);
export default function RichText({ control, name }: IFieldProps) {
return (
<>
<_RichText value={field.value} onChange={handleChange} />
<ErrorMessage name={field.name} />
</>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => (
<_RichText value={value} onChange={onChange} />
)}
/>
);
}

View File

@@ -1,56 +1,63 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { useTheme } from "@material-ui/core";
import MultiSelect, { MultiSelectProps } from "@antlerengineering/multiselect";
import FormattedChip from "components/FormattedChip";
export type ISingleSelectProps = IFieldProps &
Omit<
MultiSelectProps<string>,
"name" | "multiple" | "value" | "onChange" | "options"
> & {
config?: { options: string[] };
};
/**
* Uses the MultiSelect UI, but writes values as a string,
* not an array of strings
*/
export default function SingleSelect({
field,
form,
control,
docRef,
name,
editable,
config,
...props
}: FieldProps<string> &
MultiSelectProps<string> & {
config: { options: string[] };
editable: boolean;
}) {
}: ISingleSelectProps) {
const theme = useTheme();
const handleChange = value => form.setFieldValue(field.name, value);
return (
<>
<MultiSelect
{...props}
options={config.options}
multiple={false}
value={field.value}
onChange={handleChange}
disabled={editable === false}
TextFieldProps={{
label: "",
hiddenLabel: true,
error: !!(form.touched[field.name] && form.errors[field.name]),
helperText:
(form.touched[field.name] && form.errors[field.name]) || "",
onBlur: () => form.setFieldTouched(field.name),
}}
searchable
freeText={false}
/>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => (
<>
<MultiSelect
{...props}
options={config?.options ?? []}
multiple={false}
value={value}
onChange={onChange}
disabled={editable === false}
TextFieldProps={{
label: "",
hiddenLabel: true,
onBlur,
}}
searchable
freeText={false}
/>
{field.value?.length > 0 && (
<div style={{ marginTop: theme.spacing(1) }}>
<FormattedChip size="medium" label={field.value} />
</div>
{value?.length > 0 && (
<div style={{ marginTop: theme.spacing(1) }}>
<FormattedChip size="medium" label={value} />
</div>
)}
</>
)}
</>
/>
);
}

View File

@@ -1,5 +1,6 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import {
makeStyles,
@@ -11,8 +12,6 @@ import {
Typography,
} from "@material-ui/core";
import ErrorMessage from "../ErrorMessage";
const useStyles = makeStyles(theme =>
createStyles({
root: { display: "flex" },
@@ -45,17 +44,16 @@ const useStyles = makeStyles(theme =>
})
);
export interface ISliderProps extends FieldProps, SliderProps {
label: React.ReactNode;
export interface ISliderProps extends IFieldProps, Omit<SliderProps, "name"> {
units?: string;
minLabel?: React.ReactNode;
maxLabel?: React.ReactNode;
}
export default function Slider({
field,
form,
label,
control,
docRef,
name,
units,
minLabel,
maxLabel,
@@ -65,54 +63,67 @@ export default function Slider({
}: ISliderProps) {
const classes = useStyles();
const handleClick = () => form.setFieldTouched(field.name);
const handleChange = (event: any, value: number | number[]) => {
form.setFieldValue(field.name, value);
form.setFieldTouched(field.name);
};
const getAriaValueText = (value: number) =>
`${value}${units ? " " + units : ""}`;
const getValueLabelFormat = (value: number) =>
`${value}${units ? " " + units : ""}`;
return (
<FormControl className={classes.root}>
<Grid container spacing={2} alignItems="center">
<Grid item>
<Typography variant="overline" component="span" color="textSecondary">
{minLabel ?? `${min}${units ? " " + units : ""}`}
</Typography>
</Grid>
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
const handleChange = (_: any, value: number | number[]) => {
onChange(value);
onBlur();
};
<Grid item xs>
<MuiSlider
valueLabelDisplay="auto"
min={min}
max={max}
getAriaValueText={getAriaValueText}
valueLabelFormat={getValueLabelFormat}
{...props}
value={typeof field.value === "number" ? field.value : min}
onClick={handleClick}
onChange={handleChange}
classes={{
root: classes.slider,
thumb: classes.thumb,
valueLabel: classes.valueLabel,
}}
/>
</Grid>
const getAriaValueText = (value: number) =>
`${value}${units ? " " + units : ""}`;
<Grid item>
<Typography variant="overline" component="span" color="textSecondary">
{maxLabel ?? `${max}${units ? " " + units : ""}`}
</Typography>
</Grid>
</Grid>
const getValueLabelFormat = (value: number) =>
`${value}${units ? " " + units : ""}`;
<ErrorMessage name={field.name} />
</FormControl>
return (
<FormControl className={classes.root}>
<Grid container spacing={2} alignItems="center">
<Grid item>
<Typography
variant="overline"
component="span"
color="textSecondary"
>
{minLabel ?? `${min}${units ? " " + units : ""}`}
</Typography>
</Grid>
<Grid item xs>
<MuiSlider
valueLabelDisplay="auto"
min={min}
max={max}
getAriaValueText={getAriaValueText}
valueLabelFormat={getValueLabelFormat}
{...props}
value={value ?? min}
onClick={onBlur}
onChange={handleChange}
classes={{
root: classes.slider,
thumb: classes.thumb,
valueLabel: classes.valueLabel,
}}
/>
</Grid>
<Grid item>
<Typography
variant="overline"
component="span"
color="textSecondary"
>
{maxLabel ?? `${max}${units ? " " + units : ""}`}
</Typography>
</Grid>
</Grid>
</FormControl>
);
}}
/>
);
}

View File

@@ -1,5 +1,6 @@
import React from "react";
import { FieldProps } from "formik";
import { Controller, useWatch } from "react-hook-form";
import { IFieldProps } from "../utils";
import { Link } from "react-router-dom";
import queryString from "query-string";
@@ -31,30 +32,38 @@ const useStyles = makeStyles(theme =>
})
);
export interface ISubTableProps extends IFieldProps {
config: { parentLabel?: string[] };
label: string;
}
export default function SubTable({
form,
field,
control,
name,
docRef,
label,
config,
}: FieldProps<any> & { config: { parentLabel?: string[] }; label: string }) {
}: ISubTableProps) {
const classes = useStyles();
const values = useWatch({ control });
const router = useRouter();
const parentLabels = queryString.parse(router.location.search).parentLabel;
const _label = config?.parentLabel
? config.parentLabel.reduce((acc, curr) => {
if (acc !== "") return `${acc} - ${form.values[curr]}`;
else return form.values[curr];
if (acc !== "") return `${acc} - ${values[curr]}`;
else return values[curr];
}, "")
: "";
let subTablePath = "";
if (parentLabels)
subTablePath =
encodeURIComponent(`${form.values.ref.path}/${field.name}`) +
encodeURIComponent(`${docRef.path}/${name}`) +
`?parentLabel=${parentLabels},${label}`;
else
subTablePath =
encodeURIComponent(`${form.values.ref.path}/${field.name}`) +
encodeURIComponent(`${docRef.path}/${name}`) +
`?parentLabel=${encodeURIComponent(_label)}`;
return (

View File

@@ -1,7 +1,13 @@
import React from "react";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { makeStyles, createStyles } from "@material-ui/core";
import { TextField, TextFieldProps } from "formik-material-ui";
import {
makeStyles,
createStyles,
TextField,
FilledTextFieldProps,
} from "@material-ui/core";
const useStyles = makeStyles(theme =>
createStyles({
@@ -9,11 +15,20 @@ const useStyles = makeStyles(theme =>
})
);
export interface ITextProps extends TextFieldProps {
export interface ITextProps
extends IFieldProps,
Omit<FilledTextFieldProps, "variant" | "name"> {
fieldVariant?: "short" | "long" | "email" | "phone" | "number" | "url";
}
export default function Text({ fieldVariant = "short", ...props }: ITextProps) {
export default function Text({
control,
name,
docRef,
fieldVariant = "short",
editable,
...props
}: ITextProps) {
const classes = useStyles();
let variantProps = {};
@@ -27,7 +42,10 @@ export default function Text({ fieldVariant = "short", ...props }: ITextProps) {
break;
case "email":
variantProps = { type: "email", inputProps: { autoComplete: "email" } };
variantProps = {
// type: "email",
inputProps: { autoComplete: "email" },
};
break;
case "phone":
@@ -36,26 +54,42 @@ export default function Text({ fieldVariant = "short", ...props }: ITextProps) {
break;
case "number":
variantProps = { type: "number" };
variantProps = { inputMode: "numeric", pattern: "[0-9]*" };
break;
case "short":
default:
break;
}
return (
<TextField
key={`${props.form.initialValues.id}-${props.field.name}`}
variant="filled"
fullWidth
margin="none"
placeholder={props.label as string}
{...variantProps}
{...props}
id={`sidedrawer-field-${props.field.name}`}
label=""
hiddenLabel
//InputProps={{ disableUnderline: true }}
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => {
const handleChange = e => {
if (fieldVariant === "number") onChange(parseInt(e.target.value, 10));
else onChange(e.target.value);
};
return (
<TextField
variant="filled"
fullWidth
margin="none"
placeholder={props.label as string}
{...variantProps}
{...props}
onChange={handleChange}
onBlur={onBlur}
value={value}
id={`sidedrawer-field-${name}`}
label=""
hiddenLabel
disabled={editable === false}
/>
);
}}
/>
);
}

View File

@@ -1,124 +0,0 @@
import React, { useState } from "react";
import { FieldProps } from "formik";
import {
makeStyles,
createStyles,
FormControl,
Grid,
TextField,
IconButton,
List,
ListItem,
ListItemText,
ListItemSecondaryAction,
Divider,
} from "@material-ui/core";
import AddIcon from "@material-ui/icons/Add";
import DeleteIcon from "@material-ui/icons/Cancel";
import Label from "../Label";
import ErrorMessage from "../ErrorMessage";
const useStyles = makeStyles(theme =>
createStyles({
root: { display: "flex" },
list: { marginBottom: theme.spacing(2) },
})
);
export interface ITextMultiProps extends FieldProps {
label: React.ReactNode;
addItemLabel?: string;
addItemPlaceholder?: string;
}
export default function TextMulti({
form,
field,
label,
addItemLabel,
addItemPlaceholder,
}: ITextMultiProps) {
const classes = useStyles();
const [itemToAdd, setItemToAdd] = useState("");
const handleAddToList = () => {
if (Array.isArray(field.value))
form.setFieldValue(field.name, [...field.value, itemToAdd]);
else form.setFieldValue(field.name, [itemToAdd]);
setItemToAdd("");
};
const handleDeleteFromList = (i: number) => {
if (!Array.isArray(field.value)) form.setFieldValue(field.name, []);
const newValues = [...field.value];
newValues.splice(i, 1);
form.setFieldValue(field.name, newValues);
};
return (
<FormControl className={classes.root}>
<Label error={!!(form.errors[field.name] && form.touched[field.name])}>
{label}
</Label>
<List className={classes.list} disablePadding>
{Array.isArray(field.value) &&
field.value.map((item: string, i: number) => (
<React.Fragment key={i}>
<ListItem>
<ListItemText primary={item} />
<ListItemSecondaryAction>
<IconButton
edge="end"
aria-label="Remove"
onClick={() => {
handleDeleteFromList(i);
form.setFieldTouched(field.name);
}}
size="small"
>
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
<Grid container alignItems="center" spacing={1}>
<Grid item>
<IconButton
onClick={() => {
handleAddToList();
form.setFieldTouched(field.name);
}}
>
<AddIcon fontSize="small" />
</IconButton>
</Grid>
<Grid item xs>
<TextField
id={`${field.name}-temp`}
type="text"
onChange={e => setItemToAdd(e.target.value)}
variant="filled"
fullWidth
value={itemToAdd}
label={addItemLabel || `Add ${label}`}
placeholder={addItemPlaceholder}
onKeyPress={e => {
if (e.key === "Enter") handleAddToList();
}}
// NOTE: Field is not automatically touched, has to be set here
onBlur={() => form.setFieldTouched(field.name)}
/>
</Grid>
</Grid>
<ErrorMessage name={field.name} />
</FormControl>
);
}

View File

@@ -1,34 +1,54 @@
import React from "react";
import { Controller } from "react-hook-form";
import { IFieldProps } from "../utils";
import { Grid, IconButton } from "@material-ui/core";
import { TextField, TextFieldProps } from "formik-material-ui";
import {
Grid,
TextField,
FilledTextFieldProps,
IconButton,
} from "@material-ui/core";
import LaunchIcon from "@material-ui/icons/Launch";
export default function Url(props: TextFieldProps) {
export interface IUrlProps
extends IFieldProps,
Omit<FilledTextFieldProps, "name" | "variant"> {}
export default function Url({ control, name, docRef, ...props }: IUrlProps) {
return (
<Grid container wrap="nowrap">
<TextField
variant="filled"
fullWidth
margin="none"
placeholder={props.label as string}
type="url"
{...props}
id={`sidedrawer-field-${props.field.name}`}
label=""
hiddenLabel
<Controller
control={control}
name={name}
render={({ onChange, onBlur, value }) => (
<>
<TextField
variant="filled"
fullWidth
margin="none"
placeholder={props.label as string}
type="url"
{...props}
onChange={onChange}
onBlur={onBlur}
value={value || ""}
id={`sidedrawer-field-${name}`}
label=""
hiddenLabel
/>
<IconButton
component="a"
href={value as string}
target="_blank"
rel="noopener noreferrer"
style={{ width: 56 }}
disabled={!value}
>
<LaunchIcon />
</IconButton>
</>
)}
/>
<IconButton
component="a"
href={props.field.value}
target="_blank"
rel="noopener noreferrer"
style={{ width: 56 }}
disabled={!props.field.value}
>
<LaunchIcon />
</IconButton>
</Grid>
);
}

View File

@@ -1,26 +1,18 @@
import React, { lazy, useEffect } from "react";
import { Formik, Form as FormikForm, Field } from "formik";
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
import DateFnsUtils from "@date-io/date-fns";
import React, { lazy } from "react";
import { useForm } from "react-hook-form";
import _isFunction from "lodash/isFunction";
import _isEmpty from "lodash/isEmpty";
import { useFiretableContext } from "contexts/firetableContext";
import { Grid } from "@material-ui/core";
import { Fields, Values, getInitialValues, Field } from "./utils";
import { FieldType } from "constants/fields";
import Autosave from "./Autosave";
import FieldWrapper from "./FieldWrapper";
import Text from "./Fields/Text";
import { FieldType } from "constants/fields";
const Url = lazy(() =>
import("./Fields/Url" /* webpackChunkName: "SideDrawer-Url" */)
);
const Percentage = lazy(() =>
import("./Fields/Percentage" /* webpackChunkName: "SideDrawer-Percentage" */)
);
const SingleSelect = lazy(() =>
import(
"./Fields/SingleSelect" /* webpackChunkName: "SideDrawer-SingleSelect" */
@@ -45,6 +37,9 @@ const Checkbox = lazy(() =>
const Rating = lazy(() =>
import("./Fields/Rating" /* webpackChunkName: "SideDrawer-Rating" */)
);
const Percentage = lazy(() =>
import("./Fields/Percentage" /* webpackChunkName: "SideDrawer-Percentage" */)
);
const Color = lazy(() =>
import("./Fields/Color" /* webpackChunkName: "SideDrawer-Color" */)
);
@@ -82,61 +77,6 @@ const Action = lazy(() =>
import("./Fields/Action" /* webpackChunkName: "SideDrawer-Action" */)
);
export type Values = { [key: string]: any };
export type Field = {
type?: FieldType;
name?: string;
label?: React.ReactNode;
[key: string]: any;
};
export type Fields = (Field | ((values: Values) => Field))[];
const initializeValue = type => {
switch (type) {
case FieldType.singleSelect:
case FieldType.multiSelect:
case FieldType.image:
case FieldType.file:
return [];
case FieldType.date:
case FieldType.dateTime:
return null;
case FieldType.checkbox:
return false;
case FieldType.number:
return 0;
case FieldType.json:
return {};
break;
case FieldType.shortText:
case FieldType.longText:
case FieldType.email:
case FieldType.phone:
case FieldType.url:
case FieldType.code:
case FieldType.richText:
default:
break;
}
};
const getInitialValues = (fields: Fields): Values =>
fields.reduce((acc, _field) => {
const field = _isFunction(_field) ? _field({}) : _field;
if (!field.name) return acc;
let _type = field.type;
if (field.config && field.config.renderFieldType) {
_type = field.config.renderFieldType;
}
const value = initializeValue(_type);
return { ...acc, [field.name]: value };
}, {});
export interface IFormProps {
fields: Fields;
values: Values;
@@ -144,8 +84,21 @@ export interface IFormProps {
export default function Form({ fields, values }: IFormProps) {
const initialValues = getInitialValues(fields);
const { ref: docRef, ...rowValues } = values;
const defaultValues = { ...initialValues, ...rowValues };
const { sideDrawerRef } = useFiretableContext();
const { register, control } = useForm({
mode: "onBlur",
defaultValues,
});
// Update field values when Firestore document updates
// useEffect(() => {
// console.log("RESET", defaultValues);
// reset(defaultValues);
// }, [reset, JSON.stringify(rowValues)]);
// const { sideDrawerRef } = useFiretableContext();
// useEffect(() => {
// const column = sideDrawerRef?.current?.cell?.column;
// if (!column) return;
@@ -158,206 +111,146 @@ export default function Form({ fields, values }: IFormProps) {
// }, [sideDrawerRef?.current]);
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Formik
enableReinitialize
initialValues={{ ...initialValues, ...values }}
onSubmit={(values, actions) => {
// Mark as submitted. We use Autosave instead.
actions.setSubmitting(false);
}}
>
{({ values, errors }) => (
<FormikForm>
<Autosave values={values} errors={errors} />
<form>
<Autosave
control={control}
defaultValues={defaultValues}
docRef={docRef}
/>
<Grid container spacing={4} direction="column" wrap="nowrap">
{fields.map((_field, i) => {
// Call the field function with values if necessary
// Otherwise, just use the field object
const field: Field = _isFunction(_field)
? _field(values)
: _field;
const { type, ...fieldProps } = field;
let _type = type;
if (field.config && field.config.renderFieldType) {
_type = field.config.renderFieldType;
}
// TODO: handle get initial field value for when a field is later
// shown to prevent uncontrolled components becoming controlled
<Grid container spacing={4} direction="column" wrap="nowrap">
{fields.map((_field, i) => {
// Call the field function with values if necessary
// Otherwise, just use the field object
const field: Field = _isFunction(_field) ? _field(values) : _field;
const { type, ...fieldProps } = field;
let _type = type;
let renderedField: React.ReactNode = null;
// Derivative field support
if (field.config && field.config.renderFieldType) {
_type = field.config.renderFieldType;
}
switch (_type) {
case FieldType.shortText:
case FieldType.longText:
case FieldType.email:
case FieldType.phone:
case FieldType.number:
renderedField = (
<Field {...fieldProps} component={Text} hiddenLabel />
);
break;
let fieldComponent: React.ComponentType<any> | null = null;
case FieldType.url:
renderedField = (
<Field {...fieldProps} component={Url} hiddenLabel />
);
break;
switch (_type) {
case FieldType.shortText:
case FieldType.longText:
case FieldType.email:
case FieldType.phone:
case FieldType.number:
fieldComponent = Text;
break;
case FieldType.percentage:
renderedField = (
<Field
{...fieldProps}
component={Percentage}
hiddenLabel
/>
);
break;
case FieldType.url:
fieldComponent = Url;
break;
case FieldType.singleSelect:
renderedField = (
<Field
{...fieldProps}
component={SingleSelect}
hiddenLabel
/>
);
break;
case FieldType.singleSelect:
fieldComponent = SingleSelect;
break;
case FieldType.multiSelect:
renderedField = (
<Field
{...fieldProps}
component={MultiSelect}
hiddenLabel
/>
);
break;
case FieldType.multiSelect:
fieldComponent = MultiSelect;
break;
case FieldType.date:
renderedField = (
<Field
{...fieldProps}
component={DatePicker}
hiddenLabel
/>
);
break;
case FieldType.date:
fieldComponent = DatePicker;
break;
case FieldType.dateTime:
renderedField = (
<Field
{...fieldProps}
component={DateTimePicker}
hiddenLabel
/>
);
break;
case FieldType.dateTime:
fieldComponent = DateTimePicker;
break;
case FieldType.checkbox:
renderedField = (
<Checkbox {...fieldProps} name={fieldProps.name!} />
);
break;
case FieldType.checkbox:
fieldComponent = Checkbox;
break;
case FieldType.color:
renderedField = <Field {...fieldProps} component={Color} />;
break;
case FieldType.color:
fieldComponent = Color;
break;
case FieldType.slider:
renderedField = (
<Field {...fieldProps} component={Slider} />
);
break;
case FieldType.slider:
fieldComponent = Slider;
break;
case FieldType.richText:
renderedField = (
<Field {...fieldProps} component={RichText} />
);
break;
case FieldType.richText:
fieldComponent = RichText;
break;
case FieldType.image:
renderedField = (
<Field
{...fieldProps}
component={ImageUploader}
docRef={values.ref}
/>
);
break;
case FieldType.image:
fieldComponent = ImageUploader;
break;
case FieldType.file:
renderedField = (
<Field
{...fieldProps}
component={FileUploader}
docRef={values.ref}
/>
);
break;
case FieldType.file:
fieldComponent = FileUploader;
break;
case FieldType.rating:
renderedField = (
<Field {...fieldProps} component={Rating} />
);
break;
case FieldType.rating:
fieldComponent = Rating;
break;
case FieldType.connectTable:
renderedField = (
<Field {...fieldProps} component={ConnectTable} />
);
break;
case FieldType.percentage:
fieldComponent = Percentage;
break;
case FieldType.subTable:
renderedField = (
<Field {...fieldProps} component={SubTable} />
);
break;
case FieldType.connectTable:
fieldComponent = ConnectTable;
break;
case FieldType.action:
renderedField = (
<Field {...fieldProps} component={Action} />
);
break;
case FieldType.subTable:
fieldComponent = SubTable;
break;
case FieldType.json:
renderedField = (
<Field {...fieldProps} component={JsonEditor} />
);
break;
case FieldType.code:
renderedField = <Field {...fieldProps} component={Code} />;
break;
case undefined:
return null;
case FieldType.action:
fieldComponent = Action;
break;
default:
break;
}
case FieldType.json:
fieldComponent = JsonEditor;
break;
return (
<FieldWrapper
key={fieldProps.name ?? i}
type={_type}
name={field.name}
label={field.label}
>
{renderedField}
</FieldWrapper>
);
case FieldType.code:
fieldComponent = Code;
break;
case undefined:
// default:
return null;
default:
break;
}
// Should not reach this state
if (fieldComponent === null) {
console.error("`fieldComponent` is null");
return null;
}
return (
<FieldWrapper
key={fieldProps.name ?? i}
type={_type}
name={field.name}
label={field.label}
>
{React.createElement(fieldComponent, {
...fieldProps,
control,
docRef,
})}
</FieldWrapper>
);
})}
<FieldWrapper
type="debug"
name="_ft_debug_path"
label="Document Path"
debugText={values.ref?.path ?? values.id ?? "No ref"}
/>
</Grid>
</FormikForm>
)}
</Formik>
</MuiPickersUtilsProvider>
<FieldWrapper
type="debug"
name="_ft_debug_path"
label="Document Path"
debugText={values.ref?.path ?? values.id ?? "No ref"}
/>
</Grid>
</form>
);
}

View File

@@ -0,0 +1,65 @@
import { Control } from "react-hook-form";
import _isFunction from "lodash/isFunction";
import { FieldType } from "constants/fields";
export interface IFieldProps {
control: Control;
name: string;
docRef: firebase.firestore.DocumentReference;
editable?: boolean;
}
export type Values = { [key: string]: any };
export type Field = {
type?: FieldType;
name: string;
label?: string;
[key: string]: any;
};
export type Fields = (Field | ((values: Values) => Field))[];
export const initializeValue = type => {
switch (type) {
case FieldType.singleSelect:
case FieldType.multiSelect:
case FieldType.image:
case FieldType.file:
return [];
case FieldType.date:
case FieldType.dateTime:
return null;
case FieldType.checkbox:
return false;
case FieldType.number:
return 0;
case FieldType.json:
return {};
case FieldType.shortText:
case FieldType.longText:
case FieldType.email:
case FieldType.phone:
case FieldType.url:
case FieldType.code:
case FieldType.richText:
default:
break;
}
};
export const getInitialValues = (fields: Fields): Values =>
fields.reduce((acc, _field) => {
const field = _isFunction(_field) ? _field({}) : _field;
if (!field.name) return acc;
let _type = field.type;
if (field.config && field.config.renderFieldType) {
_type = field.config.renderFieldType;
}
const value = initializeValue(_type);
return { ...acc, [field.name]: value };
}, {});

View File

@@ -2,14 +2,14 @@ import React, { useState, useEffect } from "react";
import clsx from "clsx";
import _isNil from "lodash/isNil";
import _sortBy from "lodash/sortBy";
import _findIndex from "lodash/findIndex";
import { Drawer, Fab } from "@material-ui/core";
import ChevronIcon from "@material-ui/icons/KeyboardArrowLeft";
import ChevronUpIcon from "@material-ui/icons/KeyboardArrowUp";
import ChevronDownIcon from "@material-ui/icons/KeyboardArrowDown";
import Form, { Field } from "./Form";
import Form from "./Form";
import { Field } from "./Form/utils";
import ErrorBoundary from "components/ErrorBoundary";
import { useStyles } from "./useStyles";
@@ -49,7 +49,7 @@ export default function SideDrawer() {
setCell!(cell => ({ column: cell!.column, row }));
const idx = _findIndex(tableState?.columns, ["key", cell!.column]);
const idx = tableState?.columns[cell!.column]?.index;
dataGridRef?.current?.selectCell({ rowIdx: row, idx });
};
@@ -116,7 +116,11 @@ export default function SideDrawer() {
<ErrorBoundary>
<div className={classes.drawerContents}>
{open && fields && cell && (
<Form fields={fields} values={tableState?.rows[cell.row] ?? {}} />
<Form
key={cell.row}
fields={fields}
values={tableState?.rows[cell.row] ?? {}}
/>
)}
</div>
</ErrorBoundary>

View File

@@ -63,7 +63,7 @@ export default function FormDialog({
label="Column Header"
type="text"
fullWidth
onChange={(e) => {
onChange={e => {
setColumnLabel(e.target.value);
}}
/>
@@ -75,7 +75,7 @@ export default function FormDialog({
label="Field Key"
type="text"
fullWidth
onChange={(e) => {
onChange={e => {
setFieldKey(e.target.value);
}}
/>

View File

@@ -62,7 +62,7 @@ export default function WebhooksDialog({ open, handleClose }) {
const fullWidth = true;
const maxWidth: DialogProps["maxWidth"] = "xl";
const handleChange = (key: string) => (value: any) => {
setState((s) => ({ ...s, [key]: value }));
setState(s => ({ ...s, [key]: value }));
};
const initializeWebhooksConfig = () => {
const secret = makeId(32);
@@ -122,7 +122,7 @@ export default function WebhooksDialog({ open, handleClose }) {
labelPlacement="end"
checked={state.enabled}
onChange={
(e) => {
e => {
handleChange("enabled")(!state.enabled);
}
// handleChange("isCollectionGroup", !formState.isCollectionGroup)
@@ -161,7 +161,7 @@ export default function WebhooksDialog({ open, handleClose }) {
<Typography variant="body1">
please set the question reference in typeform to the following
field keys :{" "}
{tableFields.map((key) => (
{tableFields.map(key => (
<>
{" "}
<b key={key}>{key}</b>,

View File

@@ -10,7 +10,7 @@ import {
import { FieldType } from "constants/fields";
const styles = (theme) =>
const styles = theme =>
createStyles({
root: {
width: "calc(100% - 1px)",

View File

@@ -48,9 +48,8 @@ const Percentage = lazy(() =>
*/
export const getFormatter = (column: any) => {
let _type = column.type;
if (column.config.renderFieldType) {
_type = column.config.renderFieldType;
}
if (column.config?.renderFieldType) _type = column.config.renderFieldType;
switch (_type) {
case FieldType.date:
case FieldType.dateTime:

View File

@@ -6,7 +6,7 @@ import { makeStyles, createStyles } from "@material-ui/core";
import ErrorBoundary from "components/ErrorBoundary";
import { useFiretableContext } from "../../../contexts/firetableContext";
import _get from "lodash/get";
const useStyles = makeStyles((theme) =>
const useStyles = makeStyles(theme =>
createStyles({
"@global": {
".rdg-cell-mask.rdg-selected": {

View File

@@ -58,7 +58,7 @@ export default function Table() {
} = useFiretableContext();
const { userDoc } = useAppContext();
const userDocHiddenFields =
userDoc.state.doc?.tables[`${tableState?.tablePath}`]?.hiddenFields ?? [];
userDoc.state.doc?.tables?.[`${tableState?.tablePath}`]?.hiddenFields ?? [];
const rowsContainerRef = useRef<HTMLDivElement>(null);
// Gets more rows when scrolled down.
@@ -108,7 +108,7 @@ export default function Table() {
...column,
width: column.width ? (column.width > 380 ? 380 : column.width) : 150,
}))
.filter((column) => !userDocHiddenFields.includes(column.key));
.filter(column => !userDocHiddenFields.includes(column.key));
columns.push({
isNew: true,
key: "new",
@@ -167,7 +167,7 @@ export default function Table() {
rowGetter={rowGetter}
rowsCount={rows.length}
rowKey={"id" as "id"}
onGridRowsUpdated={(event) => {
onGridRowsUpdated={event => {
const { action, cellKey, updated } = event;
if (action === "CELL_UPDATE" && updated !== null)
updateCell!(rows[event.toRow].ref, cellKey as string, updated);
@@ -199,7 +199,7 @@ export default function Table() {
enableCellSelect
onScroll={handleScroll}
ref={dataGridRef}
RowsContainer={(props) => (
RowsContainer={props => (
<>
<div {...props} ref={rowsContainerRef} />
<Grid

View File

@@ -66,7 +66,7 @@ const firetableContext = React.createContext<Partial<FiretableContextProps>>(
);
export default firetableContext;
export const firetableUser = (currentUser) => {
export const firetableUser = currentUser => {
const {
displayName,
email,
@@ -102,10 +102,10 @@ export const FiretableContextProvider: React.FC = ({ children }) => {
if (tables && userRoles && !sections) {
const filteredTables = _sortBy(tables, "name")
.filter(
(table) =>
!table.roles || table.roles.some((role) => userRoles.includes(role))
table =>
!table.roles || table.roles.some(role => userRoles.includes(role))
)
.map((table) => ({
.map(table => ({
...table,
section: table.section ? table.section.toUpperCase().trim() : "OTHER",
}));
@@ -118,7 +118,7 @@ export const FiretableContextProvider: React.FC = ({ children }) => {
useEffect(() => {
if (currentUser && !userClaims) {
currentUser.getIdTokenResult(true).then((results) => {
currentUser.getIdTokenResult(true).then(results => {
setUserRoles(results.claims.roles || []);
setUserClaims(results.claims);
});
@@ -145,10 +145,10 @@ export const FiretableContextProvider: React.FC = ({ children }) => {
updatedBy: _ft_updatedBy,
})
.then(
(success) => {
success => {
console.log("successful update");
},
(error) => {
error => {
if (error.code === "permission-denied") {
open({
message: `You don't have permissions to make this change`,

View File

@@ -112,7 +112,7 @@ const useUploader = () => {
if (docRef && docRef.update)
docRef.update({ [fieldName]: newValue });
// Also call callback if it exists
// IMPORTANT: Formik may not update its local values after this
// IMPORTANT: SideDrawer form may not update its local values after this
// function updates the doc, so you MUST update it manually
// using this callback
if (onComplete) onComplete(newValue);

View File

@@ -106,6 +106,15 @@
"@algolia/logger-common" "4.1.0"
"@algolia/requester-common" "4.1.0"
"@antlerengineering/components@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@antlerengineering/components/-/components-0.4.1.tgz#68955a5eebac4f3022442f6c148ed5aa0d7b6e48"
integrity sha512-7MMP75dMrfx/OrQk3lL4/3wWhYCvTeyGuhqTbohpWG7FSS513YBoh7Q7wly0XASB0Shz5gzuFrDZ5s4WfpSf9Q==
dependencies:
dompurify "^2.0.10"
lodash "^4.17.15"
lodash-es "^4.17.15"
"@antlerengineering/multiselect@^0.3.14":
version "0.3.14"
resolved "https://registry.yarnpkg.com/@antlerengineering/multiselect/-/multiselect-0.3.14.tgz#d24c983913ba1a2272bfe4dd5afbb081aedc95dc"
@@ -148,7 +157,7 @@
semver "^5.4.1"
source-map "^0.5.0"
"@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.4.5":
"@babel/core@^7.1.0", "@babel/core@^7.4.5":
version "7.8.7"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.7.tgz#b69017d221ccdeb203145ae9da269d72cf102f3b"
integrity sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA==
@@ -393,7 +402,7 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.4.3", "@babel/parser@^7.8.4", "@babel/parser@^7.8.6", "@babel/parser@^7.8.7":
"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.4", "@babel/parser@^7.8.6", "@babel/parser@^7.8.7":
version "7.8.8"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.8.tgz#4c3b7ce36db37e0629be1f0d50a571d2f86f6cd4"
integrity sha512-mO5GWzBPsPf6865iIbzNE0AvkKF3NE+2S3eRUpE+FE07BOAkXh6G+GW/Pj01hhXjve1WScbaIO4UlY1JKeqCcA==
@@ -407,7 +416,7 @@
"@babel/helper-remap-async-to-generator" "^7.8.3"
"@babel/plugin-syntax-async-generators" "^7.8.0"
"@babel/plugin-proposal-class-properties@7.8.3", "@babel/plugin-proposal-class-properties@^7.1.0":
"@babel/plugin-proposal-class-properties@7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz#5e06654af5cd04b608915aada9b2a6788004464e"
integrity sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==
@@ -456,7 +465,7 @@
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/plugin-syntax-numeric-separator" "^7.8.3"
"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.8.3":
"@babel/plugin-proposal-object-rest-spread@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb"
integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==
@@ -661,7 +670,7 @@
"@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3"
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/plugin-transform-flow-strip-types@7.8.3", "@babel/plugin-transform-flow-strip-types@^7.8.3":
"@babel/plugin-transform-flow-strip-types@7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.8.3.tgz#da705a655466b2a9b36046b57bf0cbcd53551bd4"
integrity sha512-g/6WTWG/xbdd2exBBzMfygjX/zw4eyNC4X8pRaq7aRHRoDUCzAIu3kGYIXviOv8BjCuWm8vDBwjHcjiRNgXrPA==
@@ -954,7 +963,7 @@
levenary "^1.1.1"
semver "^5.5.0"
"@babel/preset-env@^7.1.6", "@babel/preset-env@^7.4.5":
"@babel/preset-env@^7.4.5":
version "7.8.7"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.7.tgz#1fc7d89c7f75d2d70c2b6768de6c2e049b3cb9db"
integrity sha512-BYftCVOdAYJk5ASsznKAUl53EMhfBbr8CJ1X+AJLfGPscQkwJFiaV/Wn9DPH/7fzm2v6iRYJKYHSqyynTGw0nw==
@@ -1017,14 +1026,6 @@
levenary "^1.1.1"
semver "^5.5.0"
"@babel/preset-flow@^7.0.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.8.3.tgz#52af74c6a4e80d889bd9436e8e278d0fecac6e18"
integrity sha512-iCXFk+T4demnq+dNLLvlGOgvYF6sPZ/hS1EmswugOqh1Ysp2vuiqJzpgsnp5rW8+6dLJT/0CXDzye28ZH6BAfQ==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/plugin-transform-flow-strip-types" "^7.8.3"
"@babel/preset-react@7.8.3", "@babel/preset-react@^7.0.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.8.3.tgz#23dc63f1b5b0751283e04252e78cf1d6589273d2"
@@ -1036,7 +1037,7 @@
"@babel/plugin-transform-react-jsx-self" "^7.8.3"
"@babel/plugin-transform-react-jsx-source" "^7.8.3"
"@babel/preset-typescript@7.8.3", "@babel/preset-typescript@^7.1.0":
"@babel/preset-typescript@7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz#90af8690121beecd9a75d0cc26c6be39d1595d13"
integrity sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA==
@@ -1044,17 +1045,6 @@
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/plugin-transform-typescript" "^7.8.3"
"@babel/register@^7.0.0":
version "7.8.6"
resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.8.6.tgz#a1066aa6168a73a70c35ef28cc5865ccc087ea69"
integrity sha512-7IDO93fuRsbyml7bAafBQb3RcBGlCpU4hh5wADA2LJEEcYk92WkwFZ0pHyIi2fb5Auoz1714abETdZKCOxN0CQ==
dependencies:
find-cache-dir "^2.0.0"
lodash "^4.17.13"
make-dir "^2.1.0"
pirates "^4.0.0"
source-map-support "^0.5.16"
"@babel/runtime@7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308"
@@ -1062,7 +1052,7 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.5", "@babel/runtime@^7.7.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
version "7.8.7"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.7.tgz#8fefce9802db54881ba59f90bb28719b4996324d"
integrity sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg==
@@ -1076,6 +1066,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.8.3":
version "7.10.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c"
integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.4.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
version "7.8.6"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
@@ -1085,7 +1082,7 @@
"@babel/parser" "^7.8.6"
"@babel/types" "^7.8.6"
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.5", "@babel/traverse@^7.6.2", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6":
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6":
version "7.8.6"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff"
integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==
@@ -1558,14 +1555,23 @@
"@types/istanbul-reports" "^1.1.1"
"@types/yargs" "^13.0.0"
"@material-ui/codemod@^4.3.0":
version "4.5.0"
resolved "https://registry.yarnpkg.com/@material-ui/codemod/-/codemod-4.5.0.tgz#e258a4865a7d68506579e046a6170fd742ffdf4f"
integrity sha512-qgx6I1T+kTL6TkbtTu+Bn4NIi5AgQ8SR8R/bXpivKPkrSADCsoanfJrS3atyCi8Sykl0DZiLdXxQOAcjP1rh4w==
"@material-ui/core@^4.11.0":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.11.0.tgz#b69b26e4553c9e53f2bfaf1053e216a0af9be15a"
integrity sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g==
dependencies:
"@babel/core" "^7.4.5"
"@babel/traverse" "^7.6.2"
jscodeshift-add-imports "^1.0.1"
"@babel/runtime" "^7.4.4"
"@material-ui/styles" "^4.10.0"
"@material-ui/system" "^4.9.14"
"@material-ui/types" "^5.1.0"
"@material-ui/utils" "^4.10.2"
"@types/react-transition-group" "^4.2.0"
clsx "^1.0.4"
hoist-non-react-statics "^3.3.2"
popper.js "1.16.1-lts"
prop-types "^15.7.2"
react-is "^16.8.0"
react-transition-group "^4.4.0"
"@material-ui/core@^4.7.1":
version "4.9.7"
@@ -1585,25 +1591,6 @@
react-is "^16.8.0"
react-transition-group "^4.3.0"
"@material-ui/core@^4.9.13":
version "4.9.13"
resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.9.13.tgz#024962bcdda05139e1bad17a1815bf4088702b15"
integrity sha512-GEXNwUr+laZ0N+F1efmHB64Fyg+uQIRXLqbSejg3ebSXgLYNpIjnMOPRfWdu4rICq0dAIgvvNXGkKDMcf3AMpA==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/react-transition-group" "^4.3.0"
"@material-ui/styles" "^4.9.13"
"@material-ui/system" "^4.9.13"
"@material-ui/types" "^5.0.1"
"@material-ui/utils" "^4.9.12"
"@types/react-transition-group" "^4.2.0"
clsx "^1.0.4"
hoist-non-react-statics "^3.3.2"
popper.js "^1.16.1-lts"
prop-types "^15.7.2"
react-is "^16.8.0"
react-transition-group "^4.3.0"
"@material-ui/icons@^4.5.1", "@material-ui/icons@^4.9.1":
version "4.9.1"
resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.9.1.tgz#fdeadf8cb3d89208945b33dbc50c7c616d0bd665"
@@ -1611,13 +1598,13 @@
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/lab@^4.0.0-alpha.52":
version "4.0.0-alpha.52"
resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.52.tgz#a868d8c772a90db091a6bfc89aed21a0e2c486bf"
integrity sha512-aDoRWA+q3/T2spvvQrxPz8qjtf9l8NhaG9ZISBy9zD3cJ05s3KfEP2nrsoBOBgonlSMFQQzUTnxAwThwsJfllw==
"@material-ui/lab@^4.0.0-alpha.56":
version "4.0.0-alpha.56"
resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz#ff63080949b55b40625e056bbda05e130d216d34"
integrity sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/utils" "^4.9.6"
"@material-ui/utils" "^4.10.2"
clsx "^1.0.4"
prop-types "^15.7.2"
react-is "^16.8.0"
@@ -1634,24 +1621,14 @@
react-transition-group "^4.0.0"
rifm "^0.7.0"
"@material-ui/react-transition-group@^4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@material-ui/react-transition-group/-/react-transition-group-4.3.0.tgz#92529142addb5cc179dbf42d246c7e3fe4d6104b"
integrity sha512-CwQ0aXrlUynUTY6sh3UvKuvye1o92en20VGAs6TORnSxUYeRmkX8YeTUN3lAkGiBX1z222FxLFO36WWh6q73rQ==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
"@material-ui/styles@^4.9.13":
version "4.9.13"
resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.9.13.tgz#08b3976bdd21c38bc076693d95834f97539f3b15"
integrity sha512-lWlXJanBdHQ18jW/yphedRokHcvZD1GdGzUF/wQxKDsHwDDfO45ZkAxuSBI202dG+r1Ph483Z3pFykO2obeSRA==
"@material-ui/styles@^4.10.0":
version "4.10.0"
resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.10.0.tgz#2406dc23aa358217aa8cc772e6237bd7f0544071"
integrity sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==
dependencies:
"@babel/runtime" "^7.4.4"
"@emotion/hash" "^0.8.0"
"@material-ui/types" "^5.0.1"
"@material-ui/types" "^5.1.0"
"@material-ui/utils" "^4.9.6"
clsx "^1.0.4"
csstype "^2.5.2"
@@ -1688,13 +1665,14 @@
jss-plugin-vendor-prefixer "^10.0.3"
prop-types "^15.7.2"
"@material-ui/system@^4.9.13":
version "4.9.13"
resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.9.13.tgz#adefb3b6a5ddf0b00fe4e82ac63bb48276e9749d"
integrity sha512-6AlpvdW6KJJ5bF1Xo2OD13sCN8k+nlL36412/bWnWZOKIfIMo/Lb8c8d1DOIaT/RKWxTEUaWnKZjabVnA3eZjA==
"@material-ui/system@^4.9.14":
version "4.9.14"
resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.9.14.tgz#4b00c48b569340cefb2036d0596b93ac6c587a5f"
integrity sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/utils" "^4.9.6"
csstype "^2.5.2"
prop-types "^15.7.2"
"@material-ui/system@^4.9.6":
@@ -1711,24 +1689,15 @@
resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.0.0.tgz#26d6259dc6b39f4c2e1e9aceff7a11e031941741"
integrity sha512-UeH2BuKkwDndtMSS0qgx1kCzSMw+ydtj0xx/XbFtxNSTlXydKwzs5gVW5ZKsFlAkwoOOQ9TIsyoCC8hq18tOwg==
"@material-ui/types@^5.0.1":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.0.1.tgz#c4954063cdc196eb327ee62c041368b1aebb6d61"
integrity sha512-wURPSY7/3+MAtng3i26g+WKwwNE3HEeqa/trDBR5+zWKmcjO+u9t7Npu/J1r+3dmIa/OeziN9D/18IrBKvKffw==
"@material-ui/types@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2"
integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==
"@material-ui/utils@^4.9.12":
version "4.9.12"
resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.9.12.tgz#0d639f1c1ed83fffb2ae10c21d15a938795d9e65"
integrity sha512-/0rgZPEOcZq5CFA4+4n6Q6zk7fi8skHhH2Bcra8R3epoJEYy5PL55LuMazPtPH1oKeRausDV/Omz4BbgFsn1HQ==
dependencies:
"@babel/runtime" "^7.4.4"
prop-types "^15.7.2"
react-is "^16.8.0"
"@material-ui/utils@^4.9.6":
version "4.9.6"
resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.9.6.tgz#5f1f9f6e4df9c8b6a263293b68c94834248ff157"
integrity sha512-gqlBn0JPPTUZeAktn1rgMcy9Iczrr74ecx31tyZLVGdBGGzsxzM6PP6zeS7FuoLS6vG4hoZP7hWnOoHtkR0Kvw==
"@material-ui/utils@^4.10.2", "@material-ui/utils@^4.9.6":
version "4.10.2"
resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.10.2.tgz#3fd5470ca61b7341f1e0468ac8f29a70bf6df321"
integrity sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==
dependencies:
"@babel/runtime" "^7.4.4"
prop-types "^15.7.2"
@@ -1955,14 +1924,6 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/backbone@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@types/backbone/-/backbone-1.4.1.tgz#aa03f9f69994bd96646c50cfc70b5f30d38aafaa"
integrity sha512-KYfGuQy4d2vvYXbn0uHFZ6brFLndatTMomxBlljpbWf4kFpA3BG/6LA3ec+J9iredrX6eAVI7sm9SVAvwiIM6g==
dependencies:
"@types/jquery" "*"
"@types/underscore" "*"
"@types/bytebuffer@^5.0.40":
version "5.0.40"
resolved "https://registry.yarnpkg.com/@types/bytebuffer/-/bytebuffer-5.0.40.tgz#d6faac40dcfb09cd856cdc4c01d3690ba536d3ee"
@@ -1971,11 +1932,6 @@
"@types/long" "*"
"@types/node" "*"
"@types/cash@^0.0.3":
version "0.0.3"
resolved "https://registry.yarnpkg.com/@types/cash/-/cash-0.0.3.tgz#770d6382c605bb4f8572f17cea6f40cec5832496"
integrity sha512-gS24kdFuVwfo5h7IlStnXyBSIH4e9aFIhNHb4w+o5DwbYDeQJv+i9heh7u7nSvqnOP3v34tQMTe7VoJp2US08w==
"@types/chroma-js@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/chroma-js/-/chroma-js-2.0.0.tgz#b0fc98c8625d963f14e8138e0a7961103303ab22"
@@ -2056,13 +2012,6 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
"@types/jquery@*":
version "3.3.33"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.33.tgz#61d9cbd4004ffcdf6cf7e34720a87a5625a7d8e9"
integrity sha512-U6IdXYGkfUI42SR79vB2Spj+h1Ly3J3UZjpd8mi943lh126TK7CB+HZOxGh2nM3IySor7wqVQdemD/xtydsBKA==
dependencies:
"@types/sizzle" "*"
"@types/js-yaml@^3.12.2":
version "3.12.3"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.3.tgz#abf383c5b639d0aa8b8c4a420d6a85f703357d6c"
@@ -2093,11 +2042,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.2.tgz#ace1880c03594cc3e80206d96847157d8e7fa349"
integrity sha512-bnoqK579sAYrQbp73wwglccjJ4sfRdKU7WNEZ5FW4K2U6Kc0/eZ5kvXG0JKsEKFB50zrFmfFt52/cvBbZa7eXg==
"@types/node@12.7.4":
version "12.7.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.4.tgz#64db61e0359eb5a8d99b55e05c729f130a678b04"
integrity sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ==
"@types/node@^10.1.0":
version "10.17.17"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.17.tgz#7a183163a9e6ff720d86502db23ba4aade5999b8"
@@ -2169,13 +2113,21 @@
"@types/react" "*"
"@types/react-transition-group@^4.2.0":
version "4.2.4"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.2.4.tgz#c7416225987ccdb719262766c1483da8f826838d"
integrity sha512-8DMUaDqh0S70TjkqU0DxOu80tFUiiaS9rxkWip/nb7gtvAsbqOXm02UCmR8zdcjWujgeYPiPNTVpVpKzUDotwA==
version "4.4.0"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.0.tgz#882839db465df1320e4753e6e9f70ca7e9b4d46d"
integrity sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^16.9.2":
"@types/react@*":
version "16.9.43"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.43.tgz#c287f23f6189666ee3bebc2eb8d0f84bcb6cdb6b"
integrity sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/react@^16.9.2":
version "16.9.23"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.23.tgz#1a66c6d468ba11a8943ad958a8cb3e737568271c"
integrity sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw==
@@ -2183,11 +2135,6 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/sizzle@*":
version "2.3.2"
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
@@ -2205,11 +2152,6 @@
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.4.tgz#922d092c84a776a59acb0bd6785fd82b59b9bad5"
integrity sha512-6jtHrHpmiXOXoJ31Cg9R+iEVwuEKPf0XHwFUI93eEPXx492/J2JHyafkleKE2EYzZprayk9FSjTyK1GDqcwDng==
"@types/underscore@*":
version "1.9.4"
resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.9.4.tgz#22d1a3e6b494608e430221ec085fa0b7ccee7f33"
integrity sha512-CjHWEMECc2/UxOZh0kpiz3lEyX2Px3rQS9HzD20lxMvx571ivOBQKeLnqEjxUY0BMgp6WJWo/pQLRBwMW5v4WQ==
"@types/yargs-parser@*":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
@@ -2894,11 +2836,6 @@ ast-types-flow@0.0.7, ast-types-flow@^0.0.7:
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
ast-types@0.11.7:
version "0.11.7"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.7.tgz#f318bf44e339db6a320be0009ded64ec1471f46c"
integrity sha512-2mP3TwtkY/aTv5X3ZsMpNAbOnyoC/aMJwJSoaELPkHId0nSQgFcnU4dRW3isxiz7+zBexk0ym3WNVjMiQBnJSw==
astral-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
@@ -2996,11 +2933,6 @@ babel-code-frame@^6.22.0:
esutils "^2.0.2"
js-tokens "^3.0.2"
babel-core@^7.0.0-bridge.0:
version "7.0.0-bridge.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==
babel-eslint@10.0.3:
version "10.0.3"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a"
@@ -3970,9 +3902,9 @@ clone@^1.0.2:
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
clsx@^1.0.2, clsx@^1.0.4:
version "1.1.0"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.0.tgz#62937c6adfea771247c34b54d320fb99624f5702"
integrity sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA==
version "1.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
co@^4.6.0:
version "4.6.0"
@@ -4056,11 +3988,6 @@ colors@1.0.3, colors@1.0.x:
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
colors@^1.1.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
colour@~0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
@@ -4555,12 +4482,12 @@ css-tree@1.0.0-alpha.37:
mdn-data "2.0.4"
source-map "^0.6.1"
css-vendor@^2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.7.tgz#4e6d53d953c187981576d6a542acc9fb57174bda"
integrity sha512-VS9Rjt79+p7M0WkPqcAza4Yq1ZHrsHrwf7hPL/bjQB+c1lwmAI+1FXxYTYt818D/50fFVflw0XKleiBN5RITkg==
css-vendor@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d"
integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==
dependencies:
"@babel/runtime" "^7.6.2"
"@babel/runtime" "^7.8.3"
is-in-browser "^1.0.2"
css-what@2.1:
@@ -4686,9 +4613,9 @@ cssstyle@^1.0.0, cssstyle@^1.1.1:
cssom "0.3.x"
csstype@^2.2.0, csstype@^2.5.2, csstype@^2.6.5, csstype@^2.6.7:
version "2.6.9"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098"
integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==
version "2.6.11"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.11.tgz#452f4d024149ecf260a852b025e36562a253ffc5"
integrity sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw==
csv-parse@^4.4.6:
version "4.8.8"
@@ -4826,11 +4753,6 @@ deep-is@^0.1.3, deep-is@~0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
deepmerge@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
default-gateway@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
@@ -5041,11 +4963,11 @@ dom-converter@^0.2:
utila "~0.4"
dom-helpers@^5.0.1:
version "5.1.3"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.1.3.tgz#7233248eb3a2d1f74aafca31e52c5299cc8ce821"
integrity sha512-nZD1OtwfWGRBWlpANxacBEZrEuLa16o1nh7YopFWeoF68Zt8GGEmzHu6Xv4F3XaFIC+YXtTLrzgqKxFgLEe4jw==
version "5.1.4"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.1.4.tgz#4609680ab5c79a45f2531441f1949b79d6587f4b"
integrity sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==
dependencies:
"@babel/runtime" "^7.6.3"
"@babel/runtime" "^7.8.7"
csstype "^2.6.7"
dom-serializer@0, dom-serializer@^0.2.1:
@@ -5105,6 +5027,11 @@ domhandler@^3.0.0:
dependencies:
domelementtype "^2.0.1"
dompurify@^2.0.10:
version "2.0.12"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.12.tgz#284a2b041e1c60b8e72d7b4d2fadad36141254ae"
integrity sha512-Fl8KseK1imyhErHypFPA8qpq9gPzlsJ/EukA6yk9o0gX23p1TzC+rh9LqNg1qvErRTc0UNMYlKxEGSfSh43NDg==
dompurify@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.8.tgz#6ef89d2d227d041af139c7b01d9f67ed59c2eb3c"
@@ -6172,11 +6099,6 @@ flatten@^1.0.2:
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b"
integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==
flow-parser@0.*:
version "0.121.0"
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.121.0.tgz#9f9898eaec91a9f7c323e9e992d81ab5c58e618f"
integrity sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg==
flush-write-stream@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
@@ -6257,30 +6179,6 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"
formik-material-ui-pickers@^0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/formik-material-ui-pickers/-/formik-material-ui-pickers-0.0.8.tgz#203e602b71eff4a1f28ef40c4c7989a63fc5ff07"
integrity sha512-4/5Fcxe+Bi/6g0nA+ZE1U/D+W8s8yEiictA5w/vLPDab9P9uoktXFjEy2TfKQhfeUP4krYIt6U2tNNZuhRwoIg==
formik-material-ui@^2.0.0-beta.1:
version "2.0.0-beta.1"
resolved "https://registry.yarnpkg.com/formik-material-ui/-/formik-material-ui-2.0.0-beta.1.tgz#adf6321c97f8617aff00ed717daba8b66d436fd7"
integrity sha512-Zt2pHQzaU2f9reXLS0E85ddeU8aFFtVJV42IPfVdC3lLY+kf+PUdzSiyCHFbRFVniG7SGisEoOwOZFMpkA85Qw==
formik@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.4.tgz#8deef07ec845ea98f75e03da4aad7aab4ac46570"
integrity sha512-oKz8S+yQBzuQVSEoxkqqJrKQS5XJASWGVn6mrs+oTWrBoHgByVwwI1qHiVc9GKDpZBU9vAxXYAKz2BvujlwunA==
dependencies:
deepmerge "^2.1.1"
hoist-non-react-statics "^3.3.0"
lodash "^4.17.14"
lodash-es "^4.17.14"
react-fast-compare "^2.0.1"
scheduler "^0.18.0"
tiny-warning "^1.0.2"
tslib "^1.10.0"
forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
@@ -7049,7 +6947,7 @@ hoist-non-react-statics@^2.1.0:
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -7269,9 +7167,9 @@ husky@^3.0.5:
slash "^3.0.0"
hyphenate-style-name@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz#097bb7fa0b8f1a9cf0bd5c734cf95899981a9b48"
integrity sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==
version "1.0.4"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.24"
@@ -8420,45 +8318,6 @@ jsbn@~0.1.0:
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jscodeshift-add-imports@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/jscodeshift-add-imports/-/jscodeshift-add-imports-1.0.3.tgz#1e27ee28e284b3be3db22853738b5bcb04a6bf79"
integrity sha512-h7zZ6HS+k2hlXYtx3sFoMAOZq0yGnDfCAHudZqw0KnF1qV30wcXwN9bO5v8zRLUhoUibli8xx3wbT2QDGc+ung==
dependencies:
"@babel/traverse" "^7.4.5"
jscodeshift-find-imports "^1.0.2"
jscodeshift-find-imports@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/jscodeshift-find-imports/-/jscodeshift-find-imports-1.1.1.tgz#2d4c0a96f1068dded688a8f59fa9470795fd8944"
integrity sha512-vjhUZbVRajqE5F1lonyZ0vy5ux/P+eHWTgdhAawDtsSvxPfwQAsygdBjvhEZZao0zF0gBJ3MPOZlXYEmT9UypQ==
dependencies:
jscodeshift "^0.6.4"
jscodeshift@^0.6.4:
version "0.6.4"
resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.6.4.tgz#e19ab86214edac86a75c4557fc88b3937d558a8e"
integrity sha512-+NF/tlNbc2WEhXUuc4WEJLsJumF84tnaMUZW2hyJw3jThKKRvsPX4sPJVgO1lPE28z0gNL+gwniLG9d8mYvQCQ==
dependencies:
"@babel/core" "^7.1.6"
"@babel/parser" "^7.1.6"
"@babel/plugin-proposal-class-properties" "^7.1.0"
"@babel/plugin-proposal-object-rest-spread" "^7.0.0"
"@babel/preset-env" "^7.1.6"
"@babel/preset-flow" "^7.0.0"
"@babel/preset-typescript" "^7.1.0"
"@babel/register" "^7.0.0"
babel-core "^7.0.0-bridge.0"
colors "^1.1.2"
flow-parser "0.*"
graceful-fs "^4.1.11"
micromatch "^3.1.10"
neo-async "^2.5.0"
node-dir "^0.1.17"
recast "^0.16.1"
temp "^0.8.1"
write-file-atomic "^2.3.0"
jsdom@^11.5.1:
version "11.12.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8"
@@ -8668,68 +8527,69 @@ jsprim@^1.2.2:
verror "1.10.0"
jss-plugin-camel-case@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.1.1.tgz#8e73ecc4f1d0f8dfe4dd31f6f9f2782588970e78"
integrity sha512-MDIaw8FeD5uFz1seQBKz4pnvDLnj5vIKV5hXSVdMaAVq13xR6SVTVWkIV/keyTs5txxTvzGJ9hXoxgd1WTUlBw==
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.3.0.tgz#ae4da53b39a6e3ea94b70a20fc41c11f0b87386a"
integrity sha512-tadWRi/SLWqLK3EUZEdDNJL71F3ST93Zrl9JYMjV0QDqKPAl0Liue81q7m/nFUpnSTXczbKDy4wq8rI8o7WFqA==
dependencies:
"@babel/runtime" "^7.3.1"
hyphenate-style-name "^1.0.3"
jss "10.1.1"
jss "^10.3.0"
jss-plugin-default-unit@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.1.1.tgz#2df86016dfe73085eead843f5794e3890e9c5c47"
integrity sha512-UkeVCA/b3QEA4k0nIKS4uWXDCNmV73WLHdh2oDGZZc3GsQtlOCuiH3EkB/qI60v2MiCq356/SYWsDXt21yjwdg==
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.3.0.tgz#cd74cf5088542620a82591f76c62c6b43a7e50a6"
integrity sha512-tT5KkIXAsZOSS9WDSe8m8lEHIjoEOj4Pr0WrG0WZZsMXZ1mVLFCSsD2jdWarQWDaRNyMj/I4d7czRRObhOxSuw==
dependencies:
"@babel/runtime" "^7.3.1"
jss "10.1.1"
jss "^10.3.0"
jss-plugin-global@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.1.1.tgz#36b0d6d9facb74dfd99590643708a89260747d14"
integrity sha512-VBG3wRyi3Z8S4kMhm8rZV6caYBegsk+QnQZSVmrWw6GVOT/Z4FA7eyMu5SdkorDlG/HVpHh91oFN56O4R9m2VA==
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.3.0.tgz#6b883e74900bb71f65ac2b19bea78f7d1e85af3f"
integrity sha512-etYTG/y3qIR/vxZnKY+J3wXwObyBDNhBiB3l/EW9/pE3WHE//BZdK8LFvQcrCO48sZW1Z6paHo6klxUPP7WbzA==
dependencies:
"@babel/runtime" "^7.3.1"
jss "10.1.1"
jss "^10.3.0"
jss-plugin-nested@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.1.1.tgz#5c3de2b8bda344de1ebcef3a4fd30870a29a8a8c"
integrity sha512-ozEu7ZBSVrMYxSDplPX3H82XHNQk2DQEJ9TEyo7OVTPJ1hEieqjDFiOQOxXEj9z3PMqkylnUbvWIZRDKCFYw5Q==
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.3.0.tgz#ae8aceac95e09c3d40c991ea32403fb647d9e0a8"
integrity sha512-qWiEkoXNEkkZ+FZrWmUGpf+zBsnEOmKXhkjNX85/ZfWhH9dfGxUCKuJFuOWFM+rjQfxV4csfesq4hY0jk8Qt0w==
dependencies:
"@babel/runtime" "^7.3.1"
jss "10.1.1"
jss "^10.3.0"
tiny-warning "^1.0.2"
jss-plugin-props-sort@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.1.1.tgz#34bddcbfaf9430ec8ccdf92729f03bb10caf1785"
integrity sha512-g/joK3eTDZB4pkqpZB38257yD4LXB0X15jxtZAGbUzcKAVUHPl9Jb47Y7lYmiGsShiV4YmQRqG1p2DHMYoK91g==
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.3.0.tgz#5b0625f87b6431a7969c56b0d8c696525969bfe4"
integrity sha512-boetORqL/lfd7BWeFD3K+IyPqyIC+l3CRrdZr+NPq7Noqp+xyg/0MR7QisgzpxCEulk+j2CRcEUoZsvgPC4nTg==
dependencies:
"@babel/runtime" "^7.3.1"
jss "10.1.1"
jss "^10.3.0"
jss-plugin-rule-value-function@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.1.1.tgz#be00dac6fc394aaddbcef5860b9eca6224d96382"
integrity sha512-ClV1lvJ3laU9la1CUzaDugEcwnpjPTuJ0yGy2YtcU+gG/w9HMInD5vEv7xKAz53Bk4WiJm5uLOElSEshHyhKNw==
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.3.0.tgz#498b0e2bae16cb316a6bdb73fd783cf9604ba747"
integrity sha512-7WiMrKIHH3rwxTuJki9+7nY11r1UXqaUZRhHvqTD4/ZE+SVhvtD5Tx21ivNxotwUSleucA/8boX+NF21oXzr5Q==
dependencies:
"@babel/runtime" "^7.3.1"
jss "10.1.1"
jss "^10.3.0"
tiny-warning "^1.0.2"
jss-plugin-vendor-prefixer@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.1.1.tgz#8348b20749f790beebab3b6a8f7075b07c2cfcfd"
integrity sha512-09MZpQ6onQrhaVSF6GHC4iYifQ7+4YC/tAP6D4ZWeZotvCMq1mHLqNKRIaqQ2lkgANjlEot2JnVi1ktu4+L4pw==
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.3.0.tgz#b09c13a4d05a055429d8a24e19cc01ce049f0ed4"
integrity sha512-sZQbrcZyP5V0ADjCLwUA1spVWoaZvM7XZ+2fSeieZFBj31cRsnV7X70FFDerMHeiHAXKWzYek+67nMDjhrZAVQ==
dependencies:
"@babel/runtime" "^7.3.1"
css-vendor "^2.0.7"
jss "10.1.1"
css-vendor "^2.0.8"
jss "^10.3.0"
jss@10.1.1, jss@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/jss/-/jss-10.1.1.tgz#450b27d53761af3e500b43130a54cdbe157ea332"
integrity sha512-Xz3qgRUFlxbWk1czCZibUJqhVPObrZHxY3FPsjCXhDld4NOj1BgM14Ir5hVm+Qr6OLqVljjGvoMcCdXNOAbdkQ==
jss@^10.0.3, jss@^10.3.0:
version "10.3.0"
resolved "https://registry.yarnpkg.com/jss/-/jss-10.3.0.tgz#2cf7be265f72b59c1764d816fdabff1c5dd18326"
integrity sha512-B5sTRW9B6uHaUVzSo9YiMEOEp3UX8lWevU0Fsv+xtRnsShmgCfIYX44bTH8bPJe6LQKqEXku3ulKuHLbxBS97Q==
dependencies:
"@babel/runtime" "^7.3.1"
csstype "^2.6.5"
@@ -9016,7 +8876,7 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash-es@^4.17.14, lodash-es@^4.2.1:
lodash-es@^4.17.15, lodash-es@^4.2.1:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
@@ -9604,7 +9464,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4:
minimatch@3.0.4, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -9873,13 +9733,6 @@ no-case@^3.0.3:
lower-case "^2.0.1"
tslib "^1.10.0"
node-dir@^0.1.17:
version "0.1.17"
resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=
dependencies:
minimatch "^3.0.2"
node-emoji@^1.4.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da"
@@ -10695,7 +10548,7 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
pirates@^4.0.0, pirates@^4.0.1:
pirates@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==
@@ -10770,7 +10623,12 @@ pnp-webpack-plugin@1.6.0:
dependencies:
ts-pnp "^1.1.2"
popper.js@^1.14.1, popper.js@^1.16.1-lts:
popper.js@1.16.1-lts:
version "1.16.1-lts"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05"
integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==
popper.js@^1.14.1:
version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
@@ -11500,7 +11358,7 @@ pretty-quick@^2.0.1:
mri "^1.1.4"
multimatch "^4.0.0"
private@^0.1.8, private@~0.1.5:
private@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
@@ -11941,10 +11799,10 @@ react-error-overlay@^6.0.6:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.6.tgz#ac4d9dc4c1b5c536c2c312bf66aa2b09bfa384e2"
integrity sha512-Yzpno3enVzSrSCnnljmr4b/2KUQSMZaPuqmS26t9k4nW7uwJk6STWmH9heNjPuvqUTO3jOSPkHoKgO4+Dw7uIw==
react-fast-compare@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-hook-form@^6.5.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-6.5.0.tgz#9442797f9f05644829125772b2656d3da19f732e"
integrity sha512-DRziWoDvmwNIwBk6tkBN/fPeCgbtYHr1tIlVVd0ihmQg9Fv+gjOs0BU0D3o7HrKDeKwDA8pnp4tuEwxe8qg9TA==
react-image@^4.0.3:
version "4.0.3"
@@ -11958,11 +11816,16 @@ react-input-autosize@^2.1.2:
dependencies:
prop-types "^15.5.8"
react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4:
react-is@^16.12.0, react-is@^16.6.0, react-is@^16.8.4:
version "16.13.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527"
integrity sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==
react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-json-view@^1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.19.1.tgz#95d8e59e024f08a25e5dc8f076ae304eed97cf5c"
@@ -12083,10 +11946,10 @@ react-textarea-autosize@^6.1.0:
dependencies:
prop-types "^15.6.0"
react-transition-group@^4.0.0, react-transition-group@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.3.0.tgz#fea832e386cf8796c58b61874a3319704f5ce683"
integrity sha512-1qRV1ZuVSdxPlPf4O8t7inxUGpdyO5zG9IoNfJxSO0ImU2A1YWkEQvFPuIPZmMLkg5hYs7vv5mMOyfgSkvAwvw==
react-transition-group@^4.0.0, react-transition-group@^4.3.0, react-transition-group@^4.4.0:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
@@ -12210,16 +12073,6 @@ realpath-native@^1.1.0:
dependencies:
util.promisify "^1.0.0"
recast@^0.16.1:
version "0.16.2"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.16.2.tgz#3796ebad5fe49ed85473b479cd6df554ad725dc2"
integrity sha512-O/7qXi51DPjRVdbrpNzoBQH5dnAPQNbfoOFyRiUwreTMJfIHYOEBzwuH+c0+/BTSJ3CQyKs6ILSWXhESH6Op3A==
dependencies:
ast-types "0.11.7"
esprima "~4.0.0"
private "~0.1.5"
source-map "~0.6.1"
recursive-readdir@2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f"
@@ -12580,7 +12433,7 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.
dependencies:
glob "^7.1.3"
rimraf@2.6.3, rimraf@~2.6.2:
rimraf@2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
@@ -12716,14 +12569,6 @@ saxes@^3.1.9:
dependencies:
xmlchars "^2.1.1"
scheduler@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4"
integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler@^0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.0.tgz#a715d56302de403df742f4a9be11975b32f5698d"
@@ -13053,7 +12898,7 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12:
source-map-support@^0.5.6, source-map-support@~0.5.12:
version "0.5.16"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
@@ -13588,13 +13433,6 @@ tcp-port-used@^1.0.1:
debug "4.1.0"
is2 "2.0.1"
temp@^0.8.1:
version "0.8.4"
resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==
dependencies:
rimraf "~2.6.2"
term-size@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
@@ -14742,7 +14580,7 @@ write-file-atomic@2.4.1:
imurmurhash "^0.1.4"
signal-exit "^3.0.2"
write-file-atomic@^2.0.0, write-file-atomic@^2.3.0:
write-file-atomic@^2.0.0:
version "2.4.3"
resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==