diff --git a/apps/console/src/layouts/ConsoleLayout.tsx b/apps/console/src/layouts/ConsoleLayout.tsx index a7af6e5b3..6accb98bf 100644 --- a/apps/console/src/layouts/ConsoleLayout.tsx +++ b/apps/console/src/layouts/ConsoleLayout.tsx @@ -381,8 +381,8 @@ export default function ConsoleLayout() { - -
+ +
Frameworks - Probo -
-
-
-

Frameworks

-

- Manage your compliance frameworks -

-
-
- - - - - - - Import Framework - -
-
- - -

- Upload a JSON file containing your framework definition. -

+
+ + + + + + + + Import Framework + +
+
+ + +

+ Upload a JSON file containing your framework definition. +

+
-
- -
- -
-
+ + + +
+ } + />
{frameworks.map((framework) => { diff --git a/apps/console/src/pages/FrameworkOverviewPage.tsx b/apps/console/src/pages/FrameworkOverviewPage.tsx index e7cd08c56..9a1d07366 100644 --- a/apps/console/src/pages/FrameworkOverviewPage.tsx +++ b/apps/console/src/pages/FrameworkOverviewPage.tsx @@ -12,6 +12,7 @@ import { Button } from "@/components/ui/button"; import type { FrameworkOverviewPageQuery as FrameworkOverviewPageQueryType } from "./__generated__/FrameworkOverviewPageQuery.graphql"; import { Helmet } from "react-helmet-async"; import { createPortal } from "react-dom"; +import { PageHeader } from "./PageHeader"; const FrameworkOverviewPageQuery = graphql` query FrameworkOverviewPageQuery($frameworkId: ID!) { @@ -81,14 +82,13 @@ function FrameworkOverviewPageContent({ ).length; return ( -
-
-
-
-

{framework.name}

-

{framework.description}

-
-
+
+
-
-
+ } + />

Controls

diff --git a/apps/console/src/pages/PageHeader.tsx b/apps/console/src/pages/PageHeader.tsx new file mode 100644 index 000000000..3d197fae0 --- /dev/null +++ b/apps/console/src/pages/PageHeader.tsx @@ -0,0 +1,50 @@ +import { cn } from "@/lib/utils"; +import { ReactNode } from "react"; + +export function PageHeader({ + className, + title, + actions, + description, +}: { + className?: string; + title: string; + actions?: ReactNode; + description: string; +}) { + return ( +
+ {actions ? ( +
+ + {actions} +
+ ) : ( + + )} + {description} +
+ ); +} + +export function PageHeading({ + title, + className, +}: { + className?: string; + title: string; +}) { + return

{title}

; +} + +export function PageDescription({ + children, + className, +}: { + className?: string; + children: ReactNode; +}) { + return ( +

{children}

+ ); +} diff --git a/apps/console/src/pages/PeopleListPage.tsx b/apps/console/src/pages/PeopleListPage.tsx index ef8bca8e9..7c5b78fb2 100644 --- a/apps/console/src/pages/PeopleListPage.tsx +++ b/apps/console/src/pages/PeopleListPage.tsx @@ -18,6 +18,7 @@ import type { PeopleListPageQuery as PeopleListPageQueryType } from "./__generat import type { PeopleListPageDeletePeopleMutation } from "./__generated__/PeopleListPageDeletePeopleMutation.graphql"; import { PeopleListPagePaginationQuery } from "./__generated__/PeopleListPagePaginationQuery.graphql"; import { PeopleListPage_peoples$key } from "./__generated__/PeopleListPage_peoples.graphql"; +import { PageHeader } from "./PageHeader"; const ITEMS_PER_PAGE = 25; @@ -168,124 +169,127 @@ function PeopleListContent({ const pageInfo = peoplesConnection.peoples.pageInfo; return ( -
-
-

Employees

-

- Keep track of your company{"'"}s workforce and their progress towards - completing tasks assigned to them. -

-
+ <> + + People - Probo + +
+ + + + Add a person + + + } + /> -
- -
- -
- {peoples.map((person) => ( - -
-
- - {person?.fullName?.[0]} - +
+ {peoples.map((person) => ( + +
+
+ + {person?.fullName?.[0]} + +
+

{person?.fullName}

+ {person?.primaryEmailAddress && ( + <> + • +

+ {person.primaryEmailAddress} +

+ + )} +
+
-

{person?.fullName}

- {person?.primaryEmailAddress && ( - <> - • -

- {person.primaryEmailAddress} -

- - )} + + {person?.kind === "EMPLOYEE" + ? "Employee" + : person?.kind === "CONTRACTOR" + ? "Contractor" + : "Vendor"} + + +
-
- - {person?.kind === "EMPLOYEE" - ? "Employee" - : person?.kind === "CONTRACTOR" - ? "Contractor" - : "Vendor"} - - - -
-
- - ))} -
+ + ))} +
- { - startTransition(() => { - setSearchParams((prev) => { - prev.set("before", pageInfo?.startCursor || ""); - prev.delete("after"); - return prev; + { + startTransition(() => { + setSearchParams((prev) => { + prev.set("before", pageInfo?.startCursor || ""); + prev.delete("after"); + return prev; + }); + loadPrevious(ITEMS_PER_PAGE); }); - loadPrevious(ITEMS_PER_PAGE); - }); - }} - /> - { - startTransition(() => { - setSearchParams((prev) => { - prev.set("after", pageInfo?.endCursor || ""); - prev.delete("before"); - return prev; + }} + /> + { + startTransition(() => { + setSearchParams((prev) => { + prev.set("after", pageInfo?.endCursor || ""); + prev.delete("before"); + return prev; + }); + loadNext(ITEMS_PER_PAGE); }); - loadNext(ITEMS_PER_PAGE); - }); - }} - /> -
+ }} + /> +
+ ); } diff --git a/apps/console/src/pages/PolicyListPage.tsx b/apps/console/src/pages/PolicyListPage.tsx index 424474eba..cc7cd6761 100644 --- a/apps/console/src/pages/PolicyListPage.tsx +++ b/apps/console/src/pages/PolicyListPage.tsx @@ -34,6 +34,7 @@ import { import { Badge } from "@/components/ui/badge"; import { format } from "date-fns"; import type { PolicyListPageQuery as PolicyListPageQueryType } from "./__generated__/PolicyListPageQuery.graphql"; +import { PageHeader } from "./PageHeader"; const PolicyListPageQuery = graphql` query PolicyListPageQuery($organizationId: ID!) { @@ -223,21 +224,20 @@ function PolicyListPageContent({ Policies - Probo -
-
-
-

Policies

-

- Manage your organization{"'"}s policies -

-
- -
+
+ + + + Create Policy + + + } + /> {/* Search and filter controls */}
diff --git a/apps/console/src/pages/SettingsPage.tsx b/apps/console/src/pages/SettingsPage.tsx index 52c73b571..c164d8021 100644 --- a/apps/console/src/pages/SettingsPage.tsx +++ b/apps/console/src/pages/SettingsPage.tsx @@ -39,6 +39,7 @@ import type { SettingsPageQuery as SettingsPageQueryType } from "./__generated__ import type { SettingsPageUpdateOrganizationMutation as SettingsPageUpdateOrganizationMutationType } from "./__generated__/SettingsPageUpdateOrganizationMutation.graphql"; import type { SettingsPageInviteUserMutation as SettingsPageInviteUserMutationType } from "./__generated__/SettingsPageInviteUserMutation.graphql"; import type { SettingsPageRemoveUserMutation as SettingsPageRemoveUserMutationType } from "./__generated__/SettingsPageRemoveUserMutation.graphql"; +import { PageHeader } from "./PageHeader"; const settingsPageQuery = graphql` query SettingsPageQuery($organizationID: ID!) { @@ -290,13 +291,12 @@ function SettingsPageContent({ return ( <> -
-
-

Settings

-

- Manage your details and personal preferences here. -

-
+
+ diff --git a/apps/console/src/pages/VendorListPage.tsx b/apps/console/src/pages/VendorListPage.tsx index 4d4c3c80d..5ec7dca70 100644 --- a/apps/console/src/pages/VendorListPage.tsx +++ b/apps/console/src/pages/VendorListPage.tsx @@ -22,6 +22,7 @@ import { VendorListPageDeleteVendorMutation } from "./__generated__/VendorListPa import { VendorListPagePaginationQuery } from "./__generated__/VendorListPagePaginationQuery.graphql"; import { VendorListPage_vendors$key } from "./__generated__/VendorListPage_vendors.graphql"; import { useToast } from "@/hooks/use-toast"; +import { PageHeader } from "./PageHeader"; const ITEMS_PER_PAGE = 25; @@ -234,183 +235,190 @@ function VendorListContent({ }); return ( -
-
-

Vendors

-

- Vendors are third-party services that your company uses. Add them to - keep track of their risk and compliance status. -

-
+ <> + + Vendors - Probo + +
+ -
-
- -

Add a vendor

-
-
- { - const value = e.target.value; - setSearchTerm(value); - if (value.trim() === "") { - setFilteredVendors([]); - } else { - const results = fuse.search(value).map((result) => result.item); - setFilteredVendors(results); - } - }} - /> - - {searchTerm.trim() !== "" && filteredVendors.length > 0 && ( -
+
+ +

Add a vendor

+
+
+ - {filteredVendors.map((vendor: VendorItem) => ( - - ))} -
- )} -
-
+ onChange={(e) => { + const value = e.target.value; + setSearchTerm(value); + if (value.trim() === "") { + setFilteredVendors([]); + } else { + const results = fuse + .search(value) + .map((result) => result.item); + setFilteredVendors(results); + } + }} + /> -
- {vendors.map((vendor) => ( - -
-
- - {vendor?.name?.[0]} - -
-

{vendor?.name}

- {vendor?.description && ( - <> - • -

- {vendor.description} -

- - )} -
-
-
- - {vendor.riskTier} - - - + }} + > + {vendor.name} + + ))}
-
- - ))} -
+ )} +
+
- { - startTransition(() => { - setSearchParams((prev) => { - prev.set("before", pageInfo?.startCursor || ""); - prev.delete("after"); - return prev; +
+ {vendors.map((vendor) => ( + +
+
+ + {vendor?.name?.[0]} + +
+

{vendor?.name}

+ {vendor?.description && ( + <> + • +

+ {vendor.description} +

+ + )} +
+
+
+ + {vendor.riskTier} + + + +
+
+ + ))} +
+ + { + startTransition(() => { + setSearchParams((prev) => { + prev.set("before", pageInfo?.startCursor || ""); + prev.delete("after"); + return prev; + }); + loadPrevious(ITEMS_PER_PAGE); }); - loadPrevious(ITEMS_PER_PAGE); - }); - }} - /> - { - startTransition(() => { - setSearchParams((prev) => { - prev.set("after", pageInfo?.endCursor || ""); - prev.delete("before"); - return prev; + }} + /> + { + startTransition(() => { + setSearchParams((prev) => { + prev.set("after", pageInfo?.endCursor || ""); + prev.delete("before"); + return prev; + }); + loadNext(ITEMS_PER_PAGE); }); - loadNext(ITEMS_PER_PAGE); - }); - }} - /> -
+ }} + /> +
+ ); }