From 4cf3b61da793b85b4017049ebf1422dc04a55cc7 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 5 May 2021 14:28:56 +0800 Subject: [PATCH] feat(projects): edit page header and delete button. --- package-lock.json | 45 ++++++++++++++++++ package.json | 2 + src/index.tsx | 20 +++++--- src/pipelines/pipeline-list.tsx | 8 +++- src/projects/project-detail.tsx | 2 +- src/projects/project-editor.tsx | 84 ++++++++++++++++++++++++++++++--- 6 files changed, 145 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index d7623c5..f5cb3bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,8 @@ "formik-material-ui": "^3.0.1", "formik-material-ui-pickers": "^0.0.12", "graphql": "^15.5.0", + "material-ui-confirm": "^2.1.2", + "notistack": "^1.0.6", "ramda": "^0.27.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -15099,6 +15101,16 @@ "node": ">=0.10.0" } }, + "node_modules/material-ui-confirm": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/material-ui-confirm/-/material-ui-confirm-2.1.2.tgz", + "integrity": "sha512-GdM1vFQfkj2kpeW2hLmTxznPmIjWVqWoYzV7Vhjh92UqItOFxLbV15lyakuWdHOn92Bx4y9rQuGHIDP6PENpmQ==", + "peerDependencies": { + "@material-ui/core": ">= 3.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -15823,6 +15835,24 @@ "node": ">=8" } }, + "node_modules/notistack": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.6.tgz", + "integrity": "sha512-/p7W9b3r3/LDXUpUjNgZqnYj+NYG3/4htZcyucOFftrDKEpveEMPFdPlvmoT9+N1L4GgcKEY9Vr9+Dxyk2FQcQ==", + "dependencies": { + "clsx": "^1.1.0", + "hoist-non-react-statics": "^3.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/notistack" + }, + "peerDependencies": { + "@material-ui/core": "^4.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -37163,6 +37193,12 @@ "object-visit": "^1.0.0" } }, + "material-ui-confirm": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/material-ui-confirm/-/material-ui-confirm-2.1.2.tgz", + "integrity": "sha512-GdM1vFQfkj2kpeW2hLmTxznPmIjWVqWoYzV7Vhjh92UqItOFxLbV15lyakuWdHOn92Bx4y9rQuGHIDP6PENpmQ==", + "requires": {} + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -37755,6 +37791,15 @@ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", "dev": true }, + "notistack": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.6.tgz", + "integrity": "sha512-/p7W9b3r3/LDXUpUjNgZqnYj+NYG3/4htZcyucOFftrDKEpveEMPFdPlvmoT9+N1L4GgcKEY9Vr9+Dxyk2FQcQ==", + "requires": { + "clsx": "^1.1.0", + "hoist-non-react-statics": "^3.3.0" + } + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", diff --git a/package.json b/package.json index 886cffb..4c48380 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "formik-material-ui": "^3.0.1", "formik-material-ui-pickers": "^0.0.12", "graphql": "^15.5.0", + "material-ui-confirm": "^2.1.2", + "notistack": "^1.0.6", "ramda": "^0.27.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/src/index.tsx b/src/index.tsx index c83e9a2..5c23069 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -13,6 +13,8 @@ import { createRouterComponent } from "@curi/react-dom"; import { createRouter, announce } from "@curi/router"; import { browser } from "@hickory/browser"; import routes from "./routes"; +import { ConfirmProvider } from 'material-ui-confirm'; +import { SnackbarProvider } from 'notistack'; const router = createRouter(browser, routes, { sideEffects: [ @@ -27,13 +29,17 @@ const Router = createRouterComponent(router); router.once(() => { ReactDOM.render( - - - - - - - + + + + + + + + + + + , document.getElementById("root") ); diff --git a/src/pipelines/pipeline-list.tsx b/src/pipelines/pipeline-list.tsx index 4aa55bc..c8c51eb 100644 --- a/src/pipelines/pipeline-list.tsx +++ b/src/pipelines/pipeline-list.tsx @@ -27,8 +27,12 @@ export const PipelineList: FC = ({ projectId }) => { return ( {data?.pipelines.map((pipeline) => ( - - + + ))} diff --git a/src/projects/project-detail.tsx b/src/projects/project-detail.tsx index 90a16f4..81e1dfa 100644 --- a/src/projects/project-detail.tsx +++ b/src/projects/project-detail.tsx @@ -48,7 +48,7 @@ export const ProjectDetail: FC = ({ project }) => { - {} + {} diff --git a/src/projects/project-editor.tsx b/src/projects/project-editor.tsx index 199519f..34f61b7 100644 --- a/src/projects/project-editor.tsx +++ b/src/projects/project-editor.tsx @@ -1,14 +1,25 @@ -import { gql, useMutation } from "@apollo/client"; -import { Button, LinearProgress, makeStyles, Paper } from "@material-ui/core"; +import { gql, Reference, useMutation } from "@apollo/client"; +import { + Button, + LinearProgress, + makeStyles, + Paper, + Portal, + Typography, + Grid, + IconButton, +} from "@material-ui/core"; import { Form, Formik, Field, FormikHelpers } from "formik"; import { TextField } from "formik-material-ui"; import { not } from "ramda"; import { FC } from "react"; -import { - Project, -} from "../generated/graphql"; +import { Project } from "../generated/graphql"; import * as Yup from "yup"; import { useRouter } from "@curi/react-dom"; +import { useHeaderContainer } from "../layouts"; +import DeleteIcon from "@material-ui/icons/Delete"; +import { useConfirm } from "material-ui-confirm"; +import { useSnackbar } from "notistack"; type Values = Partial; @@ -51,6 +62,12 @@ const UPDATE_PROJECT = gql` } `; +const REMOVE_PROJECT = gql` + mutation RemoveProject($id: String!) { + removeProject(id: $id) + } +`; + export const ProjectEditor: FC = ({ project }) => { const isCreate = not("id" in project); @@ -60,7 +77,7 @@ export const ProjectEditor: FC = ({ project }) => { update(cache, { data }) { cache.modify({ fields: { - findProjects(exitingProjects = []) { + projects(exitingProjects = []) { const newProjectRef = cache.writeFragment({ data: data!.createProject, fragment: gql` @@ -84,6 +101,9 @@ export const ProjectEditor: FC = ({ project }) => { const [updateProject] = useMutation(UPDATE_PROJECT); const router = useRouter(); + + const { enqueueSnackbar } = useSnackbar(); + const submitForm = async ( values: Values, formikHelpers: FormikHelpers @@ -104,6 +124,9 @@ export const ProjectEditor: FC = ({ project }) => { }, }); } + enqueueSnackbar("Saved successfully", { + variant: "success", + }); router.navigate({ url: router.url({ name: "project-detail", @@ -118,9 +141,58 @@ export const ProjectEditor: FC = ({ project }) => { } }; + const [removeProject, { loading: deleting }] = useMutation(REMOVE_PROJECT, { + variables: { id: project.id }, + update(cache) { + cache.modify({ + fields: { + projects(exitingProjects: Reference[] = [], { readField }) { + return exitingProjects.filter( + (ref) => project.id !== readField("id", ref) + ); + }, + }, + }); + }, + }); + + const confirm = useConfirm(); + const handleDelete = async () => { + try { + await confirm({ description: `This will delete ${project.name}.` }); + await removeProject(); + enqueueSnackbar("Deleted successfully", { + variant: "success", + }); + router.navigate({ + url: router.url({ + name: "dashboard", + }), + }); + } catch {} + }; + + const headerContainer = useHeaderContainer(); + const classes = useStyles(); return ( + + + + {isCreate ? "Create" : "Edit"} Project + + {isCreate ? null : ( + + + + )} + +