From 11f70282d745bec93f1da658cc815cbb0b4d6802 Mon Sep 17 00:00:00 2001 From: David Stotijn Date: Wed, 23 Feb 2022 15:20:23 +0100 Subject: [PATCH] Tidy up `admin` structure --- .gitignore | 2 +- admin/.eslintrc.json | 53 +- admin/gqlcodegen.yml | 2 +- admin/package.json | 3 +- admin/public/android-chrome-192x192.png | Bin 0 -> 5678 bytes admin/public/android-chrome-512x512.png | Bin 0 -> 12322 bytes admin/public/apple-touch-icon.png | Bin 0 -> 5095 bytes admin/public/favicon-16x16.png | Bin 0 -> 454 bytes admin/public/favicon-32x32.png | Bin 0 -> 840 bytes admin/public/favicon.ico | Bin 15086 -> 15406 bytes admin/public/site.webmanifest | 1 + admin/src/components/projects/NewProject.tsx | 117 --- .../reqlog/hooks/useClearHTTPRequestLog.ts | 16 - .../reqlog/hooks/useCreateSenderRequest.ts | 13 - .../reqlog/hooks/useHttpRequestLogs.ts | 22 - admin/src/{components => features}/Layout.tsx | 22 +- .../projects/components/NewProject.tsx | 67 ++ .../projects/components}/ProjectList.tsx | 148 +-- .../projects/graphql/closeProject.graphql | 5 + .../projects/graphql/createProject.graphql | 6 + .../projects/graphql/deleteProject.graphql | 5 + .../projects/graphql/openProject.graphql | 7 + .../projects/graphql/projects.graphql | 7 + .../projects/hooks/useOpenProjectMutation.ts | 47 + .../reqlog/components}/ConfirmationDialog.tsx | 2 +- .../reqlog/components}/HttpHeadersTable.tsx | 8 +- .../reqlog/components}/LogDetail.tsx | 47 +- .../reqlog/components}/LogsOverview.tsx | 25 +- .../reqlog/components}/RequestDetail.tsx | 14 +- .../reqlog/components}/RequestList.tsx | 23 +- .../reqlog/components}/ResponseDetail.tsx | 17 +- .../reqlog/components}/Search.tsx | 76 +- .../graphql/clearHttpRequestLog.graphql | 5 + .../reqlog/graphql/httpRequestLog.graphql | 23 + .../graphql/httpRequestLogFilter.graphql | 6 + .../reqlog/graphql/httpRequestLogs.graphql | 12 + .../graphql/setHttpRequestLogFilter.graphql | 6 + .../scope/components}/AddRule.tsx | 37 +- .../scope/components}/RuleListItem.tsx | 26 +- .../scope/components}/Rules.tsx | 17 +- .../src/features/scope/graphql/scope.graphql | 5 + .../features/scope/graphql/setScope.graphql | 5 + .../sender/components}/EditRequest.tsx | 31 +- .../sender/components}/EditRequestTabs.tsx | 11 +- .../sender/components}/History.tsx | 11 +- .../sender/components}/KeyValuePair.tsx | 10 +- .../sender/components}/Response.tsx | 9 +- .../sender/components}/ResponseTabs.tsx | 15 +- .../graphql}/createOrUpdateRequest.graphql | 0 .../createSenderRequestFromRequestLog.graphql | 0 .../sender/graphql}/sendRequest.graphql | 0 .../sender/graphql}/senderRequest.graphql | 0 .../sender/graphql}/senderRequests.graphql | 0 admin/src/generated/graphql.tsx | 479 --------- admin/src/lib/Project.ts | 5 - .../components}/CenteredPaper.tsx | 0 .../common => lib/components}/Editor.tsx | 0 .../components}/HttpStatusIcon.tsx | 2 +- .../components}/ResponseStatus.tsx | 7 +- .../components}/useContextMenu.tsx | 14 +- admin/src/lib/graphql.ts | 61 -- admin/src/lib/graphql/generated.tsx | 983 ++++++++++++++++++ admin/src/lib/graphql/omitTypename.ts | 7 + admin/src/lib/graphql/useApollo.ts | 24 + admin/src/lib/{ => mui}/createEmotionCache.ts | 0 admin/src/lib/{ => mui}/theme.ts | 2 +- admin/src/lib/omitTypename.ts | 5 - admin/src/lib/requestLogs.ts | 24 - admin/src/lib/scope.ts | 3 - admin/src/pages/_app.tsx | 19 +- admin/src/pages/_document.tsx | 9 +- admin/src/pages/get-started/index.tsx | 32 - admin/src/pages/index.tsx | 4 +- admin/src/pages/projects/index.tsx | 7 +- admin/src/pages/proxy/index.tsx | 6 +- admin/src/pages/proxy/logs/index.tsx | 6 +- admin/src/pages/scope/index.tsx | 6 +- admin/src/pages/sender/index.tsx | 6 +- admin/tsconfig.json | 20 +- admin/yarn.lock | 16 +- 80 files changed, 1525 insertions(+), 1206 deletions(-) create mode 100644 admin/public/android-chrome-192x192.png create mode 100644 admin/public/android-chrome-512x512.png create mode 100644 admin/public/apple-touch-icon.png create mode 100644 admin/public/favicon-16x16.png create mode 100644 admin/public/favicon-32x32.png create mode 100644 admin/public/site.webmanifest delete mode 100644 admin/src/components/projects/NewProject.tsx delete mode 100644 admin/src/components/reqlog/hooks/useClearHTTPRequestLog.ts delete mode 100644 admin/src/components/reqlog/hooks/useCreateSenderRequest.ts delete mode 100644 admin/src/components/reqlog/hooks/useHttpRequestLogs.ts rename admin/src/{components => features}/Layout.tsx (98%) create mode 100644 admin/src/features/projects/components/NewProject.tsx rename admin/src/{components/projects => features/projects/components}/ProjectList.tsx (63%) create mode 100644 admin/src/features/projects/graphql/closeProject.graphql create mode 100644 admin/src/features/projects/graphql/createProject.graphql create mode 100644 admin/src/features/projects/graphql/deleteProject.graphql create mode 100644 admin/src/features/projects/graphql/openProject.graphql create mode 100644 admin/src/features/projects/graphql/projects.graphql create mode 100644 admin/src/features/projects/hooks/useOpenProjectMutation.ts rename admin/src/{components/reqlog => features/reqlog/components}/ConfirmationDialog.tsx (100%) rename admin/src/{components/reqlog => features/reqlog/components}/HttpHeadersTable.tsx (94%) rename admin/src/{components/reqlog => features/reqlog/components}/LogDetail.tsx (56%) rename admin/src/{components/reqlog => features/reqlog/components}/LogsOverview.tsx (76%) rename admin/src/{components/reqlog => features/reqlog/components}/RequestDetail.tsx (87%) rename admin/src/{components/reqlog => features/reqlog/components}/RequestList.tsx (88%) rename admin/src/{components/reqlog => features/reqlog/components}/ResponseDetail.tsx (79%) rename admin/src/{components/reqlog => features/reqlog/components}/Search.tsx (76%) create mode 100644 admin/src/features/reqlog/graphql/clearHttpRequestLog.graphql create mode 100644 admin/src/features/reqlog/graphql/httpRequestLog.graphql create mode 100644 admin/src/features/reqlog/graphql/httpRequestLogFilter.graphql create mode 100644 admin/src/features/reqlog/graphql/httpRequestLogs.graphql create mode 100644 admin/src/features/reqlog/graphql/setHttpRequestLogFilter.graphql rename admin/src/{components/scope => features/scope/components}/AddRule.tsx (78%) rename admin/src/{components/scope => features/scope/components}/RuleListItem.tsx (81%) rename admin/src/{components/scope => features/scope/components}/Rules.tsx (73%) create mode 100644 admin/src/features/scope/graphql/scope.graphql create mode 100644 admin/src/features/scope/graphql/setScope.graphql rename admin/src/{components/sender => features/sender/components}/EditRequest.tsx (97%) rename admin/src/{components/sender => features/sender/components}/EditRequestTabs.tsx (93%) rename admin/src/{components/sender => features/sender/components}/History.tsx (91%) rename admin/src/{components/sender => features/sender/components}/KeyValuePair.tsx (97%) rename admin/src/{components/sender => features/sender/components}/Response.tsx (87%) rename admin/src/{components/sender => features/sender/components}/ResponseTabs.tsx (87%) rename admin/src/{components/sender => features/sender/graphql}/createOrUpdateRequest.graphql (100%) rename admin/src/{components/sender => features/sender/graphql}/createSenderRequestFromRequestLog.graphql (100%) rename admin/src/{components/sender => features/sender/graphql}/sendRequest.graphql (100%) rename admin/src/{components/sender => features/sender/graphql}/senderRequest.graphql (100%) rename admin/src/{components/sender => features/sender/graphql}/senderRequests.graphql (100%) delete mode 100644 admin/src/generated/graphql.tsx delete mode 100644 admin/src/lib/Project.ts rename admin/src/{components/common => lib/components}/CenteredPaper.tsx (100%) rename admin/src/{components/common => lib/components}/Editor.tsx (100%) rename admin/src/{components/common => lib/components}/HttpStatusIcon.tsx (100%) rename admin/src/{components/common => lib/components}/ResponseStatus.tsx (82%) rename admin/src/{components/common => lib/components}/useContextMenu.tsx (80%) delete mode 100644 admin/src/lib/graphql.ts create mode 100644 admin/src/lib/graphql/generated.tsx create mode 100644 admin/src/lib/graphql/omitTypename.ts create mode 100644 admin/src/lib/graphql/useApollo.ts rename admin/src/lib/{ => mui}/createEmotionCache.ts (100%) rename admin/src/lib/{ => mui}/theme.ts (100%) delete mode 100644 admin/src/lib/omitTypename.ts delete mode 100644 admin/src/lib/requestLogs.ts delete mode 100644 admin/src/lib/scope.ts delete mode 100644 admin/src/pages/get-started/index.tsx diff --git a/.gitignore b/.gitignore index e1d1e52..9744485 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/.vscode +*.vscode /dist /hetty /cmd/hetty/admin diff --git a/admin/.eslintrc.json b/admin/.eslintrc.json index e2acf76..a901afe 100644 --- a/admin/.eslintrc.json +++ b/admin/.eslintrc.json @@ -1,18 +1,51 @@ { - "extends": ["next/core-web-vitals", "prettier"], + "root": true, + "extends": ["next/core-web-vitals", "prettier", "plugin:@typescript-eslint/recommended", "plugin:import/typescript"], + "plugins": ["prettier", "@typescript-eslint", "import"], + "ignorePatterns": ["next*", "src/lib/graphql/generated.tsx"], + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx"] + }, + "import/resolver": { + "typescript": { + "alwaysTryTypes": true + } + } + }, "rules": { + "prettier/prettier": ["error"], "@next/next/no-css-tags": "off", - "@typescript-eslint/no-unused-vars": "off", - "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": [ + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error", + + "import/default": "off", + + "import/no-unresolved": "error", + "import/named": "error", + "import/namespace": "error", + "import/export": "error", + "import/no-deprecated": "error", + "import/no-cycle": "error", + + "import/no-named-as-default": "warn", + "import/no-named-as-default-member": "warn", + "import/no-duplicates": "warn", + "import/newline-after-import": "warn", + "import/order": [ "warn", { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_" + "alphabetize": { "order": "asc", "caseInsensitive": false }, + "newlines-between": "always", + "groups": ["builtin", "external", "parent", "sibling", "index"] + } + ], + "import/no-unused-modules": [ + "error", + { + "missingExports": true, + "ignoreExports": ["./src/pages"] } ] - }, - "plugins": ["unused-imports", "prettier"] + } } diff --git a/admin/gqlcodegen.yml b/admin/gqlcodegen.yml index dbba8a0..5a9f02d 100644 --- a/admin/gqlcodegen.yml +++ b/admin/gqlcodegen.yml @@ -2,7 +2,7 @@ overwrite: true schema: "../pkg/api/schema.graphql" documents: "src/**/*.graphql" generates: - src/generated/graphql.tsx: + src/lib/graphql/generated.tsx: plugins: - "typescript" - "typescript-operations" diff --git a/admin/package.json b/admin/package.json index 4c95497..59c313d 100644 --- a/admin/package.json +++ b/admin/package.json @@ -44,8 +44,9 @@ "eslint": "^8.7.0", "eslint-config-next": "12.0.8", "eslint-config-prettier": "^8.3.0", + "eslint-import-resolver-typescript": "^2.5.0", + "eslint-plugin-import": "^2.25.4", "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-unused-imports": "^2.0.0", "prettier": "^2.1.2", "typescript": "^4.0.3", "webpack": "^5.67.0" diff --git a/admin/public/android-chrome-192x192.png b/admin/public/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..5bc3e6d43d07de634d6a81133c93daf7d650ee3d GIT binary patch literal 5678 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 vW~AmI3$o`wG(MdrUt literal 0 HcmV?d00001 diff --git a/admin/public/android-chrome-512x512.png b/admin/public/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..9ecc4038fe4f340dc84b2857752e2c40a65a14a2 GIT binary patch literal 12322 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 literal 0 HcmV?d00001 diff --git a/admin/public/favicon-32x32.png b/admin/public/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..54d253805a26a40b6a6858942afe33b30807c4fc GIT binary patch literal 840 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZv>fz_iKJ#W5s; z^KE!^wy>kfKeOp(nZ-Akbm=;2t<&T1M`XWrktU(T|v z%KXY!ok#rh{?BG%YTj#7P*uftb0=%w!~{-nn^{e}Hl0e`rI2#KE#vcd+170T%|{Qe znUIyOFh6s7*5`L~Z%aMMwe~P9j@@8!NQvj}E~ln4htuK$Z+AAlnJ$0k-luQ#Em(G+ zXV%@#_w*i1J3HGh#@)O-<4=3|?t5yW#vwUj&e1(8o=qvjvkdB4*!wS6KKiIFGD*As z%deJ;>w9dNxwP619ZwwCp6&d>c8*ioH*2FOn&vXmDHXe;G-ZrM=ii&OZm)IMjFq~* zA6qy@CS`h?O3%GvbKySg$wc=$%f675Su0=8ep{EDCN}d$IG-_B{qyS?nlsqXi>{8B z?7UEws8$u!Soi7gNsaKDGhs6t&IYsZZFu$VeOlSH?e`SlO^Xf5Ussp!t}PRtI%`Ui zdD2Hyt(N%*S>AW?Q0KQek!y^v|DHK+xn|$*lpfAwK3RWEKXr4p&tz3(j#`;y z>f5|*(&Mu>9_cLXRV%^_MQ7X%=l_55ut+zry=iq+iXwBB_>uSh%D*e;&0+j3rk;PB z(L!39A=LE^U#8*V3I5xi?dNcL^0R>96n^P56ceEN)gRWHroPyD^} z$jz7P^Xrt4xvMWoyJqR5GNF3SuXqKew8tff^lt2UdOGI#RhEC+Y<0}P>MrU$%$;fq OO2wY8elF{r5}E+tVqFmc literal 0 HcmV?d00001 diff --git a/admin/public/favicon.ico b/admin/public/favicon.ico index 4965832f2c9b0605eaa189b7c7fb11124d24e48a..51fec0cb0016a38f71a833f1c194809fa65bd53f 100644 GIT binary patch literal 15406 zcmeHN33C)h6rSv6LlQR0F3Bd@&9!04W<$vCQph0@8YCPnSQVP9rOBi&wEc% zaulcH@hGefD)Vy{WsssM!Jzsc@hZwb))$XogohR7yiZXg42KP2Bh-G@*j>Z`H~j5z zC{$6Cr|BUaE2M*;HIpkZhxcvl4AIzWr5fC7qSiY+{Qd4( zWwiNNg9bB?cQ_UD2YVRcGoGlVReS4sALc#rTZ}4eFY&0K!|BYSs(Ryi;9^X1FO{cN zuh!Gd#gzscVh$_*0o#1EfhI8C@!UGzLy(CXV!|BIUwL&RZ{wzyQpc$<$A>Q8`mTlg z4(ypQUhrXVdloyX`$Cjz`sDL5kFT$$g`28V9*_A#%?0H3x%e1QSuXWyDNJj;nWz8R zI}<1K3w|cZ?h)*Uf4a;ibuRs^v;k=YDcit9E34?x=griZbm7G9sQw&^70*);{~o=+rBf% z=Q#C8EMf1)80@Kszi8$-Qy-}?(BS*xuQ3k0b%J`vu%lzwzv7j8KK}HdajFif`>PqZ zt=-RYc6}Hz&<7sA0ra!>K<@;Yc^<3xLbroPPV!Pi)P6s%Ys}{~K*zjq4;od>VbGt~ zcj??^Me9oXwx4a}bRJ$~v^8gL4t0LjkHaR-^<|`kRQS4Qj*rvm{H7m)rhW|UAG&$z z-9|&d9>?w(HZ*#&mm1^t`o~zDnV@6P8GKu@fljDj0q+Ma7_qh?JNhg4B)2~?cJ2P& zoDSBE=o9VE_ahuOXGI_ZCUC4;VZV?qU^+XS@rSYVJ!I@=YtGH|riV|NU(R8NzicL) zf5!NvH8*pn;(z(RAblZiS zYB-H8#}of!)*TLU*wXEFS)<=P(9LO_{X0(nI^(|%{0QXl`Xx&6E9uIX5|pq z)4Bgi<9`&sRDur@z{;aW+8{)3O$Gz<3Adkx@;ISOQV=Olf8G-j=cLRCL zjX4AJm~`KvyEnhR#0%&kzn*NKw&ekh{{x@)rD_|Q5kETiqZ-3P&OJ8NopkPGwDoY* zSD=1C=(77ljA|N^$378b7O}N1#+RMUh=cAw*H@c=@s`@F%0Fa*?vMw-w@wx}7qX-N zVgvI-LhdCUb%flLfa_b-Hwe6UevVR6$@TX`4pv(-eNm<6UtVK2AYjy2ljoQ`nAm{c1i*Ji>&~Y+MJu=MiCF3a_IC6~JPJ}hS zwswUr{Sf9HGqo45MS=`RnD2_-e0A4xI(+MKQ3ECP3LCM@`=M@W|9N#CV^2dJ6zZGw zb7lHm%lyrw>#Atc^EK2oAoV&V&_muw_#w!Fe25hvSldr+tJP#h?O4gh8Z0aPRQsS8 zk$(VvF16PaTE3c z@O7N+RXAVh;o=$jJnVHs)^u}&Vjg|#^Sk&NOw0*e2$*X2^!QfKs6*S@rTQ26p#>YO zE$av1hn{A+G(qbK+xPSGuY3*QoHc{h06w_XpSJBl9-PT$FY{~u1!vOoD(k%<-s;xQ zLy%+Cz1H8#N>ADBLk%o!VI$d_8;6 zzWxGr3BbYqI?GR^uJu~;Yef$}UGRnTer2uoIUMU)oWD>09;3GY$L;+m`x5 literal 15086 zcmeHOOH5Q(7(R0cc?bh2AT>N@1PWL!LLfZKyG5c!MTHoP7_p!sBz0k$?pjS;^lmgJ zU6^i~bWuZYHL)9$wuvEKm~qo~(5=Lvx5&Hv;?X#m}i|`yaGY4gX+&b>tew;gcnRQA1kp zBbm04SRuuE{Hn+&1wk%&g;?wja_Is#1gKoFlI7f`Gt}X*-nsMO30b_J@)EFNhzd1QM zdH&qFb9PVqQOx@clvc#KAu}^GrN`q5oP(8>m4UOcp`k&xwzkTio*p?kI4BPtIwX%B zJN69cGsm=x90<;Wmh-bs>43F}ro$}Of@8)4KHndLiR$nW?*{Rl72JPUqRr3ta6e#A z%DTEbi9N}+xPtd1juj8;(CJt3r9NOgb>KTuK|z7!JB_KsFW3(pBN4oh&M&}Nb$Ee2 z$-arA6a)CdsPj`M#1DS>fqj#KF%0q?w50GN4YbmMZIoF{e1yTR=4ablqXHBB2!`wM z1M1ke9+<);|AI;f=2^F1;G6Wfpql?1d5D4rMr?#f(=hkoH)U`6Gb)#xDLjoKjp)1;Js@2Iy5yk zMXUqj+gyk1i0yLjWS|3sM2-1ECc;MAz<4t0P53%7se$$+5Ex`L5TQO_MMXXi04UDIU+3*7Ez&X|mj9cFYBXqM{M;mw_ zpw>azP*qjMyNSD4hh)XZt$gqf8f?eRSFX8VQ4Y+H3jAtvyTrXr`qHAD6`m;aYmH2zOhJC~_*AuT} zvUxC38|JYN94i(05R)dVKgUQF$}#cxV7xZ4FULqFCNX*Forhgp*yr6;DsIk=ub0Hv zpk2L{9Q&|uI^b<6@i(Y+iSxeO_n**4nRLc`P!3ld5jL=nZRw6;DEJ*1z6Pvg+eW|$lnnjO zjd|8>6l{i~UxI244CGn2kK@cJ|#ecwgSyt&HKA2)z zrOO{op^o*- {}, - onCompleted(data) { - setName(""); - openProject({ variables: { id: data.createProject.id } }); - }, - }); - const [openProject, { error: openProjErr, loading: openProjLoading }] = useMutation(OPEN_PROJECT, { - onError: () => {}, - update(cache, { data: { openProject } }) { - cache.modify({ - fields: { - activeProject() { - const activeProjRef = cache.writeFragment({ - id: openProject.id, - data: openProject, - fragment: gql` - fragment ActiveProject on Project { - id - name - isActive - type - } - `, - }); - return activeProjRef; - }, - projects(_, { DELETE }) { - cache.writeFragment({ - id: openProject.id, - data: openProject, - fragment: gql` - fragment OpenProject on Project { - id - name - isActive - type - } - `, - }); - return DELETE; - }, - }, - }); - }, - }); - - const handleCreateAndOpenProjectForm = (e: React.SyntheticEvent) => { - e.preventDefault(); - createProject({ variables: { name } }); - }; - - return ( -
- - New project - -
- setName(e.target.value)} - error={Boolean(createProjErr || openProjErr)} - helperText={(createProjErr && createProjErr.message) || (openProjErr && openProjErr.message)} - /> - - -
- ); -} - -export default NewProject; diff --git a/admin/src/components/reqlog/hooks/useClearHTTPRequestLog.ts b/admin/src/components/reqlog/hooks/useClearHTTPRequestLog.ts deleted file mode 100644 index 2870712..0000000 --- a/admin/src/components/reqlog/hooks/useClearHTTPRequestLog.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { gql, useMutation } from "@apollo/client"; -import { HTTP_REQUEST_LOGS } from "./useHttpRequestLogs"; - -const CLEAR_HTTP_REQUEST_LOG = gql` - mutation ClearHTTPRequestLog { - clearHTTPRequestLog { - success - } - } -`; - -export function useClearHTTPRequestLog() { - return useMutation(CLEAR_HTTP_REQUEST_LOG, { - refetchQueries: [{ query: HTTP_REQUEST_LOGS }], - }); -} diff --git a/admin/src/components/reqlog/hooks/useCreateSenderRequest.ts b/admin/src/components/reqlog/hooks/useCreateSenderRequest.ts deleted file mode 100644 index aa81efe..0000000 --- a/admin/src/components/reqlog/hooks/useCreateSenderRequest.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { gql, useMutation } from "@apollo/client"; - -const CREATE_SENDER_REQUEST = gql` - mutation CreateSenderRequest($request: SenderRequestInput!) { - createSenderRequest(request: $request) { - id - } - } -`; - -export default function useCreateSenderRequest() { - return useMutation(CREATE_SENDER_REQUEST); -} diff --git a/admin/src/components/reqlog/hooks/useHttpRequestLogs.ts b/admin/src/components/reqlog/hooks/useHttpRequestLogs.ts deleted file mode 100644 index f426702..0000000 --- a/admin/src/components/reqlog/hooks/useHttpRequestLogs.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { gql, useQuery } from "@apollo/client"; - -export const HTTP_REQUEST_LOGS = gql` - query HttpRequestLogs { - httpRequestLogs { - id - method - url - timestamp - response { - statusCode - statusReason - } - } - } -`; - -export function useHttpRequestLogs() { - return useQuery(HTTP_REQUEST_LOGS, { - pollInterval: 1000, - }); -} diff --git a/admin/src/components/Layout.tsx b/admin/src/features/Layout.tsx similarity index 98% rename from admin/src/components/Layout.tsx rename to admin/src/features/Layout.tsx index 0c6302c..5368793 100644 --- a/admin/src/components/Layout.tsx +++ b/admin/src/features/Layout.tsx @@ -1,4 +1,11 @@ -import React from "react"; +import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; +import FolderIcon from "@mui/icons-material/Folder"; +import HomeIcon from "@mui/icons-material/Home"; +import LocationSearchingIcon from "@mui/icons-material/LocationSearching"; +import MenuIcon from "@mui/icons-material/Menu"; +import SendIcon from "@mui/icons-material/Send"; +import SettingsEthernetIcon from "@mui/icons-material/SettingsEthernet"; import { Theme, useTheme, @@ -18,14 +25,7 @@ import MuiDrawer from "@mui/material/Drawer"; import MuiListItemButton, { ListItemButtonProps } from "@mui/material/ListItemButton"; import MuiListItemIcon, { ListItemIconProps } from "@mui/material/ListItemIcon"; import Link from "next/link"; -import MenuIcon from "@mui/icons-material/Menu"; -import HomeIcon from "@mui/icons-material/Home"; -import SettingsEthernetIcon from "@mui/icons-material/SettingsEthernet"; -import SendIcon from "@mui/icons-material/Send"; -import FolderIcon from "@mui/icons-material/Folder"; -import LocationSearchingIcon from "@mui/icons-material/LocationSearching"; -import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; -import ChevronRightIcon from "@mui/icons-material/ChevronRight"; +import React, { useState } from "react"; export enum Page { Home, @@ -133,7 +133,7 @@ interface Props { export function Layout({ title, page, children }: Props): JSX.Element { const theme = useTheme(); - const [open, setOpen] = React.useState(false); + const [open, setOpen] = useState(false); const handleDrawerOpen = () => { setOpen(true); @@ -247,5 +247,3 @@ export function Layout({ title, page, children }: Props): JSX.Element { ); } - -export default Layout; diff --git a/admin/src/features/projects/components/NewProject.tsx b/admin/src/features/projects/components/NewProject.tsx new file mode 100644 index 0000000..550b04e --- /dev/null +++ b/admin/src/features/projects/components/NewProject.tsx @@ -0,0 +1,67 @@ +import AddIcon from "@mui/icons-material/Add"; +import { Box, Button, CircularProgress, TextField, Typography } from "@mui/material"; +import React, { useState } from "react"; + +import useOpenProjectMutation from "../hooks/useOpenProjectMutation"; + +import { useCreateProjectMutation } from "lib/graphql/generated"; + +function NewProject(): JSX.Element { + const [name, setName] = useState(""); + + const [createProject, createProjResult] = useCreateProjectMutation({ + onCompleted(data) { + setName(""); + if (data?.createProject) { + openProject({ variables: { id: data.createProject?.id } }); + } + }, + }); + const [openProject, openProjResult] = useOpenProjectMutation(); + + const handleCreateAndOpenProjectForm = (e: React.SyntheticEvent) => { + e.preventDefault(); + createProject({ variables: { name } }); + }; + + return ( +
+ + New project + +
+ setName(e.target.value)} + error={Boolean(createProjResult.error || openProjResult.error)} + helperText={ + (createProjResult.error && createProjResult.error.message) || + (openProjResult.error && openProjResult.error.message) + } + /> + + +
+ ); +} + +export default NewProject; diff --git a/admin/src/components/projects/ProjectList.tsx b/admin/src/features/projects/components/ProjectList.tsx similarity index 63% rename from admin/src/components/projects/ProjectList.tsx rename to admin/src/features/projects/components/ProjectList.tsx index e3a6987..3ad2dd0 100644 --- a/admin/src/components/projects/ProjectList.tsx +++ b/admin/src/features/projects/components/ProjectList.tsx @@ -1,4 +1,8 @@ -import { gql, useMutation, useQuery } from "@apollo/client"; +import CloseIcon from "@mui/icons-material/Close"; +import DeleteIcon from "@mui/icons-material/Delete"; +import DescriptionIcon from "@mui/icons-material/Description"; +import LaunchIcon from "@mui/icons-material/Launch"; +import { Alert } from "@mui/lab"; import { Avatar, Box, @@ -21,110 +25,25 @@ import { Typography, useTheme, } from "@mui/material"; -import CloseIcon from "@mui/icons-material/Close"; -import DescriptionIcon from "@mui/icons-material/Description"; -import DeleteIcon from "@mui/icons-material/Delete"; -import LaunchIcon from "@mui/icons-material/Launch"; -import { Alert } from "@mui/lab"; import React, { useState } from "react"; -import { Project } from "../../lib/Project"; +import useOpenProjectMutation from "../hooks/useOpenProjectMutation"; -const PROJECTS = gql` - query Projects { - projects { - id - name - isActive - } - } -`; - -const OPEN_PROJECT = gql` - mutation OpenProject($id: ID!) { - openProject(id: $id) { - id - name - isActive - } - } -`; - -const CLOSE_PROJECT = gql` - mutation CloseProject { - closeProject { - success - } - } -`; - -const DELETE_PROJECT = gql` - mutation DeleteProject($id: ID!) { - deleteProject(id: $id) { - success - } - } -`; +import { + ProjectsQuery, + useCloseProjectMutation, + useDeleteProjectMutation, + useProjectsQuery, +} from "lib/graphql/generated"; function ProjectList(): JSX.Element { const theme = useTheme(); - const { - loading: projLoading, - error: projErr, - data: projData, - } = useQuery<{ projects: Project[] }>(PROJECTS, { - fetchPolicy: "network-only", - }); - const [openProject, { error: openProjErr, loading: openProjLoading }] = useMutation<{ openProject: Project }>( - OPEN_PROJECT, - { - errorPolicy: "all", - onError: () => {}, - update(cache, { data }) { - cache.modify({ - fields: { - activeProject() { - const activeProjRef = cache.writeFragment({ - data: data?.openProject, - fragment: gql` - fragment ActiveProject on Project { - id - name - isActive - type - } - `, - }); - return activeProjRef; - }, - projects(_, { DELETE }) { - cache.writeFragment({ - id: data?.openProject.id, - data: openProject, - fragment: gql` - fragment OpenProject on Project { - id - name - isActive - type - } - `, - }); - return DELETE; - }, - httpRequestLogFilter(_, { DELETE }) { - return DELETE; - }, - }, - }); - }, - } - ); - const [closeProject, { error: closeProjErr, client }] = useMutation(CLOSE_PROJECT, { + const projResult = useProjectsQuery({ fetchPolicy: "network-only" }); + const [openProject, openProjResult] = useOpenProjectMutation(); + const [closeProject, closeProjResult] = useCloseProjectMutation({ errorPolicy: "all", - onError: () => {}, onCompleted() { - client.resetStore(); + closeProjResult.client.resetStore(); }, update(cache) { cache.modify({ @@ -142,9 +61,8 @@ function ProjectList(): JSX.Element { }); }, }); - const [deleteProject, { loading: deleteProjLoading, error: deleteProjErr }] = useMutation(DELETE_PROJECT, { + const [deleteProject, deleteProjResult] = useDeleteProjectMutation({ errorPolicy: "all", - onError: () => {}, update(cache) { cache.modify({ fields: { @@ -158,14 +76,16 @@ function ProjectList(): JSX.Element { }, }); - const [deleteProj, setDeleteProj] = useState(); + const [deleteProj, setDeleteProj] = useState(); const [deleteDiagOpen, setDeleteDiagOpen] = useState(false); - const handleDeleteButtonClick = (project: any) => { + const handleDeleteButtonClick = (project: ProjectsQuery["projects"][number]) => { setDeleteProj(project); setDeleteDiagOpen(true); }; const handleDeleteConfirm = () => { - deleteProject({ variables: { id: deleteProj?.id } }); + if (deleteProj) { + deleteProject({ variables: { id: deleteProj.id } }); + } }; const handleDeleteCancel = () => { setDeleteDiagOpen(false); @@ -189,7 +109,9 @@ function ProjectList(): JSX.Element { Deleting a project permanently removes all its data from the database. This action is irreversible. - {deleteProjErr && Error closing project: {deleteProjErr.message}} + {deleteProjResult.error && ( + Error closing project: {deleteProjResult.error.message} + )}