mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-17 19:37:02 +00:00
Finished contact CRUD and frontend with websockets
This commit is contained in:
@@ -61,14 +61,18 @@ exports.store = async (req, res) => {
|
||||
exports.show = async (req, res) => {
|
||||
const { contactId } = req.params;
|
||||
|
||||
const { id, name, number, extraInfo } = await Contact.findByPk(contactId, {
|
||||
include: [{ model: ContactCustomField, as: "extraInfo" }],
|
||||
});
|
||||
const { id, name, number, email, extraInfo } = await Contact.findByPk(
|
||||
contactId,
|
||||
{
|
||||
include: [{ model: ContactCustomField, as: "extraInfo" }],
|
||||
}
|
||||
);
|
||||
|
||||
res.status(200).json({
|
||||
id,
|
||||
name,
|
||||
number,
|
||||
email,
|
||||
extraInfo,
|
||||
});
|
||||
};
|
||||
@@ -93,3 +97,23 @@ exports.update = async (req, res) => {
|
||||
|
||||
res.status(200).json(contact);
|
||||
};
|
||||
|
||||
exports.delete = async (req, res) => {
|
||||
const io = getIO();
|
||||
const { contactId } = req.params;
|
||||
|
||||
const contact = await Contact.findByPk(contactId);
|
||||
|
||||
if (!contact) {
|
||||
return res.status(400).json({ error: "No contact found with this ID" });
|
||||
}
|
||||
|
||||
await contact.destroy();
|
||||
|
||||
io.emit("contact", {
|
||||
action: "delete",
|
||||
contactId: contactId,
|
||||
});
|
||||
|
||||
res.status(200).json({ message: "Contact deleted" });
|
||||
};
|
||||
|
||||
@@ -13,4 +13,6 @@ routes.post("/contacts", isAuth, ContactController.store);
|
||||
|
||||
routes.put("/contacts/:contactId", isAuth, ContactController.update);
|
||||
|
||||
routes.delete("/contacts/:contactId", isAuth, ContactController.delete);
|
||||
|
||||
module.exports = routes;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"react-modal-image": "^2.5.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "3.4.1",
|
||||
"shortid": "^2.2.15",
|
||||
"socket.io-client": "^2.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
|
||||
const ConfirmationModal = ({ title, children, open, setOpen, onConfirm }) => {
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
aria-labelledby="confirm-dialog"
|
||||
>
|
||||
<DialogTitle id="confirm-dialog">{title}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography>{children}</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => setOpen(false)}
|
||||
color="secondary"
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
onConfirm();
|
||||
}}
|
||||
color="default"
|
||||
>
|
||||
Confirmar
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmationModal;
|
||||
@@ -1,37 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { Navbar, Nav, Container } from "react-bootstrap";
|
||||
import { LinkContainer } from "react-router-bootstrap";
|
||||
|
||||
const LogedinNavbar = () => {
|
||||
return (
|
||||
<div>
|
||||
<Navbar variant="dark" bg="dark" expand="lg">
|
||||
<Container>
|
||||
<LinkContainer to="/" style={{ color: "#519032" }}>
|
||||
<Navbar.Brand>EconoWhatsBot</Navbar.Brand>
|
||||
</LinkContainer>
|
||||
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
|
||||
<Navbar.Collapse id="responsive-navbar-nav">
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/">
|
||||
<Nav.Link href="#home">Home</Nav.Link>
|
||||
</LinkContainer>
|
||||
<LinkContainer to="/chat">
|
||||
<Nav.Link href="#link">Chat</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<LinkContainer to="/login">
|
||||
<Nav.Link href="#login">Login</Nav.Link>
|
||||
</LinkContainer>
|
||||
<LinkContainer to="/signup">
|
||||
<Nav.Link href="#signup">Signup</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Navbar.Collapse>
|
||||
</Container>
|
||||
</Navbar>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogedinNavbar;
|
||||
@@ -1,52 +0,0 @@
|
||||
import React from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { Navbar, Nav, Container } from "react-bootstrap";
|
||||
import { LinkContainer } from "react-router-bootstrap";
|
||||
import "./Navbar.css";
|
||||
|
||||
const DefaultNavbar = () => {
|
||||
const username = localStorage.getItem("username");
|
||||
const history = useHistory();
|
||||
|
||||
const handleLogout = e => {
|
||||
e.preventDefault();
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("userName");
|
||||
localStorage.removeItem("userId");
|
||||
history.push("/");
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Navbar variant="dark" bg="dark" expand="lg">
|
||||
<Container>
|
||||
<LinkContainer to="/" style={{ color: "#519032" }}>
|
||||
<Navbar.Brand>EconoWhatsBot</Navbar.Brand>
|
||||
</LinkContainer>
|
||||
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
|
||||
<Navbar.Collapse id="responsive-navbar-nav">
|
||||
<Nav className="mr-auto">
|
||||
<LinkContainer to="/">
|
||||
<Nav.Link href="#home">Home</Nav.Link>
|
||||
</LinkContainer>
|
||||
<LinkContainer to="/chat">
|
||||
<Nav.Link href="#link">Chat</Nav.Link>
|
||||
</LinkContainer>
|
||||
<LinkContainer to="/chat2">
|
||||
<Nav.Link href="#link">Chat MaterialUi</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Navbar.Text>
|
||||
Logado como: <a href="#login">{username}</a>
|
||||
</Navbar.Text>
|
||||
<Nav.Link href="#logout" onClick={handleLogout}>
|
||||
Logout
|
||||
</Nav.Link>
|
||||
</Navbar.Collapse>
|
||||
</Container>
|
||||
</Navbar>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DefaultNavbar;
|
||||
@@ -12,6 +12,8 @@ import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import { green } from "@material-ui/core/colors";
|
||||
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
@@ -34,6 +36,20 @@ const useStyles = makeStyles(theme => ({
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
|
||||
btnWrapper: {
|
||||
// margin: theme.spacing(1),
|
||||
position: "relative",
|
||||
},
|
||||
|
||||
buttonProgress: {
|
||||
color: green[500],
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
marginTop: -12,
|
||||
marginLeft: -12,
|
||||
},
|
||||
}));
|
||||
|
||||
const ContactModal = ({
|
||||
@@ -82,17 +98,12 @@ const ContactModal = ({
|
||||
handleClose();
|
||||
};
|
||||
|
||||
console.log(contact);
|
||||
console.log("id", contactId);
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Dialog
|
||||
open={modalOpen}
|
||||
onClose={handleClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
maxWidth="lg"
|
||||
// maxHeight="xs"
|
||||
scroll="paper"
|
||||
className={classes.modal}
|
||||
>
|
||||
@@ -117,7 +128,7 @@ const ContactModal = ({
|
||||
}) => (
|
||||
<>
|
||||
<DialogTitle id="form-dialog-title">
|
||||
Adicionar contato
|
||||
{contactId ? "Editar contato" : "Adicionar contato"}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
@@ -215,11 +226,28 @@ const ContactModal = ({
|
||||
</FieldArray>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose} color="secondary">
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
color="secondary"
|
||||
disabled={isSubmitting}
|
||||
variant="outlined"
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} color="primary">
|
||||
Adicionar
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
color="primary"
|
||||
disabled={isSubmitting}
|
||||
variant="contained"
|
||||
className={classes.btnWrapper}
|
||||
>
|
||||
{contactId ? "Salvar" : "Adicionar"}
|
||||
{isSubmitting && (
|
||||
<CircularProgress
|
||||
size={24}
|
||||
className={classes.buttonProgress}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
|
||||
@@ -25,6 +25,9 @@ import EditIcon from "@material-ui/icons/Edit";
|
||||
import PaginationActions from "./PaginationActions";
|
||||
import api from "../../util/api";
|
||||
import ContactModal from "./ContactModal";
|
||||
import ContactsSekeleton from "./ContactsSekeleton";
|
||||
|
||||
import ConfirmationModal from "../../components/ConfirmationModal/ConfirmationModal";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
mainContainer: {
|
||||
@@ -68,7 +71,7 @@ const Contacts = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
const token = localStorage.getItem("token");
|
||||
const userId = localStorage.getItem("userId");
|
||||
// const userId = localStorage.getItem("userId");
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [page, setPage] = useState(0);
|
||||
@@ -80,6 +83,9 @@ const Contacts = () => {
|
||||
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
const [deletingContact, setDeletingContact] = useState(null);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
@@ -108,6 +114,10 @@ const Contacts = () => {
|
||||
if (data.action === "update" || data.action === "create") {
|
||||
updateContacts(data.contact);
|
||||
}
|
||||
|
||||
if (data.action === "delete") {
|
||||
deleteContact(data.contactId);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
@@ -128,6 +138,18 @@ const Contacts = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const deleteContact = contactId => {
|
||||
setContacts(prevState => {
|
||||
const contactIndex = prevState.findIndex(c => c.id === +contactId);
|
||||
|
||||
if (contactIndex === -1) return prevState;
|
||||
|
||||
const aux = [...prevState];
|
||||
aux.splice(contactIndex, 1);
|
||||
return aux;
|
||||
});
|
||||
};
|
||||
|
||||
const handleChangePage = (event, newPage) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
@@ -156,6 +178,11 @@ const Contacts = () => {
|
||||
setModalOpen(true);
|
||||
};
|
||||
|
||||
const handleDeleteContact = async contactId => {
|
||||
await api.delete(`/contacts/${contactId}`);
|
||||
setDeletingContact(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container className={classes.mainContainer}>
|
||||
<ContactModal
|
||||
@@ -165,6 +192,15 @@ const Contacts = () => {
|
||||
aria-labelledby="form-dialog-title"
|
||||
contactId={selectedContactId}
|
||||
></ContactModal>
|
||||
<ConfirmationModal
|
||||
title={deletingContact && `Deletar ${deletingContact.name}`}
|
||||
open={confirmOpen}
|
||||
setOpen={setConfirmOpen}
|
||||
onConfirm={e => handleDeleteContact(deletingContact.id)}
|
||||
>
|
||||
Tem certeza que deseja deletar este contato? Todos os tickets
|
||||
relacionados serão perdidos.
|
||||
</ConfirmationModal>
|
||||
<div className={classes.contactsHeader}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Contatos
|
||||
@@ -204,27 +240,40 @@ const Contacts = () => {
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{contacts.map(contact => (
|
||||
<TableRow key={contact.id}>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
{<Avatar src={contact.profilePicUrl} />}
|
||||
</TableCell>
|
||||
<TableCell>{contact.name}</TableCell>
|
||||
<TableCell>{contact.number}</TableCell>
|
||||
<TableCell>{contact.updatedAt}</TableCell>
|
||||
<TableCell align="right">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => hadleEditContact(contact.id)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
<IconButton size="small">
|
||||
<DeleteOutlineIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{loading ? (
|
||||
<ContactsSekeleton />
|
||||
) : (
|
||||
<>
|
||||
{contacts.map(contact => (
|
||||
<TableRow key={contact.id}>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
{<Avatar src={contact.profilePicUrl} />}
|
||||
</TableCell>
|
||||
<TableCell>{contact.name}</TableCell>
|
||||
<TableCell>{contact.number}</TableCell>
|
||||
<TableCell>{contact.email}</TableCell>
|
||||
<TableCell align="right">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => hadleEditContact(contact.id)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={e => {
|
||||
setConfirmOpen(true);
|
||||
setDeletingContact(contact);
|
||||
}}
|
||||
>
|
||||
<DeleteOutlineIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
|
||||
163
frontend/src/pages/Contacts/ContactsSekeleton.js
Normal file
163
frontend/src/pages/Contacts/ContactsSekeleton.js
Normal file
@@ -0,0 +1,163 @@
|
||||
import React from "react";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Skeleton from "@material-ui/lab/Skeleton";
|
||||
|
||||
const ContactsSekeleton = () => {
|
||||
return (
|
||||
<>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={80} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={70} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={90} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={55} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={60} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={100} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={80} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={70} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={90} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={55} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={60} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={100} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={80} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={70} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={90} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={55} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={60} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={100} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={80} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={70} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={90} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={55} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={60} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={100} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={80} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={70} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={90} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingRight: 0 }}>
|
||||
<Skeleton animation="wave" variant="circle" width={40} height={40} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={55} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={60} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton animation="wave" height={20} width={100} />
|
||||
</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactsSekeleton;
|
||||
@@ -7372,11 +7372,6 @@ nan@^2.12.1:
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
|
||||
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
|
||||
|
||||
nanoid@^2.1.0:
|
||||
version "2.1.11"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
||||
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||
@@ -9954,13 +9949,6 @@ shellwords@^0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
||||
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
|
||||
|
||||
shortid@^2.2.15:
|
||||
version "2.2.15"
|
||||
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
|
||||
integrity sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==
|
||||
dependencies:
|
||||
nanoid "^2.1.0"
|
||||
|
||||
side-channel@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"
|
||||
|
||||
Reference in New Issue
Block a user