Remove old frontend

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-06-13 13:38:48 -07:00
parent 2adfe50054
commit d6ba8e1072
646 changed files with 671 additions and 78623 deletions

View File

@@ -1,38 +0,0 @@
import { Toaster } from "@/components/ui/toaster";
import { ReactNode } from "react";
export default function AuthLayout({ children }: { children: ReactNode }) {
return (
<div className="flex min-h-screen flex-col">
<div className="flex flex-1">
<div className="flex flex-1 flex-col bg-subtle-bg/40">
<div className="flex flex-1 items-center justify-center">
<main className="w-full max-w-md p-6">{children}</main>
</div>
</div>
<div className="hidden flex-1 bg-linear-to-br from-gray-900 to-gray-950 lg:block">
<div className="flex h-full items-center justify-center p-8">
<div className="relative h-full w-full">
<div className="absolute right-0 top-1/4 z-10">
<img
src="/assets/android-chrome-512x512.png"
alt="Probo Mascot"
className="h-auto w-96"
/>
</div>
<div className="absolute left-8 top-1/3 z-0 text-white">
<h1 className="text-4xl font-bold leading-tight">
Navigate compliance with
<br />
confidence thanks to{" "}
<span className="text-accent">probo</span>
</h1>
</div>
</div>
</div>
</div>
</div>
<Toaster />
</div>
);
}

View File

@@ -0,0 +1,217 @@
import { Link, Navigate, Outlet, useParams } from "react-router";
import {
DropdownSeparator,
IconArrowBoxLeft,
IconBank,
IconCircleQuestionmark,
IconFire3,
IconGroup1,
IconInboxEmpty,
IconPageTextLine,
IconSettingsGear2,
IconStore,
IconTodo,
IconListStack,
IconBox,
Layout,
SidebarItem,
UserDropdown as UserDropdownRoot,
UserDropdownItem,
Skeleton,
Dropdown,
Button,
DropdownItem,
IconChevronGrabberVertical,
IconPlusLarge,
Avatar,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { graphql } from "relay-runtime";
import { useLazyLoadQuery } from "react-relay";
import type { MainLayoutQuery as MainLayoutQueryType } from "./__generated__/MainLayoutQuery.graphql";
import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { PageError } from "/components/PageError";
const MainLayoutQuery = graphql`
query MainLayoutQuery {
viewer {
id
user {
fullName
email
}
organizations(first: 25) @connection(key: "MainLayout_organizations") {
__id
edges {
node {
id
name
logoUrl
}
}
}
}
}
`;
/**
* Site layout with a header and a sidebar
*/
export function MainLayout() {
const { organizationId } = useParams();
const { __ } = useTranslate();
const prefix = `/organizations/${organizationId}`;
if (!organizationId) {
return <Navigate to="/" />;
}
return (
<Layout
header={
<>
<div className="mr-auto">
<Suspense fallback={<Skeleton className="w-20 h-8" />}>
<OrganizationSelector organizationId={organizationId} />
</Suspense>
</div>
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
<UserDropdown />
</Suspense>
</>
}
sidebar={
<ul className="space-y-[2px]">
<SidebarItem
label={__("Tasks")}
icon={IconInboxEmpty}
to={`${prefix}/tasks`}
/>
<SidebarItem
label={__("Measures")}
icon={IconTodo}
to={`${prefix}/measures`}
/>
<SidebarItem
label={__("Risks")}
icon={IconFire3}
to={`${prefix}/risks`}
/>
<SidebarItem
label={__("Frameworks")}
icon={IconBank}
to={`${prefix}/frameworks`}
/>
<SidebarItem
label={__("People")}
icon={IconGroup1}
to={`${prefix}/people`}
/>
<SidebarItem
label={__("Vendors")}
icon={IconStore}
to={`${prefix}/vendors`}
/>
<SidebarItem
label={__("Documents")}
icon={IconPageTextLine}
to={`${prefix}/documents`}
/>
<SidebarItem
label={__("Assets")}
icon={IconBox}
to={`${prefix}/assets`}
/>
<SidebarItem
label={__("Data")}
icon={IconListStack}
to={`${prefix}/data`}
/>
<SidebarItem
label={__("Settings")}
icon={IconSettingsGear2}
to={`${prefix}/settings`}
/>
</ul>
}
>
<ErrorBoundary FallbackComponent={PageError}>
<Outlet />
</ErrorBoundary>
</Layout>
);
}
function UserDropdown() {
const { __ } = useTranslate();
const user = useLazyLoadQuery<MainLayoutQueryType>(MainLayoutQuery, {}).viewer
.user;
return (
<UserDropdownRoot fullName={user.fullName} email={user.email}>
<UserDropdownItem
to="/settings"
icon={IconSettingsGear2}
label={__("Settings")}
/>
<UserDropdownItem
to="mailto:support@getprobo.com"
icon={IconCircleQuestionmark}
label={__("Help")}
/>
<DropdownSeparator />
<UserDropdownItem
variant="danger"
to="/logout"
icon={IconArrowBoxLeft}
label="Logout"
/>
</UserDropdownRoot>
);
}
function OrganizationSelector({ organizationId }: { organizationId: string }) {
const organizations = useLazyLoadQuery<MainLayoutQueryType>(
MainLayoutQuery,
{}
).viewer.organizations.edges.map((edge) => edge.node);
const currentOrganization = organizations.find(
(organization) => organization.id === organizationId
);
const { __ } = useTranslate();
return (
<Dropdown
toggle={
<Button
className="-ml-3"
variant="tertiary"
iconAfter={IconChevronGrabberVertical}
>
{currentOrganization?.name}
</Button>
}
>
{organizations.map((organization) => (
<DropdownItem
asChild
key={organization.id}
icon={IconCircleQuestionmark}
>
<Link to={`/organizations/${organization.id}`}>
<Avatar src={organization.logoUrl} name={organization.name} />
{organization.name}
</Link>
</DropdownItem>
))}
<DropdownSeparator />
<DropdownItem asChild icon={IconPlusLarge}>
<Link to="/organizations/new">
<IconPlusLarge size={16} />
{__("Add organization")}
</Link>
</DropdownItem>
</Dropdown>
);
}

View File

@@ -0,0 +1,280 @@
/**
* @generated SignedSource<<d411922830ba632f8c48c98caa435a22>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type MainLayoutQuery$variables = Record<PropertyKey, never>;
export type MainLayoutQuery$data = {
readonly viewer: {
readonly id: string;
readonly organizations: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly logoUrl: string | null | undefined;
readonly name: string;
};
}>;
};
readonly user: {
readonly email: string;
readonly fullName: string;
};
};
};
export type MainLayoutQuery = {
response: MainLayoutQuery$data;
variables: MainLayoutQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
v3 = [
{
"alias": null,
"args": null,
"concreteType": "OrganizationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "logoUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
v4 = [
{
"kind": "Literal",
"name": "first",
"value": 25
}
];
return {
"fragment": {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "MainLayoutQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Viewer",
"kind": "LinkedField",
"name": "viewer",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "user",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/)
],
"storageKey": null
},
{
"alias": "organizations",
"args": null,
"concreteType": "OrganizationConnection",
"kind": "LinkedField",
"name": "__MainLayout_organizations_connection",
"plural": false,
"selections": (v3/*: any*/),
"storageKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [],
"kind": "Operation",
"name": "MainLayoutQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Viewer",
"kind": "LinkedField",
"name": "viewer",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "user",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/),
(v0/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "OrganizationConnection",
"kind": "LinkedField",
"name": "organizations",
"plural": false,
"selections": (v3/*: any*/),
"storageKey": "organizations(first:25)"
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": null,
"handle": "connection",
"key": "MainLayout_organizations",
"kind": "LinkedHandle",
"name": "organizations"
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "9ab80df970b8fa7c4eabff75a6730ec5",
"id": null,
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "forward",
"path": [
"viewer",
"organizations"
]
}
]
},
"name": "MainLayoutQuery",
"operationKind": "query",
"text": "query MainLayoutQuery {\n viewer {\n id\n user {\n fullName\n email\n id\n }\n organizations(first: 25) {\n edges {\n node {\n id\n name\n logoUrl\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "fc37d1b70f1a239abb4c959d47ee28fd";
export default node;