From 52892c26e5dc34a7ca7e2f1aee947f3512bdf128 Mon Sep 17 00:00:00 2001 From: akhilmhdh Date: Fri, 28 Jul 2023 16:55:22 +0530 Subject: [PATCH] feat: fixed padding, added progress bar for routing, added sticky header for overview --- frontend/package-lock.json | 11 ++ frontend/package.json | 1 + .../components/v2/EmptyState/EmptyState.tsx | 2 +- .../components/v2/SecretInput/SecretInput.tsx | 4 +- frontend/src/components/v2/Table/Table.tsx | 20 ++- frontend/src/components/v2/Table/index.tsx | 6 +- frontend/src/pages/_app.tsx | 20 ++- frontend/src/styles/globals.css | 4 + .../src/views/DashboardPage/DashboardPage.tsx | 117 ++++++++++-------- .../SecretOverviewPage/SecretOverviewPage.tsx | 69 ++++++++--- .../SecretOverviewFolderRow.tsx | 6 +- .../SecretOverviewTableRow/SecretEditRow.tsx | 2 +- .../SecretOverviewTableRow.tsx | 49 +++++--- 13 files changed, 213 insertions(+), 98 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d25ff5cf1..987ebd5c8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -62,6 +62,7 @@ "lottie-react": "^2.4.0", "markdown-it": "^13.0.1", "next": "^12.3.4", + "nprogress": "^0.2.0", "posthog-js": "^1.58.0", "query-string": "^7.1.3", "react": "^17.0.2", @@ -17481,6 +17482,11 @@ "set-blocking": "^2.0.0" } }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -35769,6 +35775,11 @@ "set-blocking": "^2.0.0" } }, + "nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, "nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 51028a59b..e779e95b1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -70,6 +70,7 @@ "lottie-react": "^2.4.0", "markdown-it": "^13.0.1", "next": "^12.3.4", + "nprogress": "^0.2.0", "posthog-js": "^1.58.0", "query-string": "^7.1.3", "react": "^17.0.2", diff --git a/frontend/src/components/v2/EmptyState/EmptyState.tsx b/frontend/src/components/v2/EmptyState/EmptyState.tsx index bb6be9afa..e285500c1 100644 --- a/frontend/src/components/v2/EmptyState/EmptyState.tsx +++ b/frontend/src/components/v2/EmptyState/EmptyState.tsx @@ -26,7 +26,7 @@ export const EmptyState = ({ )} > -
+
{title}
{children}
diff --git a/frontend/src/components/v2/SecretInput/SecretInput.tsx b/frontend/src/components/v2/SecretInput/SecretInput.tsx index 8380eb4a1..5e517c08f 100644 --- a/frontend/src/components/v2/SecretInput/SecretInput.tsx +++ b/frontend/src/components/v2/SecretInput/SecretInput.tsx @@ -70,7 +70,9 @@ export const SecretInput = ({ dangerouslySetInnerHTML={{ __html: syntaxHighlight(value, isVisible || isSecretFocused) }} - className={`absolute top-0 left-0 z-0 h-full w-full text-ellipsis whitespace-pre-line break-all ${!value && value !== "" && "text-red-600 italic"}`} + className={`absolute top-0 left-0 z-0 h-full w-full text-ellipsis whitespace-pre-line break-all ${ + !value && value !== "" && "italic text-red-600/70" + }`} /> ( ); +export type TFootProps = { + children: ReactNode; + className?: string; +}; + +export const TFoot = ({ children, className }: TFootProps): JSX.Element => ( + + {children} + +); + // table rows export type TrProps = { children: ReactNode; @@ -68,7 +79,7 @@ export const Tr = ({ }: TrProps): JSX.Element => ( ( +export const TableSkeleton = ({ + rows = 3, + columns, + innerKey, + className +}: TBodyLoader): JSX.Element => ( <> {Array.apply(0, Array(rows)).map((_x, i) => ( diff --git a/frontend/src/components/v2/Table/index.tsx b/frontend/src/components/v2/Table/index.tsx index 9807c1e1a..8270cb002 100644 --- a/frontend/src/components/v2/Table/index.tsx +++ b/frontend/src/components/v2/Table/index.tsx @@ -3,8 +3,8 @@ export type { TableProps, TBodyProps, TdProps, + TFootProps, THeadProps, ThProps, - TrProps -} from "./Table"; -export { Table, TableContainer, TableSkeleton,TBody, Td, Th, THead, Tr } from "./Table"; + TrProps} from "./Table"; +export { Table, TableContainer, TableSkeleton, TBody, Td, TFoot,Th, THead, Tr } from "./Table"; diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index 963a8d655..82e642245 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -9,6 +9,7 @@ import { AppProps } from "next/app"; import { useRouter } from "next/router"; import { config } from "@fortawesome/fontawesome-svg-core"; import { QueryClientProvider } from "@tanstack/react-query"; +import NProgress from "nprogress"; import NotificationProvider from "@app/components/context/Notifications/NotificationProvider"; import { IntercomProvider } from "@app/components/utilities/intercom/intercomProvider"; @@ -25,6 +26,7 @@ import { import { AppLayout } from "@app/layouts"; import { queryClient } from "@app/reactQuery"; +import "nprogress/nprogress.css"; import "@fortawesome/fontawesome-svg-core/styles.css"; import "../styles/globals.css"; @@ -44,7 +46,7 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element => const telemetry = new Telemetry().getInstance(); const handleRouteChange = () => { - // (window).Intercom('update'); + // (window).Intercom('update'); if (typeof window !== "undefined") { telemetry.capture("$pageview"); } @@ -57,6 +59,22 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element => }; }, [router.events]); + useEffect(() => { + const handleStart = () => NProgress.start(); + + const handleStop = () => NProgress.done(); + + router.events.on("routeChangeStart", handleStart); + router.events.on("routeChangeComplete", handleStop); + router.events.on("routeChangeError", handleStop); + + return () => { + router.events.off("routeChangeStart", handleStart); + router.events.off("routeChangeComplete", handleStop); + router.events.off("routeChangeError", handleStop); + }; + }, [router]); + // If it's one of these routes, don't add the layout (e.g., these routes are external) if ( publicPaths.includes(`/${appProps.router.pathname.split("/")[1]}`) || diff --git a/frontend/src/styles/globals.css b/frontend/src/styles/globals.css index 9c1afd84d..ed191a319 100644 --- a/frontend/src/styles/globals.css +++ b/frontend/src/styles/globals.css @@ -87,6 +87,10 @@ scrollbar-width: thin; scrollbar-color: gray transparent; } + + #nprogress .bar { + @apply bg-primary-400; + } } @import "@fontsource/inter/400.css"; diff --git a/frontend/src/views/DashboardPage/DashboardPage.tsx b/frontend/src/views/DashboardPage/DashboardPage.tsx index f991df901..6d794cbec 100644 --- a/frontend/src/views/DashboardPage/DashboardPage.tsx +++ b/frontend/src/views/DashboardPage/DashboardPage.tsx @@ -506,38 +506,44 @@ export const DashboardPage = () => { handlePopUpClose("secretDetails"); }, []); - const onCreateWsTag = useCallback(async (tagName: string) => { - try { - await createWsTag({ - workspaceID: workspaceId, - tagName, - tagSlug: tagName.replace(" ", "_") - }); - handlePopUpClose("addTag"); - createNotification({ - text: "Successfully created a tag", - type: "success" - }); - } catch (error) { - console.error(error); - createNotification({ - text: "Failed to create a tag", - type: "error" - }); - } - }, []); - - const handleFolderOpen = useCallback((id: string) => { - setSearchFilter(""); - console.log(router.query); - router.push({ - pathname: router.pathname, - query: { - ...router.query, - folderId: id + const onCreateWsTag = useCallback( + async (tagName: string) => { + try { + await createWsTag({ + workspaceID: workspaceId, + tagName, + tagSlug: tagName.replace(" ", "_") + }); + handlePopUpClose("addTag"); + createNotification({ + text: "Successfully created a tag", + type: "success" + }); + } catch (error) { + console.error(error); + createNotification({ + text: "Failed to create a tag", + type: "error" + }); } - }); - }, []); + }, + [workspaceId] + ); + + const handleFolderOpen = useCallback( + (id: string) => { + setSearchFilter(""); + router.push({ + pathname: router.pathname, + query: { + id: workspaceId, + env: envQuery, + folderId: id + } + }); + }, + [envQuery, workspaceId] + ); const isEditFolder = Boolean(popUp?.folderForm?.data); @@ -564,28 +570,31 @@ export const DashboardPage = () => { } }; - const handleFolderUpdate = useCallback(async (name: string) => { - const { id } = popUp?.folderForm?.data as TDeleteFolderForm; - try { - await updateFolder({ - folderId: id, - workspaceId, - environment: selectedEnv?.slug || "", - name - }); - createNotification({ - type: "success", - text: "Successfully updated folder" - }); - handlePopUpClose("folderForm"); - } catch (error) { - console.error(error); - createNotification({ - text: "Failed to update folder", - type: "error" - }); - } - }, []); + const handleFolderUpdate = useCallback( + async (name: string) => { + const { id } = popUp?.folderForm?.data as TDeleteFolderForm; + try { + await updateFolder({ + folderId: id, + workspaceId, + environment: selectedEnv?.slug || "", + name + }); + createNotification({ + type: "success", + text: "Successfully updated folder" + }); + handlePopUpClose("folderForm"); + } catch (error) { + console.error(error); + createNotification({ + text: "Failed to update folder", + type: "error" + }); + } + }, + [selectedEnv?.slug, (popUp?.folderForm?.data as TDeleteFolderForm)?.id] + ); const handleFolderDelete = useCallback(async () => { const { id } = popUp?.deleteFolder?.data as TDeleteFolderForm; @@ -607,7 +616,7 @@ export const DashboardPage = () => { type: "error" }); } - }, []); + }, [selectedEnv?.slug, (popUp?.deleteFolder?.data as TDeleteFolderForm)?.id]); // SECRET IMPORT SECTION const handleSecretImportCreate = async (env: string, secretPath: string) => { diff --git a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx index 012a13166..86f2a2071 100644 --- a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx +++ b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx @@ -1,19 +1,22 @@ import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; +import Link from "next/link"; import { useRouter } from "next/router"; -import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons"; +import { faFolderBlank, faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import NavHeader from "@app/components/navigation/NavHeader"; import { Button, + EmptyState, Input, Table, TableContainer, TableSkeleton, TBody, Td, + TFoot, Th, THead, Tooltip, @@ -210,8 +213,9 @@ export const SecretOverviewPage = () => { ); } - const isTableLoading = - folders?.some(({ isLoading }) => isLoading) && secrets?.some(({ isLoading }) => isLoading); + const isTableLoading = !( + folders?.some(({ isLoading }) => !isLoading) && secrets?.some(({ isLoading }) => !isLoading) + ); const filteredSecretNames = secKeys?.filter((name) => name.toUpperCase().includes(searchFilter.toUpperCase()) @@ -219,6 +223,12 @@ export const SecretOverviewPage = () => { const filteredFolderNames = folderNames?.filter((name) => name.toLowerCase().includes(searchFilter.toLowerCase()) ); + const isTableEmpty = + !( + folders?.every(({ isLoading }) => isLoading) && secrets?.every(({ isLoading }) => isLoading) + ) && + filteredSecretNames?.length === 0 && + filteredFolderNames?.length === 0; return (
@@ -260,28 +270,32 @@ export const SecretOverviewPage = () => { />
-
- +
+ - - - + + + {userAvailableEnvs?.map(({ name, slug }, index) => { const envSecKeyCount = getEnvSecretKeyCount(slug); const missingKeyCount = secKeys.length - envSecKeyCount; return ( + + + )} {filteredFolderNames.map((folderName, index) => ( { expandableColWidth={expandableTableWidth} /> ))} - - + + {userAvailableEnvs.map(({ name, slug }) => ( - ))} - +
Name
+
+ Name +
+
-
+
{name} {missingKeyCount > 0 && ( -
+
{missingKeyCount}
@@ -301,6 +315,22 @@ export const SecretOverviewPage = () => { className="bg-mineshaft-700" /> )} + {isTableEmpty && ( +
+ + + + + +
+ +
+
+
-
+
+
diff --git a/frontend/src/views/SecretOverviewPage/components/SecretOverviewFolderRow/SecretOverviewFolderRow.tsx b/frontend/src/views/SecretOverviewPage/components/SecretOverviewFolderRow/SecretOverviewFolderRow.tsx index 9523d5250..a3e39dbfc 100644 --- a/frontend/src/views/SecretOverviewPage/components/SecretOverviewFolderRow/SecretOverviewFolderRow.tsx +++ b/frontend/src/views/SecretOverviewPage/components/SecretOverviewFolderRow/SecretOverviewFolderRow.tsx @@ -19,8 +19,8 @@ export const SecretOverviewFolderRow = ({ }: Props) => { return ( onClick(folderName)}> - -
+ +
@@ -33,7 +33,7 @@ export const SecretOverviewFolderRow = ({ diff --git a/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretEditRow.tsx b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretEditRow.tsx index 803504778..c69cf6514 100644 --- a/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretEditRow.tsx +++ b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretEditRow.tsx @@ -85,7 +85,7 @@ export const SecretEditRow = ({ }; return ( -
+
setIsFormExpanded.toggle()} className="group"> - -
+ +
@@ -60,12 +71,14 @@ export const SecretOverviewTableRow = ({ !isSecretPresent && !isSecretEmpty ? "text-red-600" : "" )} > -
+
{!isSecretEmpty && } - {isSecretEmpty && - - } + {isSecretEmpty && ( + + + + )}
@@ -74,14 +87,16 @@ export const SecretOverviewTableRow = ({ {isFormExpanded && ( - +
@@ -94,8 +109,10 @@ export const SecretOverviewTableRow = ({ > Environment - Value -
+ + Value + +