mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
Merge branch 'rc' of https://github.com/rowyio/rowy into rc
This commit is contained in:
11
package.json
11
package.json
@@ -13,12 +13,12 @@
|
||||
"@emotion/react": "^11.4.0",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@hookform/resolvers": "^2.8.1",
|
||||
"@mdi/js": "^6.2.95",
|
||||
"@mdi/js": "^6.5.95",
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@mui/icons-material": "^5.0.0",
|
||||
"@mui/lab": "^5.0.0-alpha.50",
|
||||
"@mui/material": "^5.0.0",
|
||||
"@mui/styles": "^5.0.0",
|
||||
"@mui/icons-material": "^5.2.0",
|
||||
"@mui/lab": "^5.0.0-alpha.58",
|
||||
"@mui/material": "^5.2.2",
|
||||
"@mui/styles": "^5.2.2",
|
||||
"@rowy/form-builder": "^0.4.2",
|
||||
"@rowy/multiselect": "^0.2.3",
|
||||
"@tinymce/tinymce-react": "^3.12.6",
|
||||
@@ -62,7 +62,6 @@
|
||||
"react-router-hash-link": "^2.4.3",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-usestateref": "^1.0.5",
|
||||
"semver": "^7.3.5",
|
||||
"serve": "^11.3.2",
|
||||
"swr": "^1.0.1",
|
||||
"tinymce": "^5.9.2",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon";
|
||||
import { mdiClockEditOutline } from "@mdi/js";
|
||||
|
||||
export default function UpdatedAt(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d="m19.06 14.88 2.05 2-6 6.07H13v-2.01l6.06-6.06ZM12 2a10 10 0 0 1 9.98 9.373 2.561 2.561 0 0 0-2.001.047A8 8 0 0 0 4 12a8.001 8.001 0 0 0 7 7.938v2.013C5.941 21.447 2 17.164 2 12 2 6.477 6.477 2 12 2Zm9.42 11.35 1.28 1.28c.21.21.21.56 0 .77l-1 .95-2.05-2 1-1a.55.55 0 0 1 .77 0ZM12.5 7v5.25l4.018 2.384-1.051 1.045L11 13V7h1.5Z" />
|
||||
<path d={mdiClockEditOutline} />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,14 @@ export default function DiffEditor({
|
||||
return (
|
||||
<TrapFocus open={fullScreen}>
|
||||
<Box
|
||||
sx={{ ...boxSx, ...containerProps?.sx }}
|
||||
sx={[
|
||||
boxSx,
|
||||
...(Array.isArray(containerProps?.sx)
|
||||
? containerProps!.sx
|
||||
: containerProps?.sx
|
||||
? [containerProps.sx]
|
||||
: []),
|
||||
]}
|
||||
style={fullScreen ? { height: "100%" } : {}}
|
||||
>
|
||||
<MonacoDiffEditor
|
||||
|
||||
@@ -66,7 +66,14 @@ export default function CodeEditor({
|
||||
return (
|
||||
<TrapFocus open={fullScreen}>
|
||||
<Box
|
||||
sx={{ ...boxSx, ...containerProps?.sx }}
|
||||
sx={[
|
||||
boxSx,
|
||||
...(Array.isArray(containerProps?.sx)
|
||||
? containerProps!.sx
|
||||
: containerProps?.sx
|
||||
? [containerProps.sx]
|
||||
: []),
|
||||
]}
|
||||
style={fullScreen ? { height: "100%" } : {}}
|
||||
>
|
||||
<Editor
|
||||
|
||||
@@ -6,7 +6,7 @@ import githubLightTheme from "./github-light-default.json";
|
||||
import githubDarkTheme from "./github-dark-default.json";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import type { SxProps, Theme } from "@mui/system";
|
||||
import type { SystemStyleObject, Theme } from "@mui/system";
|
||||
|
||||
import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { getFieldProp } from "@src/components/fields";
|
||||
@@ -189,7 +189,7 @@ export default function useMonacoCustomizations({
|
||||
}
|
||||
}, [monaco, tableState?.columns]);
|
||||
|
||||
let boxSx: SxProps<Theme> = {
|
||||
let boxSx: SystemStyleObject<Theme> = {
|
||||
minWidth: 400,
|
||||
minHeight,
|
||||
height: minHeight,
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function HelperText(props: IHelperTextProps) {
|
||||
style={{
|
||||
marginTop: theme.spacing(-3),
|
||||
padding: theme.spacing(0, 1.5),
|
||||
...theme.typography.body2,
|
||||
...(theme.typography.body2 as any),
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -26,9 +26,9 @@ export interface IScrollableDialogContentProps extends DialogContentProps {
|
||||
export default function ScrollableDialogContent({
|
||||
disableTopDivider = false,
|
||||
disableBottomDivider = false,
|
||||
dividerSx,
|
||||
topDividerSx,
|
||||
bottomDividerSx,
|
||||
dividerSx = [],
|
||||
topDividerSx = [],
|
||||
bottomDividerSx = [],
|
||||
...props
|
||||
}: IScrollableDialogContentProps) {
|
||||
const [scrollInfo, setRef] = useScrollInfo();
|
||||
@@ -40,7 +40,10 @@ export default function ScrollableDialogContent({
|
||||
style={{
|
||||
visibility: scrollInfo.y.percentage > 0 ? "visible" : "hidden",
|
||||
}}
|
||||
sx={{ ...dividerSx, ...topDividerSx }}
|
||||
sx={[
|
||||
...(Array.isArray(dividerSx) ? dividerSx : [dividerSx]),
|
||||
...(Array.isArray(topDividerSx) ? topDividerSx : [topDividerSx]),
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -51,7 +54,12 @@ export default function ScrollableDialogContent({
|
||||
style={{
|
||||
visibility: scrollInfo.y.percentage < 1 ? "visible" : "hidden",
|
||||
}}
|
||||
sx={{ ...dividerSx, ...bottomDividerSx }}
|
||||
sx={[
|
||||
...(Array.isArray(dividerSx) ? dividerSx : [dividerSx]),
|
||||
...(Array.isArray(bottomDividerSx)
|
||||
? bottomDividerSx
|
||||
: [bottomDividerSx]),
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -22,7 +22,7 @@ import ScrollableDialogContent, {
|
||||
} from "./ScrollableDialogContent";
|
||||
|
||||
export interface IModalProps extends Partial<Omit<DialogProps, "title">> {
|
||||
onClose: () => void;
|
||||
onClose: (setOpen: React.Dispatch<React.SetStateAction<boolean>>) => void;
|
||||
disableBackdropClick?: boolean;
|
||||
disableEscapeKeyDown?: boolean;
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function Modal({
|
||||
|
||||
setOpen(false);
|
||||
setEmphasizeCloseButton(false);
|
||||
setTimeout(() => onClose(), 300);
|
||||
setTimeout(() => onClose(setOpen), 300);
|
||||
};
|
||||
|
||||
const [emphasizeCloseButton, setEmphasizeCloseButton] = useState(false);
|
||||
|
||||
@@ -25,9 +25,9 @@ import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp";
|
||||
import { useConfirmation } from "@src/components/ConfirmationDialog/Context";
|
||||
import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { formatPath, asyncForEach } from "@src/utils/fns";
|
||||
import routes from "@src/constants/routes";
|
||||
// import routes from "@src/constants/routes";
|
||||
import { runRoutes } from "@src/constants/runRoutes";
|
||||
import { config } from "process";
|
||||
// import { config } from "process";
|
||||
import { WIKI_LINKS } from "@src/constants/externalLinks";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
@@ -266,7 +266,7 @@ export default function BulkActions({ selectedRows, columns, clearSelection }) {
|
||||
},
|
||||
}}
|
||||
SelectProps={{
|
||||
classes: { root: classes.select },
|
||||
classes: { select: classes.select },
|
||||
displayEmpty: true,
|
||||
MenuProps: {
|
||||
anchorOrigin: { vertical: "top", horizontal: "left" },
|
||||
|
||||
@@ -12,6 +12,7 @@ import Loading from "@src/components/Loading";
|
||||
|
||||
import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { useConfirmation } from "@src/components/ConfirmationDialog";
|
||||
import { useSnackLogContext } from "@src/contexts/SnackLogContext";
|
||||
import { FieldType } from "@src/constants/fields";
|
||||
import { runRoutes } from "@src/constants/runRoutes";
|
||||
|
||||
@@ -27,6 +28,7 @@ export default function FieldSettings(props: IMenuModalProps) {
|
||||
|
||||
const { requestConfirmation } = useConfirmation();
|
||||
const { tableState, rowyRun } = useProjectContext();
|
||||
const snackLogContext = useSnackLogContext();
|
||||
|
||||
const rendedFieldSettings = useMemo(
|
||||
() =>
|
||||
@@ -164,6 +166,7 @@ export default function FieldSettings(props: IMenuModalProps) {
|
||||
cancel: "Later",
|
||||
handleConfirm: async () => {
|
||||
if (!rowyRun) return;
|
||||
snackLogContext.requestSnackLog();
|
||||
rowyRun({
|
||||
route: runRoutes.buildFunction,
|
||||
body: {
|
||||
|
||||
@@ -58,7 +58,7 @@ export const TableContainer = styled("div", {
|
||||
border: "none",
|
||||
backgroundColor: "transparent",
|
||||
|
||||
...theme.typography.caption,
|
||||
...(theme.typography.caption as any),
|
||||
// fontSize: "0.8125rem",
|
||||
lineHeight: "inherit !important",
|
||||
|
||||
@@ -136,14 +136,13 @@ export const TableContainer = styled("div", {
|
||||
".row-hover-iconButton": {
|
||||
color: theme.palette.text.disabled,
|
||||
transitionDuration: "0s",
|
||||
|
||||
".rdg-row:hover &": {
|
||||
color: theme.palette.text.primary,
|
||||
backgroundColor: alpha(
|
||||
theme.palette.action.hover,
|
||||
theme.palette.action.hoverOpacity * 1.5
|
||||
),
|
||||
},
|
||||
},
|
||||
".rdg-row:hover .row-hover-iconButton": {
|
||||
color: theme.palette.text.primary,
|
||||
backgroundColor: alpha(
|
||||
theme.palette.action.hover,
|
||||
theme.palette.action.hoverOpacity * 1.5
|
||||
),
|
||||
},
|
||||
|
||||
".cell-collapse-padding": {
|
||||
|
||||
@@ -47,6 +47,8 @@ export default function AddRow() {
|
||||
ref={anchorEl}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={isCollectionGroup() || !addRow}
|
||||
onClick={handleClick}
|
||||
startIcon={<AddRowIcon />}
|
||||
@@ -55,6 +57,8 @@ export default function AddRow() {
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
aria-label="Select row add position"
|
||||
aria-haspopup="menu"
|
||||
style={{ padding: 0 }}
|
||||
|
||||
@@ -6,7 +6,7 @@ import Ansi from "ansi-to-react";
|
||||
import { TIME_FORMAT } from "constants/dates";
|
||||
|
||||
const Root = styled("div")(({ theme }) => ({
|
||||
...theme.typography.caption,
|
||||
...(theme.typography.caption as any),
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
// TODO:
|
||||
color: "#CCC",
|
||||
|
||||
@@ -118,6 +118,7 @@ export default function BuildLogsSnack({ onClose, onOpenPanel }) {
|
||||
aria-label="Expand"
|
||||
size="small"
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
style={{ color: "white" }}
|
||||
>
|
||||
{expanded ? <CollapseIcon /> : <ExpandIcon />}
|
||||
</IconButton>
|
||||
@@ -135,13 +136,19 @@ export default function BuildLogsSnack({ onClose, onOpenPanel }) {
|
||||
buildLogExpanded: 0,
|
||||
});
|
||||
}}
|
||||
style={{ color: "white" }}
|
||||
>
|
||||
<OpenIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Close">
|
||||
<IconButton aria-label="Close" size="small" onClick={onClose}>
|
||||
<IconButton
|
||||
aria-label="Close"
|
||||
size="small"
|
||||
onClick={onClose}
|
||||
style={{ color: "white" }}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
@@ -30,7 +30,7 @@ const Accordion = styled(MuiAccordion)(({ theme }) => ({
|
||||
marginTop: 0,
|
||||
"&::before": { display: "none" },
|
||||
|
||||
...theme.typography.caption,
|
||||
...(theme.typography.caption as any),
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
}));
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ const Accordion = styled(MuiAccordion)(({ theme }) => ({
|
||||
marginTop: 0,
|
||||
"&::before": { display: "none" },
|
||||
|
||||
...theme.typography.caption,
|
||||
...(theme.typography.caption as any),
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
}));
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ export const CloudLogSubheader = styled((props) => (
|
||||
zIndex: 2,
|
||||
|
||||
"&:not(:first-child)": { marginTop: theme.spacing(2) },
|
||||
...theme.typography.subtitle2,
|
||||
...(theme.typography.subtitle2 as any),
|
||||
padding: theme.spacing((32 - 20) / 2 / 8, 1.5),
|
||||
lineHeight: "20px",
|
||||
|
||||
|
||||
83
src/components/TableHeader/Extensions/AddExtensionButton.tsx
Normal file
83
src/components/TableHeader/Extensions/AddExtensionButton.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import {
|
||||
Button,
|
||||
ButtonProps,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
} from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import EmailIcon from "@mui/icons-material/EmailOutlined";
|
||||
|
||||
import { extensionTypes, extensionNames, ExtensionType } from "./utils";
|
||||
import { EMAIL_REQUEST } from "@src/constants/externalLinks";
|
||||
|
||||
export interface IAddExtensionButtonProps extends Partial<ButtonProps> {
|
||||
handleAddExtension: (type: ExtensionType) => void;
|
||||
}
|
||||
|
||||
export default function AddExtensionButton({
|
||||
handleAddExtension,
|
||||
...props
|
||||
}: IAddExtensionButtonProps) {
|
||||
const addButtonRef = useRef<HTMLButtonElement>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleChooseAddType = (type: ExtensionType) => {
|
||||
setOpen(false);
|
||||
handleAddExtension(type);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => setOpen(true)}
|
||||
ref={addButtonRef}
|
||||
sx={{
|
||||
alignSelf: { sm: "flex-end" },
|
||||
mt: {
|
||||
sm: `calc(var(--dialog-title-height) * -1 + (var(--dialog-title-height) - 32px) / 2)`,
|
||||
},
|
||||
mx: { xs: "var(--dialog-spacing)", sm: undefined },
|
||||
mr: { sm: 8 },
|
||||
mb: { xs: 1.5, sm: 2 },
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
Add Extension…
|
||||
</Button>
|
||||
|
||||
<Menu
|
||||
anchorEl={addButtonRef.current}
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
||||
transformOrigin={{ vertical: "top", horizontal: "right" }}
|
||||
>
|
||||
{extensionTypes.map((type) => (
|
||||
<MenuItem onClick={() => handleChooseAddType(type)}>
|
||||
{extensionNames[type]}
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
<Divider variant="middle" />
|
||||
|
||||
<MenuItem
|
||||
component="a"
|
||||
href={EMAIL_REQUEST}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<ListItemIcon>
|
||||
<EmailIcon aria-label="Send email" />
|
||||
</ListItemIcon>
|
||||
Request new Extension…
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,43 +1,27 @@
|
||||
import { useState, useRef } from "react";
|
||||
import { format, formatRelative } from "date-fns";
|
||||
|
||||
import {
|
||||
Stack,
|
||||
ButtonBase,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Avatar,
|
||||
Button,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
Switch,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import ExtensionIcon from "@src/assets/icons/Extension";
|
||||
import DuplicateIcon from "@src/assets/icons/Copy";
|
||||
import EditIcon from "@mui/icons-material/EditOutlined";
|
||||
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
|
||||
import EmailIcon from "@mui/icons-material/EmailOutlined";
|
||||
|
||||
import EmptyState from "@src/components/EmptyState";
|
||||
import {
|
||||
extensionTypes,
|
||||
extensionNames,
|
||||
IExtension,
|
||||
ExtensionType,
|
||||
} from "./utils";
|
||||
import { extensionNames, IExtension } from "./utils";
|
||||
import { DATE_TIME_FORMAT } from "@src/constants/dates";
|
||||
import { EMAIL_REQUEST } from "@src/constants/externalLinks";
|
||||
|
||||
export interface IExtensionListProps {
|
||||
extensions: IExtension[];
|
||||
handleAddExtension: (type: ExtensionType) => void;
|
||||
handleUpdateActive: (index: number, active: boolean) => void;
|
||||
handleDuplicate: (index: number) => void;
|
||||
handleEdit: (index: number) => void;
|
||||
@@ -46,204 +30,127 @@ export interface IExtensionListProps {
|
||||
|
||||
export default function ExtensionList({
|
||||
extensions,
|
||||
handleAddExtension,
|
||||
handleUpdateActive,
|
||||
handleDuplicate,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
}: IExtensionListProps) {
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const addButtonRef = useRef(null);
|
||||
|
||||
const activeExtensionCount = extensions.filter(
|
||||
(extension) => extension.active
|
||||
).length;
|
||||
|
||||
const handleAddButton = () => {
|
||||
setAnchorEl(addButtonRef.current);
|
||||
};
|
||||
|
||||
const handleChooseAddType = (type: ExtensionType) => {
|
||||
handleClose();
|
||||
handleAddExtension(type);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
if (extensions.length === 0)
|
||||
return (
|
||||
<EmptyState
|
||||
message="Add your first extension above"
|
||||
description="Your extensions will appear here"
|
||||
Icon={ExtensionIcon}
|
||||
style={{ height: 89 * 3 - 1 }}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={2}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
style={{ marginTop: 0 }}
|
||||
>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
component="h2"
|
||||
style={{ fontFeatureSettings: "'case', 'tnum'" }}
|
||||
>
|
||||
Extensions ({activeExtensionCount} / {extensions.length})
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={handleAddButton}
|
||||
ref={addButtonRef}
|
||||
>
|
||||
Add Extension…
|
||||
</Button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
||||
transformOrigin={{ vertical: "top", horizontal: "right" }}
|
||||
>
|
||||
{extensionTypes.map((type) => (
|
||||
<MenuItem onClick={() => handleChooseAddType(type)}>
|
||||
{extensionNames[type]}
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
<Divider variant="middle" />
|
||||
|
||||
<MenuItem
|
||||
component="a"
|
||||
href={EMAIL_REQUEST}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<ListItemIcon>
|
||||
<EmailIcon aria-label="Send email" />
|
||||
</ListItemIcon>
|
||||
Request new Extension…
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
|
||||
{extensions.length === 0 ? (
|
||||
<ButtonBase
|
||||
onClick={handleAddButton}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: 72 * 3,
|
||||
borderRadius: 1,
|
||||
"&:hover": { bgcolor: "action.hover" },
|
||||
}}
|
||||
>
|
||||
<EmptyState
|
||||
message="Add your first extension"
|
||||
description="Your extensions will appear here."
|
||||
Icon={ExtensionIcon}
|
||||
/>
|
||||
</ButtonBase>
|
||||
) : (
|
||||
<List style={{ paddingTop: 0, minHeight: 72 * 3 }}>
|
||||
{extensions.map((extensionObject, index) => (
|
||||
<ListItem
|
||||
disableGutters
|
||||
dense={false}
|
||||
divider={index !== extensions.length - 1}
|
||||
children={
|
||||
<ListItemText
|
||||
primary={extensionObject.name}
|
||||
secondary={extensionNames[extensionObject.type]}
|
||||
primaryTypographyProps={{
|
||||
style: {
|
||||
minHeight: 40,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
}
|
||||
secondaryAction={
|
||||
<Stack alignItems="flex-end">
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Tooltip
|
||||
title={extensionObject.active ? "Deactivate" : "Activate"}
|
||||
>
|
||||
<Switch
|
||||
checked={extensionObject.active}
|
||||
onClick={() =>
|
||||
handleUpdateActive(index, !extensionObject.active)
|
||||
}
|
||||
inputProps={{ "aria-label": "Activate" }}
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Duplicate">
|
||||
<IconButton
|
||||
aria-label="Duplicate"
|
||||
onClick={() => handleDuplicate(index)}
|
||||
>
|
||||
<DuplicateIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Edit">
|
||||
<IconButton
|
||||
aria-label="Edit"
|
||||
onClick={() => handleEdit(index)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete">
|
||||
<IconButton
|
||||
aria-label="Delete"
|
||||
color="error"
|
||||
onClick={() => handleDelete(index)}
|
||||
sx={{ "&&": { mr: -1.5 } }}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
Last updated
|
||||
<br />
|
||||
by {extensionObject.lastEditor.displayName}
|
||||
<br />
|
||||
at{" "}
|
||||
{format(
|
||||
extensionObject.lastEditor.lastUpdate,
|
||||
DATE_TIME_FORMAT
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ color: "text.disabled" }}
|
||||
>
|
||||
{formatRelative(
|
||||
extensionObject.lastEditor.lastUpdate,
|
||||
new Date()
|
||||
)}
|
||||
</Typography>
|
||||
<Avatar
|
||||
alt={`${extensionObject.lastEditor.displayName}’s profile photo`}
|
||||
src={extensionObject.lastEditor.photoURL}
|
||||
sx={{ width: 24, height: 24, "&&": { mr: -0.5 } }}
|
||||
/>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
}
|
||||
<List style={{ minHeight: 89 * 3 - 1 }} disablePadding>
|
||||
{extensions.map((extensionObject, index) => (
|
||||
<ListItem
|
||||
disableGutters
|
||||
dense={false}
|
||||
divider={index !== extensions.length - 1}
|
||||
children={
|
||||
<ListItemText
|
||||
primary={extensionObject.name}
|
||||
secondary={extensionNames[extensionObject.type]}
|
||||
primaryTypographyProps={{
|
||||
style: {
|
||||
minHeight: 40,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
secondaryAction={
|
||||
<Stack alignItems="flex-end">
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Tooltip
|
||||
title={extensionObject.active ? "Deactivate" : "Activate"}
|
||||
>
|
||||
<Switch
|
||||
checked={extensionObject.active}
|
||||
onClick={() =>
|
||||
handleUpdateActive(index, !extensionObject.active)
|
||||
}
|
||||
inputProps={{ "aria-label": "Activate" }}
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Duplicate">
|
||||
<IconButton
|
||||
aria-label="Duplicate"
|
||||
onClick={() => handleDuplicate(index)}
|
||||
>
|
||||
<DuplicateIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Edit">
|
||||
<IconButton
|
||||
aria-label="Edit"
|
||||
onClick={() => handleEdit(index)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete…">
|
||||
<IconButton
|
||||
aria-label="Delete…"
|
||||
color="error"
|
||||
onClick={() => handleDelete(index)}
|
||||
sx={{ "&&": { mr: -1.5 } }}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
Last updated
|
||||
<br />
|
||||
by {extensionObject.lastEditor.displayName}
|
||||
<br />
|
||||
at{" "}
|
||||
{format(
|
||||
extensionObject.lastEditor.lastUpdate,
|
||||
DATE_TIME_FORMAT
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
<Typography variant="body2" sx={{ color: "text.disabled" }}>
|
||||
{formatRelative(
|
||||
extensionObject.lastEditor.lastUpdate,
|
||||
new Date()
|
||||
)}
|
||||
</Typography>
|
||||
<Avatar
|
||||
alt={`${extensionObject.lastEditor.displayName}’s profile photo`}
|
||||
src={extensionObject.lastEditor.photoURL}
|
||||
sx={{ width: 24, height: 24, "&&": { mr: -0.5 } }}
|
||||
/>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
}
|
||||
sx={{
|
||||
flexWrap: { xs: "wrap", sm: "nowrap" },
|
||||
"& .MuiListItemSecondaryAction-root": {
|
||||
position: { xs: "static", sm: "absolute" },
|
||||
width: { xs: "100%", sm: "auto" },
|
||||
transform: { xs: "none", sm: "translateY(-50%)" },
|
||||
},
|
||||
pr: { xs: 0, sm: 216 / 8 },
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ export default function ExtensionModal({
|
||||
onClick: () => {
|
||||
let warningMessage;
|
||||
if (!validation.condition && !validation.extensionBody) {
|
||||
warningMessage = "Condition and extension body are not valid";
|
||||
warningMessage = "Condition and Extension body are not valid";
|
||||
} else if (!validation.condition) {
|
||||
warningMessage = "Condition is not valid";
|
||||
} else if (!validation.extensionBody) {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { useState } from "react";
|
||||
import _isEqual from "lodash/isEqual";
|
||||
|
||||
import { Breadcrumbs } from "@mui/material";
|
||||
|
||||
import TableHeaderButton from "../TableHeaderButton";
|
||||
import ExtensionIcon from "@src/assets/icons/Extension";
|
||||
import Modal from "@src/components/Modal";
|
||||
import AddExtensionButton from "./AddExtensionButton";
|
||||
import ExtensionList from "./ExtensionList";
|
||||
import ExtensionModal from "./ExtensionModal";
|
||||
import ExtensionMigration from "./ExtensionMigration";
|
||||
@@ -40,12 +39,6 @@ export default function Extensions() {
|
||||
const snackLogContext = useSnackLogContext();
|
||||
const edited = !_isEqual(currentExtensionObjects, localExtensionsObjects);
|
||||
|
||||
const tablePathTokens =
|
||||
tableState?.tablePath?.split("/").filter(function (_, i) {
|
||||
// replace IDs with dash that appears at even indexes
|
||||
return i % 2 === 0;
|
||||
}) ?? [];
|
||||
|
||||
const handleOpen = () => {
|
||||
if (tableState?.config.sparks) {
|
||||
// migration is required
|
||||
@@ -56,13 +49,16 @@ export default function Extensions() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
const handleClose = (
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>
|
||||
) => {
|
||||
if (edited) {
|
||||
setOpen(true);
|
||||
requestConfirmation({
|
||||
title: "Discard changes",
|
||||
body: "You will lose changes you have made to extensions",
|
||||
title: "Discard changes?",
|
||||
confirm: "Discard",
|
||||
handleConfirm: () => {
|
||||
setOpen(false);
|
||||
setLocalExtensionsObjects(currentExtensionObjects);
|
||||
setOpenExtensionList(false);
|
||||
},
|
||||
@@ -83,8 +79,8 @@ export default function Extensions() {
|
||||
const handleSaveDeploy = async () => {
|
||||
handleSaveExtensions();
|
||||
try {
|
||||
snackLogContext.requestSnackLog();
|
||||
if (rowyRun)
|
||||
if (rowyRun) {
|
||||
snackLogContext.requestSnackLog();
|
||||
rowyRun({
|
||||
route: runRoutes.buildFunction,
|
||||
body: {
|
||||
@@ -93,7 +89,8 @@ export default function Extensions() {
|
||||
tableConfigPath: tableState?.config.tableConfig.path,
|
||||
},
|
||||
});
|
||||
analytics.logEvent("deployed_extensions");
|
||||
analytics.logEvent("deployed_extensions");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -163,8 +160,8 @@ export default function Extensions() {
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
requestConfirmation({
|
||||
title: `Delete ${localExtensionsObjects[index].name}?`,
|
||||
body: "This extension will be permanently deleted.",
|
||||
title: `Delete “${localExtensionsObjects[index].name}”?`,
|
||||
body: "This Extension will be permanently deleted when you save",
|
||||
confirm: "Confirm",
|
||||
handleConfirm: () => {
|
||||
setLocalExtensionsObjects(
|
||||
@@ -180,6 +177,10 @@ export default function Extensions() {
|
||||
lastUpdate: Date.now(),
|
||||
});
|
||||
|
||||
const activeExtensionCount = localExtensionsObjects.filter(
|
||||
(extension) => extension.active
|
||||
).length;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableHeaderButton
|
||||
@@ -191,33 +192,32 @@ export default function Extensions() {
|
||||
{openExtensionList && !!tableState && (
|
||||
<Modal
|
||||
onClose={handleClose}
|
||||
disableBackdropClick={edited}
|
||||
disableEscapeKeyDown={edited}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
title="Extensions"
|
||||
title={`Extensions (${activeExtensionCount}\u2009/\u2009${localExtensionsObjects.length})`}
|
||||
header={
|
||||
<AddExtensionButton
|
||||
handleAddExtension={(type: ExtensionType) => {
|
||||
setExtensionModal({
|
||||
mode: "add",
|
||||
extensionObject: emptyExtensionObject(type, currentEditor()),
|
||||
});
|
||||
}}
|
||||
variant={
|
||||
localExtensionsObjects.length === 0 ? "contained" : "outlined"
|
||||
}
|
||||
/>
|
||||
}
|
||||
children={
|
||||
<>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
{tablePathTokens.map((pathToken) => (
|
||||
<code>{pathToken}</code>
|
||||
))}
|
||||
</Breadcrumbs>
|
||||
<ExtensionList
|
||||
extensions={localExtensionsObjects}
|
||||
handleAddExtension={(type: ExtensionType) => {
|
||||
setExtensionModal({
|
||||
mode: "add",
|
||||
extensionObject: emptyExtensionObject(
|
||||
type,
|
||||
currentEditor()
|
||||
),
|
||||
});
|
||||
}}
|
||||
handleUpdateActive={handleUpdateActive}
|
||||
handleEdit={handleEdit}
|
||||
handleDuplicate={handleDuplicate}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
</>
|
||||
<ExtensionList
|
||||
extensions={localExtensionsObjects}
|
||||
handleUpdateActive={handleUpdateActive}
|
||||
handleEdit={handleEdit}
|
||||
handleDuplicate={handleDuplicate}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
}
|
||||
actions={{
|
||||
primary: {
|
||||
|
||||
83
src/components/TableHeader/Webhooks/AddWebhookButton.tsx
Normal file
83
src/components/TableHeader/Webhooks/AddWebhookButton.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import {
|
||||
Button,
|
||||
ButtonProps,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
} from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import EmailIcon from "@mui/icons-material/EmailOutlined";
|
||||
|
||||
import { webhookTypes, webhookNames, WebhookType } from "./utils";
|
||||
import { EMAIL_REQUEST } from "@src/constants/externalLinks";
|
||||
|
||||
export interface IAddWebhookButtonProps extends Partial<ButtonProps> {
|
||||
handleAddWebhook: (type: WebhookType) => void;
|
||||
}
|
||||
|
||||
export default function AddWebhookButton({
|
||||
handleAddWebhook,
|
||||
...props
|
||||
}: IAddWebhookButtonProps) {
|
||||
const addButtonRef = useRef<HTMLButtonElement>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleChooseAddType = (type: WebhookType) => {
|
||||
setOpen(false);
|
||||
handleAddWebhook(type);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => setOpen(true)}
|
||||
ref={addButtonRef}
|
||||
sx={{
|
||||
alignSelf: { sm: "flex-end" },
|
||||
mt: {
|
||||
sm: `calc(var(--dialog-title-height) * -1 + (var(--dialog-title-height) - 32px) / 2)`,
|
||||
},
|
||||
mx: { xs: "var(--dialog-spacing)", sm: undefined },
|
||||
mr: { sm: 8 },
|
||||
mb: { xs: 1.5, sm: 2 },
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
Add webhook…
|
||||
</Button>
|
||||
|
||||
<Menu
|
||||
anchorEl={addButtonRef.current}
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
||||
transformOrigin={{ vertical: "top", horizontal: "right" }}
|
||||
>
|
||||
{webhookTypes.map((type) => (
|
||||
<MenuItem onClick={() => handleChooseAddType(type)}>
|
||||
{webhookNames[type]}
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
<Divider variant="middle" />
|
||||
|
||||
<MenuItem
|
||||
component="a"
|
||||
href={EMAIL_REQUEST}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<ListItemIcon>
|
||||
<EmailIcon aria-label="Send email" />
|
||||
</ListItemIcon>
|
||||
Request new webhook…
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import WarningIcon from "@mui/icons-material/WarningAmber";
|
||||
|
||||
export const webhookTypes = [
|
||||
"basic",
|
||||
"typeform",
|
||||
@@ -36,7 +39,7 @@ const additionalVariables = [
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
export const webhookBasic = {
|
||||
name: "Basic",
|
||||
parser: {
|
||||
additionalVariables,
|
||||
@@ -60,6 +63,13 @@ export default {
|
||||
}`,
|
||||
},
|
||||
auth: (webhookObject, setWebhookObject) => {
|
||||
return <>no auth option for basic atm</>;
|
||||
return (
|
||||
<Typography color="text.disabled">
|
||||
<WarningIcon aria-label="Warning" style={{ verticalAlign: "bottom" }} />
|
||||
Verification is not currently available for basic webhooks
|
||||
</Typography>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default webhookBasic;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Typography, Link, TextField } from "@mui/material";
|
||||
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
|
||||
|
||||
export default {
|
||||
name: "Sendgrid",
|
||||
export const webhookSendgrid = {
|
||||
name: "SendGrid",
|
||||
parser: {
|
||||
additionalVariables: null,
|
||||
extraLibs: null,
|
||||
@@ -32,24 +33,25 @@ export default {
|
||||
return (
|
||||
<>
|
||||
<Typography gutterBottom>
|
||||
To verify the webhook call is sent from Sendgrid, You can enable
|
||||
signed event webhooks
|
||||
Enable Signed Event Webhooks on SendGrid by following{" "}
|
||||
<Link
|
||||
href={
|
||||
"https://docs.sendgrid.com/for-developers/tracking-events/getting-started-event-webhook-security-features#the-signed-event-webhook"
|
||||
}
|
||||
href="https://docs.sendgrid.com/for-developers/tracking-events/getting-started-event-webhook-security-features#the-signed-event-webhook"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
variant="body2"
|
||||
underline="always"
|
||||
variant="inherit"
|
||||
>
|
||||
here
|
||||
</Link>{" "}
|
||||
to set the secret, then add it below
|
||||
these instructions
|
||||
<InlineOpenInNewIcon />
|
||||
</Link>
|
||||
<br />
|
||||
Then add the secret below.
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
label={"Verification Key"}
|
||||
id="sendgrid-verification-key"
|
||||
label="Verification key"
|
||||
value={webhookObject.auth.secret}
|
||||
fullWidth
|
||||
multiline
|
||||
onChange={(e) => {
|
||||
setWebhookObject({
|
||||
@@ -62,3 +64,5 @@ export default {
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default webhookSendgrid;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Typography, Link, TextField } from "@mui/material";
|
||||
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
|
||||
|
||||
export default {
|
||||
export const webhookTypeform = {
|
||||
name: "Typeform",
|
||||
parser: {
|
||||
additionalVariables: null,
|
||||
@@ -55,23 +56,24 @@ export default {
|
||||
return (
|
||||
<>
|
||||
<Typography gutterBottom>
|
||||
To verify the webhook call is sent from typeform, you need to add
|
||||
secret on your webhook config on be follow the instructions{" "}
|
||||
Add a secret to your Typeform webhook config by following{" "}
|
||||
<Link
|
||||
href={
|
||||
"https://developers.typeform.com/webhooks/secure-your-webhooks/"
|
||||
}
|
||||
href="https://developers.typeform.com/webhooks/secure-your-webhooks/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
variant="body2"
|
||||
underline="always"
|
||||
variant="inherit"
|
||||
>
|
||||
here
|
||||
</Link>{" "}
|
||||
to set the secret, then add it below
|
||||
these instructions
|
||||
<InlineOpenInNewIcon />
|
||||
</Link>
|
||||
<br />
|
||||
Then add the secret below.
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
label={"Typeform Secret"}
|
||||
id="typeform-secret"
|
||||
label="Typeform secret"
|
||||
fullWidth
|
||||
value={webhookObject.auth.secret}
|
||||
onChange={(e) => {
|
||||
setWebhookObject({
|
||||
@@ -84,3 +86,5 @@ export default {
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default webhookTypeform;
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
import { IWebhookModalStepProps } from "./WebhookModal";
|
||||
import {
|
||||
FormControl,
|
||||
FormLabel,
|
||||
FormControlLabel,
|
||||
Switch,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
import { FormControlLabel, Checkbox, Typography } from "@mui/material";
|
||||
|
||||
import { webhookSchemas } from "./utils";
|
||||
|
||||
export default function Step1Endpoint({
|
||||
webhookObject,
|
||||
setWebhookObject,
|
||||
}: IWebhookModalStepProps) {
|
||||
return (
|
||||
<FormControl component="fieldset">
|
||||
<FormLabel component="legend" className="visually-hidden">
|
||||
Verification
|
||||
</FormLabel>
|
||||
<>
|
||||
<Typography variant="inherit" paragraph>
|
||||
Verification prevents malicious requests from being sent to this webhook
|
||||
endpoint
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
labelPlacement="start"
|
||||
control={
|
||||
<Switch
|
||||
<Checkbox
|
||||
checked={webhookObject.auth?.enabled}
|
||||
onClick={() =>
|
||||
setWebhookObject({
|
||||
@@ -32,17 +30,16 @@ export default function Step1Endpoint({
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="Enable Verification"
|
||||
label="Enable verification for this webhook"
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
{webhookObject.auth?.enabled ? (
|
||||
webhookSchemas[webhookObject.type].auth(webhookObject, setWebhookObject)
|
||||
) : (
|
||||
<Typography>
|
||||
Verification of webhooks is optional however it prevents malicious
|
||||
actors from spoofing the original sender
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{webhookObject.auth?.enabled &&
|
||||
webhookSchemas[webhookObject.type].auth(
|
||||
webhookObject,
|
||||
setWebhookObject
|
||||
)}
|
||||
{}
|
||||
</FormControl>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ export default function Step4Body({
|
||||
return (
|
||||
<>
|
||||
<Typography gutterBottom>
|
||||
Write the webhook parsed function. The returned object of the parser
|
||||
will be added as new row{" "}
|
||||
Write a function to parse webhook requests. Return an object, which will
|
||||
be added as a new row.{" "}
|
||||
<Link
|
||||
href={
|
||||
WIKI_LINKS[`webhooks${_upperFirst(webhookObject.type)}`] ||
|
||||
|
||||
@@ -1,37 +1,27 @@
|
||||
import { useState, useRef } from "react";
|
||||
import { useAtom } from "jotai";
|
||||
import { format, formatRelative } from "date-fns";
|
||||
|
||||
import {
|
||||
Stack,
|
||||
ButtonBase,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Avatar,
|
||||
Button,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
Switch,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import WebhookIcon from "@src/assets/icons/Webhook";
|
||||
import LogsIcon from "@src/assets/icons/CloudLogs";
|
||||
import EditIcon from "@mui/icons-material/EditOutlined";
|
||||
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
|
||||
import CopyIcon from "@src/assets/icons/Copy";
|
||||
import EmailIcon from "@mui/icons-material/EmailOutlined";
|
||||
import LinkIcon from "@mui/icons-material/Link";
|
||||
|
||||
import EmptyState from "@src/components/EmptyState";
|
||||
import { webhookTypes, webhookNames, IWebhook, WebhookType } from "./utils";
|
||||
import { webhookNames, IWebhook } from "./utils";
|
||||
import { DATE_TIME_FORMAT } from "@src/constants/dates";
|
||||
import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { EMAIL_REQUEST } from "@src/constants/externalLinks";
|
||||
import {
|
||||
modalAtom,
|
||||
cloudLogFiltersAtom,
|
||||
@@ -39,7 +29,6 @@ import {
|
||||
|
||||
export interface IWebhookListProps {
|
||||
webhooks: IWebhook[];
|
||||
handleAddWebhook: (type: WebhookType) => void;
|
||||
handleUpdateActive: (index: number, active: boolean) => void;
|
||||
handleEdit: (index: number) => void;
|
||||
handleDelete: (index: number) => void;
|
||||
@@ -47,243 +36,157 @@ export interface IWebhookListProps {
|
||||
|
||||
export default function WebhookList({
|
||||
webhooks,
|
||||
handleAddWebhook,
|
||||
handleUpdateActive,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
}: IWebhookListProps) {
|
||||
const { settings, tableState } = useProjectContext();
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const addButtonRef = useRef(null);
|
||||
|
||||
const [, setModal] = useAtom(modalAtom);
|
||||
const [, setCloudLogFilters] = useAtom(cloudLogFiltersAtom);
|
||||
const activeWebhookCount = webhooks.filter(
|
||||
(webhook) => webhook.active
|
||||
).length;
|
||||
|
||||
const handleAddButton = () => {
|
||||
setAnchorEl(addButtonRef.current);
|
||||
};
|
||||
|
||||
const handleChooseAddType = (type: WebhookType) => {
|
||||
handleClose();
|
||||
handleAddWebhook(type);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
const baseUrl = `${settings?.services?.hooks}/wh/${tableState?.tablePath}/`;
|
||||
|
||||
if (webhooks.length === 0)
|
||||
return (
|
||||
<EmptyState
|
||||
message="Add your first webhook above"
|
||||
description="Your webhooks will appear here"
|
||||
Icon={WebhookIcon}
|
||||
style={{ height: 89 * 3 - 1 }}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={2}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
style={{ marginTop: 0 }}
|
||||
>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
component="h2"
|
||||
style={{ fontFeatureSettings: "'case', 'tnum'" }}
|
||||
>
|
||||
Webhooks ({activeWebhookCount} / {webhooks.length})
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={handleAddButton}
|
||||
ref={addButtonRef}
|
||||
>
|
||||
Add webhook…
|
||||
</Button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
||||
transformOrigin={{ vertical: "top", horizontal: "right" }}
|
||||
>
|
||||
{webhookTypes.map((type) => (
|
||||
<MenuItem onClick={() => handleChooseAddType(type)}>
|
||||
{webhookNames[type]}
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
<Divider variant="middle" />
|
||||
|
||||
<MenuItem
|
||||
component="a"
|
||||
href={EMAIL_REQUEST}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<ListItemIcon>
|
||||
<EmailIcon aria-label="Send email" />
|
||||
</ListItemIcon>
|
||||
Request new webhook…
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
|
||||
{webhooks.length === 0 ? (
|
||||
<ButtonBase
|
||||
onClick={handleAddButton}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: 72 * 3,
|
||||
borderRadius: 1,
|
||||
"&:hover": { bgcolor: "action.hover" },
|
||||
}}
|
||||
>
|
||||
<EmptyState
|
||||
message="Add your first webhook"
|
||||
description="Your webhooks will appear here."
|
||||
Icon={WebhookIcon}
|
||||
/>
|
||||
</ButtonBase>
|
||||
) : (
|
||||
<List style={{ paddingTop: 0, minHeight: 72 * 3 }}>
|
||||
{webhooks.map((webhook, index) => (
|
||||
<ListItem
|
||||
disableGutters
|
||||
dense={false}
|
||||
divider={index !== webhooks.length - 1}
|
||||
children={
|
||||
<ListItemText
|
||||
primary={
|
||||
<>
|
||||
{webhook.name} <code>{webhookNames[webhook.type]}</code>
|
||||
</>
|
||||
}
|
||||
secondary={
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<div
|
||||
style={{
|
||||
maxWidth: 340,
|
||||
overflowX: "auto",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption">
|
||||
<code>
|
||||
{baseUrl}
|
||||
{webhook.endpoint}
|
||||
</code>
|
||||
</Typography>
|
||||
</div>
|
||||
<Tooltip title="copy to clipboard">
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(
|
||||
`${baseUrl}${webhook.endpoint}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<CopyIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
}
|
||||
primaryTypographyProps={{
|
||||
style: {
|
||||
minHeight: 40,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
}
|
||||
secondaryAction={
|
||||
<Stack alignItems="flex-end">
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Tooltip title={webhook.active ? "Deactivate" : "Activate"}>
|
||||
<Switch
|
||||
checked={webhook.active}
|
||||
onClick={() =>
|
||||
handleUpdateActive(index, !webhook.active)
|
||||
}
|
||||
inputProps={{ "aria-label": "Activate" }}
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Logs">
|
||||
<IconButton
|
||||
aria-label="Logs"
|
||||
onClick={() => {
|
||||
setModal("cloudLogs");
|
||||
setCloudLogFilters({
|
||||
type: "webhook",
|
||||
timeRange: { type: "days", value: 7 },
|
||||
webhook: [webhook.endpoint],
|
||||
});
|
||||
}}
|
||||
>
|
||||
<LogsIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Edit">
|
||||
<IconButton
|
||||
aria-label="Edit"
|
||||
onClick={() => handleEdit(index)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete">
|
||||
<IconButton
|
||||
aria-label="Delete"
|
||||
color="error"
|
||||
onClick={() => handleDelete(index)}
|
||||
sx={{ "&&": { mr: -1.5 } }}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
Last updated
|
||||
<br />
|
||||
by {webhook.lastEditor.displayName}
|
||||
<br />
|
||||
at{" "}
|
||||
{format(
|
||||
webhook.lastEditor.lastUpdate,
|
||||
DATE_TIME_FORMAT
|
||||
)}
|
||||
</>
|
||||
}
|
||||
<List style={{ paddingTop: 0, minHeight: 89 * 3 - 1 }} disablePadding>
|
||||
{webhooks.map((webhook, index) => (
|
||||
<ListItem
|
||||
disableGutters
|
||||
dense={false}
|
||||
divider={index !== webhooks.length - 1}
|
||||
children={
|
||||
<ListItemText
|
||||
primary={webhook.name}
|
||||
secondary={
|
||||
<>
|
||||
{webhookNames[webhook.type]}{" "}
|
||||
<code
|
||||
style={{
|
||||
userSelect: "all",
|
||||
paddingRight: 0,
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ color: "text.disabled" }}
|
||||
<Tooltip title="Endpoint ID">
|
||||
<span>{webhook.endpoint}</span>
|
||||
</Tooltip>
|
||||
<Tooltip title="Copy endpoint URL">
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(
|
||||
baseUrl + webhook.endpoint
|
||||
)
|
||||
}
|
||||
size="small"
|
||||
color="secondary"
|
||||
sx={{ my: (20 - 32) / 2 / 8 }}
|
||||
>
|
||||
{formatRelative(
|
||||
webhook.lastEditor.lastUpdate,
|
||||
new Date()
|
||||
)}
|
||||
</Typography>
|
||||
<Avatar
|
||||
alt={`${webhook.lastEditor.displayName}’s profile photo`}
|
||||
src={webhook.lastEditor.photoURL}
|
||||
sx={{ width: 24, height: 24, "&&": { mr: -0.5 } }}
|
||||
/>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
<LinkIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</code>
|
||||
</>
|
||||
}
|
||||
primaryTypographyProps={{
|
||||
style: {
|
||||
minHeight: 40,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
secondaryAction={
|
||||
<Stack alignItems="flex-end">
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Tooltip title={webhook.active ? "Deactivate" : "Activate"}>
|
||||
<Switch
|
||||
checked={webhook.active}
|
||||
onClick={() => handleUpdateActive(index, !webhook.active)}
|
||||
inputProps={{ "aria-label": "Activate" }}
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Logs">
|
||||
<IconButton
|
||||
aria-label="Logs"
|
||||
onClick={() => {
|
||||
setModal("cloudLogs");
|
||||
setCloudLogFilters({
|
||||
type: "webhook",
|
||||
timeRange: { type: "days", value: 7 },
|
||||
webhook: [webhook.endpoint],
|
||||
});
|
||||
}}
|
||||
>
|
||||
<LogsIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Edit">
|
||||
<IconButton
|
||||
aria-label="Edit"
|
||||
onClick={() => handleEdit(index)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete…">
|
||||
<IconButton
|
||||
aria-label="Delete…"
|
||||
color="error"
|
||||
onClick={() => handleDelete(index)}
|
||||
sx={{ "&&": { mr: -1.5 } }}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
Last updated
|
||||
<br />
|
||||
by {webhook.lastEditor.displayName}
|
||||
<br />
|
||||
at {format(webhook.lastEditor.lastUpdate, DATE_TIME_FORMAT)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
<Typography variant="body2" sx={{ color: "text.disabled" }}>
|
||||
{formatRelative(webhook.lastEditor.lastUpdate, new Date())}
|
||||
</Typography>
|
||||
<Avatar
|
||||
alt={`${webhook.lastEditor.displayName}’s profile photo`}
|
||||
src={webhook.lastEditor.photoURL}
|
||||
sx={{ width: 24, height: 24, "&&": { mr: -0.5 } }}
|
||||
/>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
}
|
||||
sx={{
|
||||
flexWrap: { xs: "wrap", sm: "nowrap" },
|
||||
"& .MuiListItemSecondaryAction-root": {
|
||||
position: { xs: "static", sm: "absolute" },
|
||||
width: { xs: "100%", sm: "auto" },
|
||||
transform: { xs: "none", sm: "translateY(-50%)" },
|
||||
},
|
||||
pr: { xs: 0, sm: 216 / 8 },
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@ import { useState } from "react";
|
||||
import _isEqual from "lodash/isEqual";
|
||||
import useStateRef from "react-usestateref";
|
||||
|
||||
import { Grid, TextField, FormControlLabel, Switch } from "@mui/material";
|
||||
import {
|
||||
Grid,
|
||||
TextField,
|
||||
FormControlLabel,
|
||||
Switch,
|
||||
Stack,
|
||||
} from "@mui/material";
|
||||
|
||||
import Modal, { IModalProps } from "@src/components/Modal";
|
||||
import SteppedAccordion from "@src/components/SteppedAccordion";
|
||||
@@ -16,7 +22,9 @@ import { webhookNames, IWebhook } from "./utils";
|
||||
import CopyIcon from "@src/assets/icons/Copy";
|
||||
import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { IconButton, Tooltip, Typography } from "@mui/material";
|
||||
|
||||
type StepValidation = Record<"condition" | "parser", boolean>;
|
||||
|
||||
export interface IWebhookModalStepProps {
|
||||
webhookObject: IWebhook;
|
||||
setWebhookObject: React.Dispatch<React.SetStateAction<IWebhook>>;
|
||||
@@ -128,36 +136,39 @@ export default function WebhookModal({
|
||||
}activated`}
|
||||
/>
|
||||
</Grid>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography>URL:</Typography>
|
||||
<div
|
||||
style={{
|
||||
maxWidth: "90%",
|
||||
overflowX: "auto",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption">
|
||||
<code>
|
||||
{baseUrl}
|
||||
{webhookObject.endpoint}
|
||||
</code>
|
||||
</Typography>
|
||||
</div>
|
||||
<Tooltip title="copy to clipboard">
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(
|
||||
`${baseUrl}${webhookObject.endpoint}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<CopyIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Grid>
|
||||
|
||||
<Stack direction="row" alignItems="center" style={{ marginTop: 0 }}>
|
||||
<Typography
|
||||
variant="inherit"
|
||||
style={{ whiteSpace: "nowrap", flexShrink: 0 }}
|
||||
>
|
||||
Endpoint URL:
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
style={{ overflowX: "auto", whiteSpace: "nowrap", flexGrow: 1 }}
|
||||
>
|
||||
<code>
|
||||
{baseUrl}
|
||||
{webhookObject.endpoint}
|
||||
</code>
|
||||
</Typography>
|
||||
<Tooltip title="Copy endpoint URL">
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(
|
||||
`${baseUrl}${webhookObject.endpoint}`
|
||||
)
|
||||
}
|
||||
sx={{ flexShrink: 0, mr: -0.75 }}
|
||||
>
|
||||
<CopyIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
|
||||
<SteppedAccordion
|
||||
steps={[
|
||||
{
|
||||
@@ -178,6 +189,7 @@ export default function WebhookModal({
|
||||
content: <Step3Body {...stepProps} />,
|
||||
},
|
||||
]}
|
||||
style={{ marginTop: "var(--dialog-contents-spacing)" }}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { useState } from "react";
|
||||
import _isEqual from "lodash/isEqual";
|
||||
|
||||
import { Breadcrumbs } from "@mui/material";
|
||||
|
||||
import TableHeaderButton from "../TableHeaderButton";
|
||||
import WebhookIcon from "@src/assets/icons/Webhook";
|
||||
import Modal from "@src/components/Modal";
|
||||
import AddWebhookButton from "./AddWebhookButton";
|
||||
import WebhookList from "./WebhookList";
|
||||
import WebhookModal from "./WebhookModal";
|
||||
|
||||
@@ -34,26 +33,25 @@ export default function Webhooks() {
|
||||
webhookObject: IWebhook;
|
||||
index?: number;
|
||||
} | null>(null);
|
||||
if (!compatibleRowyRunVersion?.({ minVersion: "1.2.0" })) return <></>;
|
||||
const edited = !_isEqual(currentWebhooks, localWebhooksObjects);
|
||||
|
||||
const tablePathTokens =
|
||||
tableState?.tablePath?.split("/").filter(function (_, i) {
|
||||
// replace IDs with dash that appears at even indexes
|
||||
return i % 2 === 0;
|
||||
}) ?? [];
|
||||
if (!compatibleRowyRunVersion?.({ minVersion: "1.2.0" })) return null;
|
||||
|
||||
const edited = !_isEqual(currentWebhooks, localWebhooksObjects);
|
||||
|
||||
const handleOpen = () => {
|
||||
setOpenWebhookList(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
const handleClose = (
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>
|
||||
) => {
|
||||
if (edited) {
|
||||
setOpen(true);
|
||||
requestConfirmation({
|
||||
title: "Discard changes",
|
||||
body: "You will lose changes you have made to webhooks",
|
||||
title: "Discard changes?",
|
||||
confirm: "Discard",
|
||||
handleConfirm: () => {
|
||||
setOpen(false);
|
||||
setLocalWebhooksObjects(currentWebhooks);
|
||||
setOpenWebhookList(false);
|
||||
},
|
||||
@@ -142,8 +140,8 @@ export default function Webhooks() {
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
requestConfirmation({
|
||||
title: `Delete ${localWebhooksObjects[index].name}?`,
|
||||
body: "This webhook will be permanently deleted.",
|
||||
title: `Delete “${localWebhooksObjects[index].name}”?`,
|
||||
body: "This webhook will be permanently deleted when you save",
|
||||
confirm: "Confirm",
|
||||
handleConfirm: () => {
|
||||
setLocalWebhooksObjects(
|
||||
@@ -159,6 +157,10 @@ export default function Webhooks() {
|
||||
lastUpdate: Date.now(),
|
||||
});
|
||||
|
||||
const activeWebhookCount = localWebhooksObjects.filter(
|
||||
(webhook) => webhook.active
|
||||
).length;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableHeaderButton
|
||||
@@ -170,29 +172,31 @@ export default function Webhooks() {
|
||||
{openWebhookList && !!tableState && (
|
||||
<Modal
|
||||
onClose={handleClose}
|
||||
disableBackdropClick={edited}
|
||||
disableEscapeKeyDown={edited}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
title="Webhooks"
|
||||
title={`Webhooks (${activeWebhookCount}\u2009/\u2009${localWebhooksObjects.length})`}
|
||||
header={
|
||||
<AddWebhookButton
|
||||
handleAddWebhook={(type: WebhookType) => {
|
||||
setWebhookModal({
|
||||
mode: "add",
|
||||
webhookObject: emptyWebhookObject(type, currentEditor()),
|
||||
});
|
||||
}}
|
||||
variant={
|
||||
localWebhooksObjects.length === 0 ? "contained" : "outlined"
|
||||
}
|
||||
/>
|
||||
}
|
||||
children={
|
||||
<>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
{tablePathTokens.map((pathToken) => (
|
||||
<code>{pathToken}</code>
|
||||
))}
|
||||
</Breadcrumbs>
|
||||
<WebhookList
|
||||
webhooks={localWebhooksObjects}
|
||||
handleAddWebhook={(type: WebhookType) => {
|
||||
setWebhookModal({
|
||||
mode: "add",
|
||||
webhookObject: emptyWebhookObject(type, currentEditor()),
|
||||
});
|
||||
}}
|
||||
handleUpdateActive={handleUpdateActive}
|
||||
handleEdit={handleEdit}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
</>
|
||||
<WebhookList
|
||||
webhooks={localWebhooksObjects}
|
||||
handleUpdateActive={handleUpdateActive}
|
||||
handleEdit={handleEdit}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
}
|
||||
actions={{
|
||||
primary: {
|
||||
|
||||
@@ -40,9 +40,9 @@ const additionalVariables = [
|
||||
export type WebhookType = typeof webhookTypes[number];
|
||||
|
||||
export const webhookNames: Record<WebhookType, string> = {
|
||||
sendgrid: "Sendgrid",
|
||||
sendgrid: "SendGrid",
|
||||
typeform: "Typeform",
|
||||
//github:"Github",
|
||||
//github:"GitHub",
|
||||
// shopify: "Shopify",
|
||||
// twitter: "Twitter",
|
||||
// stripe: "Stripe",
|
||||
@@ -73,6 +73,7 @@ export const webhookSchemas = {
|
||||
typeform,
|
||||
sendgrid,
|
||||
};
|
||||
|
||||
export function emptyWebhookObject(
|
||||
type: WebhookType,
|
||||
user: IWebhookEditor
|
||||
|
||||
@@ -30,9 +30,9 @@ export default function FadeList({
|
||||
children,
|
||||
disableTopDivider = true,
|
||||
disableBottomDivider = false,
|
||||
dividerSx,
|
||||
topDividerSx,
|
||||
bottomDividerSx,
|
||||
dividerSx = [],
|
||||
topDividerSx = [],
|
||||
bottomDividerSx = [],
|
||||
listSx,
|
||||
}: IFadeListProps) {
|
||||
const [scrollInfo, setRef] = useScrollInfo();
|
||||
@@ -42,7 +42,12 @@ export default function FadeList({
|
||||
{!disableTopDivider &&
|
||||
scrollInfo.y.percentage !== null &&
|
||||
scrollInfo.y.percentage > 0 && (
|
||||
<Divider sx={{ ...dividerSx, ...topDividerSx }} />
|
||||
<Divider
|
||||
sx={[
|
||||
...(Array.isArray(dividerSx) ? dividerSx : [dividerSx]),
|
||||
...(Array.isArray(topDividerSx) ? topDividerSx : [topDividerSx]),
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<MemoizedList ref={setRef} sx={listSx}>
|
||||
@@ -52,7 +57,14 @@ export default function FadeList({
|
||||
{!disableBottomDivider &&
|
||||
scrollInfo.y.percentage !== null &&
|
||||
scrollInfo.y.percentage < 1 && (
|
||||
<Divider sx={{ ...dividerSx, ...bottomDividerSx }} />
|
||||
<Divider
|
||||
sx={[
|
||||
...(Array.isArray(dividerSx) ? dividerSx : [dividerSx]),
|
||||
...(Array.isArray(bottomDividerSx)
|
||||
? bottomDividerSx
|
||||
: [bottomDividerSx]),
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function Checkbox({
|
||||
letterSpacing: "inherit",
|
||||
flexGrow: 1,
|
||||
overflowX: "hidden",
|
||||
mt: 0,
|
||||
mt: "0 !important",
|
||||
},
|
||||
|
||||
"& .MuiSwitch-root": { mr: -0.75 },
|
||||
|
||||
@@ -52,7 +52,7 @@ export default function ConnectServiceSelect({
|
||||
SelectProps={{
|
||||
renderValue: (value) => `${(value as any[]).length} selected`,
|
||||
displayEmpty: true,
|
||||
classes: { root: classes.selectRoot },
|
||||
classes: { select: classes.selectRoot },
|
||||
...TextFieldProps.SelectProps,
|
||||
// Must have this set to prevent MUI transforming `value`
|
||||
// prop for this component to a comma-separated string
|
||||
|
||||
@@ -2,7 +2,7 @@ import { lazy } from "react";
|
||||
import { IFieldConfig, FieldType } from "@src/components/fields/types";
|
||||
import withHeavyCell from "../_withTableCell/withHeavyCell";
|
||||
|
||||
import DurationIcon from "@mui/icons-material/Timer";
|
||||
import DurationIcon from "@mui/icons-material/TimerOutlined";
|
||||
import BasicCell from "../_BasicCell/BasicCellNull";
|
||||
import NullEditor from "@src/components/Table/editors/NullEditor";
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function Json({
|
||||
className={fieldClasses.root}
|
||||
style={{
|
||||
whiteSpace: "pre-wrap",
|
||||
...theme.typography.caption,
|
||||
...(theme.typography.caption as any),
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
@@ -94,7 +94,10 @@ export default function Json({
|
||||
<TabPanel value="tree" sx={{ p: 0 }}>
|
||||
<div
|
||||
className={fieldClasses.root}
|
||||
style={{ overflowX: "auto", ...theme.typography.caption }}
|
||||
style={{
|
||||
overflowX: "auto",
|
||||
...(theme.typography.caption as any),
|
||||
}}
|
||||
>
|
||||
<ReactJson
|
||||
src={sanitizedValue}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { DataGridHandle } from "react-data-grid";
|
||||
import _sortBy from "lodash/sortBy";
|
||||
import _find from "lodash/find";
|
||||
import firebase from "firebase/app";
|
||||
import { compare } from "compare-versions";
|
||||
|
||||
import { Button } from "@mui/material";
|
||||
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
|
||||
@@ -19,7 +20,6 @@ import { rowyRun, IRowyRunRequestProps } from "@src/utils/rowyRun";
|
||||
import { rowyUser } from "@src/utils/fns";
|
||||
import { WIKI_LINKS } from "@src/constants/externalLinks";
|
||||
import { runRoutes } from "@src/constants/runRoutes";
|
||||
import semver from "semver";
|
||||
|
||||
export type Table = {
|
||||
id: string;
|
||||
@@ -375,13 +375,12 @@ export const ProjectContextProvider: React.FC = ({ children }) => {
|
||||
minVersion?: string;
|
||||
maxVersion?: string;
|
||||
}) => {
|
||||
// example: "1.0.0", "1.0.0-beta.1", "1.0.0-rc.1+1"
|
||||
const version = rowyRunVersion.split("-")[0];
|
||||
if (!version) return false;
|
||||
if (minVersion && semver.lt(version, minVersion)) return false;
|
||||
if (maxVersion && semver.gt(version, maxVersion)) return false;
|
||||
if (!rowyRunVersion) return false;
|
||||
if (minVersion && compare(rowyRunVersion, minVersion, "<")) return false;
|
||||
if (maxVersion && compare(rowyRunVersion, maxVersion, ">")) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
// A ref to the data grid. Contains data grid functions
|
||||
const dataGridRef = useRef<DataGridHandle>(null);
|
||||
const sideDrawerRef = useRef<SideDrawerRef>();
|
||||
|
||||
@@ -200,7 +200,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
"--dialog-contents-spacing": theme.spacing(3),
|
||||
"& > * + *": { marginTop: "var(--dialog-contents-spacing)" },
|
||||
|
||||
...theme.typography.body2,
|
||||
...(theme.typography.body2 as any),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -266,7 +266,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
caretColor: theme.palette.primary.main,
|
||||
".Mui-error &": { caretColor: theme.palette.error.main },
|
||||
},
|
||||
inputSizeSmall: theme.typography.body2,
|
||||
inputSizeSmall: theme.typography.body2 as any,
|
||||
},
|
||||
},
|
||||
MuiFilledInput: {
|
||||
@@ -341,7 +341,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
MuiInputLabel: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
...theme.typography.button,
|
||||
...(theme.typography.button as any),
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
filled: {
|
||||
@@ -360,7 +360,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
MuiFormLabel: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
...theme.typography.button,
|
||||
...(theme.typography.button as any),
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
},
|
||||
@@ -441,7 +441,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
defaultProps: { disableSticky: true },
|
||||
styleOverrides: {
|
||||
root: {
|
||||
...theme.typography.subtitle2,
|
||||
...(theme.typography.subtitle2 as any),
|
||||
color: theme.palette.text.primary,
|
||||
lineHeight: "32px",
|
||||
userSelect: "none",
|
||||
@@ -1037,7 +1037,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
MuiAlertTitle: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
...theme.typography.subtitle2,
|
||||
...(theme.typography.subtitle2 as any),
|
||||
lineHeight: "1.5rem",
|
||||
},
|
||||
},
|
||||
@@ -1091,7 +1091,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
"& .PrivatePickersYear-yearButton": {
|
||||
...theme.typography.button,
|
||||
...(theme.typography.button as any),
|
||||
fontSize: "1rem",
|
||||
},
|
||||
},
|
||||
|
||||
305
yarn.lock
305
yarn.lock
@@ -1460,7 +1460,7 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
version "7.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a"
|
||||
integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
|
||||
@@ -1488,6 +1488,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.16.3":
|
||||
version "7.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5"
|
||||
integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.7.2":
|
||||
version "7.8.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.7.tgz#8fefce9802db54881ba59f90bb28719b4996324d"
|
||||
@@ -1709,6 +1716,17 @@
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
stylis "^4.0.3"
|
||||
|
||||
"@emotion/cache@^11.6.0":
|
||||
version "11.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.6.0.tgz#65fbdbbe4382f1991d8b20853c38e63ecccec9a1"
|
||||
integrity sha512-ElbsWY1KMwEowkv42vGo0UPuLgtPYfIs9BxxVrmvsaJVvktknsHYYlx5NQ5g6zLDcOTyamlDc7FkRg2TAcQDKQ==
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.7.4"
|
||||
"@emotion/sheet" "^1.1.0"
|
||||
"@emotion/utils" "^1.0.0"
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
stylis "^4.0.10"
|
||||
|
||||
"@emotion/hash@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||
@@ -1721,6 +1739,13 @@
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.7.4"
|
||||
|
||||
"@emotion/is-prop-valid@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.1.tgz#cbd843d409dfaad90f9404e7c0404c55eae8c134"
|
||||
integrity sha512-bW1Tos67CZkOURLc0OalnfxtSXQJMrAMV0jZTVGJUPSOd4qgjF3+tTD5CwJM13PHA8cltGW1WGbbvV9NpvUZPw==
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.7.4"
|
||||
|
||||
"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
|
||||
@@ -1755,6 +1780,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.2.tgz#1d9ffde531714ba28e62dac6a996a8b1089719d0"
|
||||
integrity sha512-QQPB1B70JEVUHuNtzjHftMGv6eC3Y9wqavyarj4x4lg47RACkeSfNo5pxIOKizwS9AEFLohsqoaxGQj4p0vSIw==
|
||||
|
||||
"@emotion/sheet@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2"
|
||||
integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==
|
||||
|
||||
"@emotion/styled@^11.3.0":
|
||||
version "11.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.3.0.tgz#d63ee00537dfb6ff612e31b0e915c5cf9925a207"
|
||||
@@ -2362,10 +2392,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@mdi/js/-/js-5.9.55.tgz#8f5bc4d924c23f30dab20545ddc768e778bbc882"
|
||||
integrity sha512-BbeHMgeK2/vjdJIRnx12wvQ6s8xAYfvMmEAVsUx9b+7GiQGQ9Za8jpwp17dMKr9CgKRvemlAM4S7S3QOtEbp4A==
|
||||
|
||||
"@mdi/js@^6.2.95":
|
||||
version "6.2.95"
|
||||
resolved "https://registry.yarnpkg.com/@mdi/js/-/js-6.2.95.tgz#decf0f86035990248f25b0a4e246a7d152211273"
|
||||
integrity sha512-fbD22sEBathqVSQWcxshEtzhhRNFmMnV64z6T7DClRbQ9N5axorykt3Suv2zPzLDyiqH7UhNRu0VPvPCPDNpnQ==
|
||||
"@mdi/js@^6.5.95":
|
||||
version "6.5.95"
|
||||
resolved "https://registry.yarnpkg.com/@mdi/js/-/js-6.5.95.tgz#2d895b013408f213252b77c30e0fdaaba6dc8b4b"
|
||||
integrity sha512-x/bwEoAGP+Mo10Dfk5audNIPi7Yz8ZBrILcbXLW3ShOI/njpgodzpgpC2WYK3D2ZSC392peRRemIFb/JsyzzYQ==
|
||||
|
||||
"@monaco-editor/loader@^1.2.0":
|
||||
version "1.2.0"
|
||||
@@ -2382,129 +2412,129 @@
|
||||
"@monaco-editor/loader" "^1.2.0"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@mui/core@5.0.0-alpha.50":
|
||||
version "5.0.0-alpha.50"
|
||||
resolved "https://registry.yarnpkg.com/@mui/core/-/core-5.0.0-alpha.50.tgz#055b7ccf8557f849e8e61a39a8e3943f8abad9b0"
|
||||
integrity sha512-szmmzbyAjEQku17IoEWs7t77n0Kr4zVnT5fREfMd+CnCA4YDifr68ccGJfWaeoGp5Zw/JmfKjQJXLY4GgT6i/g==
|
||||
"@mui/base@5.0.0-alpha.58":
|
||||
version "5.0.0-alpha.58"
|
||||
resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.58.tgz#01ab59a028f314e2f9a79f903a8336ac45853652"
|
||||
integrity sha512-YZorCbbzkokQZUnj+sdjUWIe+jaesuSVpKgwWS2mWdE50v1Ti/qMmevIrOT1lvFAilpj80Bkcg4KtlGWBJ6utQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@emotion/is-prop-valid" "^1.1.0"
|
||||
"@mui/utils" "^5.0.1"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@emotion/is-prop-valid" "^1.1.1"
|
||||
"@mui/utils" "^5.2.2"
|
||||
"@popperjs/core" "^2.4.4"
|
||||
clsx "^1.1.1"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^17.0.2"
|
||||
|
||||
"@mui/icons-material@^5.0.0":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.0.3.tgz#2a9d4f9078f375cef40f63a240b59cefa4a27eec"
|
||||
integrity sha512-Lktn+4GNnXdVrOCUUvNNvOD9VyrGazWBsJy0BQeQgBe/+IjFMdlcNrDEUIlGlA5ZXOq7Mr/Mv9Os02mgF65jiw==
|
||||
"@mui/icons-material@^5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.2.0.tgz#6c6135bb2d7891e29d6f9419df402b82dd663517"
|
||||
integrity sha512-NvyrVaGKpP4R1yFw8BCnE0QcsQ67RtpgxPr4FtH8q60MDYPuPVczLOn5Ash5CFavoDWur/NfM/4DpT54yf3InA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
|
||||
"@mui/lab@^5.0.0-alpha.50":
|
||||
version "5.0.0-alpha.50"
|
||||
resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.50.tgz#4102698b176eba28ef16ee1fcb6b0677f2fb221b"
|
||||
integrity sha512-8DgRjQjjObrHpdFx5HSjw27zQlSf0gc+I911ZSs+YIn7TADQgtg3QzaHqe5o54b+91LhMfugQAtPlRjqXMaEKA==
|
||||
"@mui/lab@^5.0.0-alpha.58":
|
||||
version "5.0.0-alpha.58"
|
||||
resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.58.tgz#47c3b2976df066119fa040131a63139677ba5a66"
|
||||
integrity sha512-Vn3bWlID2SgCb7KX3d29uSLWv3JDEHJ+QiApnaPuUqqymwHARbQUk+b2h6wfQCz/WqaR0MtmsRwA6OrrLsL3Eg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@date-io/date-fns" "^2.11.0"
|
||||
"@date-io/dayjs" "^2.11.0"
|
||||
"@date-io/luxon" "^2.11.1"
|
||||
"@date-io/moment" "^2.11.0"
|
||||
"@mui/core" "5.0.0-alpha.50"
|
||||
"@mui/system" "^5.0.3"
|
||||
"@mui/utils" "^5.0.1"
|
||||
"@mui/base" "5.0.0-alpha.58"
|
||||
"@mui/system" "^5.2.2"
|
||||
"@mui/utils" "^5.2.2"
|
||||
clsx "^1.1.1"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^17.0.2"
|
||||
react-transition-group "^4.4.2"
|
||||
rifm "^0.12.0"
|
||||
rifm "^0.12.1"
|
||||
|
||||
"@mui/material@^5.0.0":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.0.3.tgz#5ac4d9f7d9635efc9cf7347373e49db41f1b065b"
|
||||
integrity sha512-Qj2hwSi63qrYRJuHrUFdN83lCT6HXyLzpCniDTvK7NlqXCnpy4F3Gg0hRJTnO4hNqTTBV+SCOKTSbfuzHl/dnQ==
|
||||
"@mui/material@^5.2.2":
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.2.2.tgz#4dfbc9186a83e16a9dcdcc10e4a70ecaf641b1a3"
|
||||
integrity sha512-vqmZq+v59CT4V84WcvYkYldnjC6uRddYx0TJqgl2h5YRbbPYCGVVywVvg9cBwxy4j5xI3F2WH6z7WGkHqkJIQA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@mui/core" "5.0.0-alpha.50"
|
||||
"@mui/system" "^5.0.3"
|
||||
"@mui/types" "^7.0.0"
|
||||
"@mui/utils" "^5.0.1"
|
||||
"@popperjs/core" "^2.4.4"
|
||||
"@types/react-transition-group" "^4.4.3"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@mui/base" "5.0.0-alpha.58"
|
||||
"@mui/system" "^5.2.2"
|
||||
"@mui/types" "^7.1.0"
|
||||
"@mui/utils" "^5.2.2"
|
||||
"@types/react-transition-group" "^4.4.4"
|
||||
clsx "^1.1.1"
|
||||
csstype "^3.0.9"
|
||||
csstype "^3.0.10"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^17.0.2"
|
||||
react-transition-group "^4.4.2"
|
||||
|
||||
"@mui/private-theming@^5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.0.1.tgz#50a0ea6ad5a8d1d78072859c4bdaaa6b6584d986"
|
||||
integrity sha512-R8Cf2+32cG1OXFAqTighA5Mx9R5BQ57cN1ZVaNgfgdbI87Yig2fVMdFSPrw3txcjKlnwsvFJF8AdwQMqq1tJ3Q==
|
||||
"@mui/private-theming@^5.2.2":
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.2.2.tgz#ede801bc4b6939aedf5900edcece981fde8fa210"
|
||||
integrity sha512-BfTjZ5ao6KY4Sg11lgaVuQ9uUq8unaM2u9/RKDD12If0B2Vp/AhRSe7i5OTd+wErmK2guTX0kPSraGZzwDEIVg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@mui/utils" "^5.0.1"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@mui/utils" "^5.2.2"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@mui/styled-engine@^5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.0.1.tgz#401e3e0ff846ad1b1e7e097c8050b36d7b68343e"
|
||||
integrity sha512-j40nCbaKr1HAZYqpX61XvZYsadYskjo3u6+pRFFaewSViAkkD1rjjbubpnh15nqVfYmijtHMZJ9/l1x1hamvfQ==
|
||||
"@mui/styled-engine@^5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.2.0.tgz#5c97e2b1b6c4c2d9991f07517ed862972d362b85"
|
||||
integrity sha512-NZ4pWYQcM5wreUfiXRd7IMFRF+Nq1vMzsIdXtXNjgctJTKHunrofasoBqv+cqevO+hqT75ezSbNHyaXzOXp6Mg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@emotion/cache" "^11.4.0"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@emotion/cache" "^11.6.0"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@mui/styles@^5.0.0":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.0.1.tgz#1634d08d892b5c7e85c9f84e4fc8bc02a5fb0f7a"
|
||||
integrity sha512-hCtR2ZVOkoIhpTan02I4UEShnZxe59WwhKRJqauMs/addXByhAHHCNheTdiV++Irl/fyyFObmzPM0CUD3q6FIA==
|
||||
"@mui/styles@^5.2.2":
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.2.2.tgz#34c9ba1d6d5a0b9399fbd0c6e85b8f2dcfe54fbd"
|
||||
integrity sha512-Hfg/3nAU+25RVzpgB0xyE1JjrOCI4rjujrJ0K4tS7M/U4NKZQrmtinc5ldvCaZUlxb51bZGs5V1MGn2dLKZVNQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@emotion/hash" "^0.8.0"
|
||||
"@mui/private-theming" "^5.0.1"
|
||||
"@mui/types" "^7.0.0"
|
||||
"@mui/utils" "^5.0.1"
|
||||
"@mui/private-theming" "^5.2.2"
|
||||
"@mui/types" "^7.1.0"
|
||||
"@mui/utils" "^5.2.2"
|
||||
clsx "^1.1.1"
|
||||
csstype "^3.0.9"
|
||||
csstype "^3.0.10"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
jss "^10.8.0"
|
||||
jss-plugin-camel-case "^10.8.0"
|
||||
jss-plugin-default-unit "^10.8.0"
|
||||
jss-plugin-global "^10.8.0"
|
||||
jss-plugin-nested "^10.8.0"
|
||||
jss-plugin-props-sort "^10.8.0"
|
||||
jss-plugin-rule-value-function "^10.8.0"
|
||||
jss-plugin-vendor-prefixer "^10.8.0"
|
||||
jss "^10.8.2"
|
||||
jss-plugin-camel-case "^10.8.2"
|
||||
jss-plugin-default-unit "^10.8.2"
|
||||
jss-plugin-global "^10.8.2"
|
||||
jss-plugin-nested "^10.8.2"
|
||||
jss-plugin-props-sort "^10.8.2"
|
||||
jss-plugin-rule-value-function "^10.8.2"
|
||||
jss-plugin-vendor-prefixer "^10.8.2"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@mui/system@^5.0.3":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.0.3.tgz#6c126be5c2796fe89af93aa0e76d1c3c6dcccf45"
|
||||
integrity sha512-pNkW9p6Dj/ch3YCKjvrXrBhKsAyJ1/l273Q0hh60hhTKHJXgKBVONQ8r7l1fFHtufI0NNz6UGMVJooIXg4JJtA==
|
||||
"@mui/system@^5.2.2":
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.2.2.tgz#81ef74f0c269d18b99a2d0253833d6554bbf5198"
|
||||
integrity sha512-221tPOcZC8A89GOt6LH9YPTj2Iqf880iqrHd7AHT/HznBKOlLrnWD83pCuLPyX2jeFz4OzhvmGbdt5a74UEgaA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@mui/private-theming" "^5.0.1"
|
||||
"@mui/styled-engine" "^5.0.1"
|
||||
"@mui/types" "^7.0.0"
|
||||
"@mui/utils" "^5.0.1"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@mui/private-theming" "^5.2.2"
|
||||
"@mui/styled-engine" "^5.2.0"
|
||||
"@mui/types" "^7.1.0"
|
||||
"@mui/utils" "^5.2.2"
|
||||
clsx "^1.1.1"
|
||||
csstype "^3.0.9"
|
||||
csstype "^3.0.10"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@mui/types@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.0.0.tgz#a7398502bc9c508875aafcbe28aea599b2c3d203"
|
||||
integrity sha512-M/tkF2pZ4uoPhZ8pnNhlVnOFtz6F3dnYKIsnj8MuXKT6d26IE2u0UjA8B0275ggN74dR9rlHG5xJt5jgDx/Ung==
|
||||
"@mui/types@^7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.1.0.tgz#5ed928c5a41cfbf9a4be82ea3bbdc47bcc9610d5"
|
||||
integrity sha512-Hh7ALdq/GjfIwLvqH3XftuY3bcKhupktTm+S6qRIDGOtPtRuq2L21VWzOK4p7kblirK0XgGVH5BLwa6u8z/6QQ==
|
||||
|
||||
"@mui/utils@^5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.0.1.tgz#d4f0f41b82db6ac273920a1b5b6a4de7879271f5"
|
||||
integrity sha512-GWO104N+o9KG5fKiTEYnAg7kONKEg3vLN+VROAU0f3it6lFGLCVPcQYex/1gJ4QAy96u6Ez8/Hmmhi1+3cX0tQ==
|
||||
"@mui/utils@^5.2.2":
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.2.2.tgz#972aab7d2564e77c06e0c3c11e7b1aec6e37c927"
|
||||
integrity sha512-0u9ImUfpCfTxmvQTfUzTSS+jKWMX15MBZeZCRQZ0f7o9Yi8BlrLj33lMx0mFBkUSYdTXnqL4yfOn7RBzV01HMQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@types/prop-types" "^15.7.4"
|
||||
"@types/react-is" "^16.7.1 || ^17.0.0"
|
||||
prop-types "^15.7.2"
|
||||
@@ -3244,10 +3274,10 @@
|
||||
"@types/history" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@^4.4.3":
|
||||
version "4.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.3.tgz#b0994da0a7023d67dbb4a8910a62112bc00d5688"
|
||||
integrity sha512-fUx5muOWSYP8Bw2BUQ9M9RK9+W1XBK/7FLJ8PTQpnpTEkn0ccyMffyEQvan4C3h53gHdx7KE5Qrxi/LnUGQtdg==
|
||||
"@types/react-transition-group@^4.4.4":
|
||||
version "4.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"
|
||||
integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
@@ -6043,7 +6073,12 @@ cssstyle@^2.3.0:
|
||||
dependencies:
|
||||
cssom "~0.3.6"
|
||||
|
||||
csstype@^3.0.2, csstype@^3.0.9:
|
||||
csstype@^3.0.10:
|
||||
version "3.0.10"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
|
||||
integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b"
|
||||
integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==
|
||||
@@ -10136,70 +10171,70 @@ jsprim@^1.2.2:
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
jss-plugin-camel-case@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.0.tgz#575fd849202d36713a6970796458e375754446c7"
|
||||
integrity sha512-yxlXrXwcCdGw+H4BC187dEu/RFyW8joMcWfj8Rk9UPgWTKu2Xh7Sib4iW3xXjHe/t5phOHF1rBsHleHykWix7g==
|
||||
jss-plugin-camel-case@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz#8d7f915c8115afaff8cbde08faf610ec9892fba6"
|
||||
integrity sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
hyphenate-style-name "^1.0.3"
|
||||
jss "10.8.0"
|
||||
jss "10.8.2"
|
||||
|
||||
jss-plugin-default-unit@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.0.tgz#98db5962e62abbf43f1cc111e62cb70ffb09db59"
|
||||
integrity sha512-9XJV546cY9zV9OvIE/v/dOaxSi4062VfYQQfwbplRExcsU2a79Yn+qDz/4ciw6P4LV1Naq90U+OffAGRHfNq/Q==
|
||||
jss-plugin-default-unit@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz#c66f12e02e0815d911b85c02c2a979ee7b4ce69a"
|
||||
integrity sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.8.0"
|
||||
jss "10.8.2"
|
||||
|
||||
jss-plugin-global@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.8.0.tgz#0c2b0c056087f5846d600f3332eeb7a1a8b9c9f2"
|
||||
integrity sha512-H/8h/bHd4e7P0MpZ9zaUG8NQSB2ie9rWo/vcCP6bHVerbKLGzj+dsY22IY3+/FNRS8zDmUyqdZx3rD8k4nmH4w==
|
||||
jss-plugin-global@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz#1a35632a693cf50113bcc5ffe6b51969df79c4ec"
|
||||
integrity sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.8.0"
|
||||
jss "10.8.2"
|
||||
|
||||
jss-plugin-nested@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.8.0.tgz#7ef9a815e9c9fbede41a8f52ce75cffb4c3b86d5"
|
||||
integrity sha512-MhmINZkSxyFILcFBuDoZmP1+wj9fik/b9SsjoaggkGjdvMQCES21mj4K5ZnRGVm448gIXyi9j/eZjtDzhaHUYQ==
|
||||
jss-plugin-nested@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz#79f3c7f75ea6a36ae72fe52e777035bb24d230c7"
|
||||
integrity sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.8.0"
|
||||
jss "10.8.2"
|
||||
tiny-warning "^1.0.2"
|
||||
|
||||
jss-plugin-props-sort@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.0.tgz#2a83e8ca80d72828495bad57b485f7d55a33543b"
|
||||
integrity sha512-VY+Wt5WX5GMsXDmd+Ts8+O16fpiCM81svbox++U3LDbJSM/g9FoMx3HPhwUiDfmgHL9jWdqEuvSl/JAk+mh6mQ==
|
||||
jss-plugin-props-sort@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz#e25a7471868652c394562b6dc5433dcaea7dff6f"
|
||||
integrity sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.8.0"
|
||||
jss "10.8.2"
|
||||
|
||||
jss-plugin-rule-value-function@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.0.tgz#e011ed180789229e7ea8f75c222d34810bcab520"
|
||||
integrity sha512-R8N8Ma6Oye1F9HroiUuHhVjpPsVq97uAh+rMI6XwKLqirIu2KFb5x33hPj+vNBMxSHc9jakhf5wG0BbQ7fSDOg==
|
||||
jss-plugin-rule-value-function@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz#55354b55f1b2968a15976729968f767f02d64049"
|
||||
integrity sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.8.0"
|
||||
jss "10.8.2"
|
||||
tiny-warning "^1.0.2"
|
||||
|
||||
jss-plugin-vendor-prefixer@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.0.tgz#024b6d77be50b68e5dfca2c75f68091d8b722d61"
|
||||
integrity sha512-G1zD0J8dFwKZQ+GaZaay7A/Tg7lhDw0iEkJ/iFFA5UPuvZFpMprCMQttXcTBhLlhhWnyZ8YPn4yqp+amrhQekw==
|
||||
jss-plugin-vendor-prefixer@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz#ebb4a482642f34091e454901e21176441dd5f475"
|
||||
integrity sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
css-vendor "^2.0.8"
|
||||
jss "10.8.0"
|
||||
jss "10.8.2"
|
||||
|
||||
jss@10.8.0, jss@^10.8.0:
|
||||
version "10.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jss/-/jss-10.8.0.tgz#5063ee73aabd9f228ea3849df7962f0d2e213a42"
|
||||
integrity sha512-6fAMLJrVQ8epM5ghghxWqCwRR0ZamP2cKbOAtzPudcCMSNdAqtvmzQvljUZYR8OXJIeb/IpZeOXA1sDXms4R1w==
|
||||
jss@10.8.2, jss@^10.8.2:
|
||||
version "10.8.2"
|
||||
resolved "https://registry.yarnpkg.com/jss/-/jss-10.8.2.tgz#4b2a30b094b924629a64928236017a52c7c97505"
|
||||
integrity sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
csstype "^3.0.2"
|
||||
@@ -14287,10 +14322,10 @@ rgba-regex@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
|
||||
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
|
||||
|
||||
rifm@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.0.tgz#8d3a9dc0de9c190e0de9bdc8861a91a221dc1341"
|
||||
integrity sha512-PqOl+Mo2lyqrKiD34FPlnQ+ksD3F+a62TQlphiZshgriyHdfjn6jGyqUZhd+s3nsMYXwXYDdjrrv8wX7QsOG3g==
|
||||
rifm@^0.12.1:
|
||||
version "0.12.1"
|
||||
resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.1.tgz#8fa77f45b7f1cda2a0068787ac821f0593967ac4"
|
||||
integrity sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==
|
||||
|
||||
rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.3:
|
||||
version "2.7.1"
|
||||
@@ -15319,7 +15354,7 @@ stylehacks@^4.0.0:
|
||||
postcss "^7.0.0"
|
||||
postcss-selector-parser "^3.0.0"
|
||||
|
||||
stylis@^4.0.3:
|
||||
stylis@^4.0.10, stylis@^4.0.3:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240"
|
||||
integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg==
|
||||
|
||||
Reference in New Issue
Block a user