@@ -14,6 +14,7 @@
|
|||||||
"@radix-ui/react-collapsible": "^1.1.3",
|
"@radix-ui/react-collapsible": "^1.1.3",
|
||||||
"@radix-ui/react-dialog": "^1.1.6",
|
"@radix-ui/react-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||||
|
"@radix-ui/react-progress": "^1.1.2",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const NotFoundPage = lazy(() => import("./pages/NotFoundPage"));
|
|||||||
const PeoplesPage = lazy(() => import("./pages/PeoplesPage"));
|
const PeoplesPage = lazy(() => import("./pages/PeoplesPage"));
|
||||||
const VendorsPage = lazy(() => import("./pages/VendorsPage"));
|
const VendorsPage = lazy(() => import("./pages/VendorsPage"));
|
||||||
const FrameworksPage = lazy(() => import("./pages/FrameworksPage"));
|
const FrameworksPage = lazy(() => import("./pages/FrameworksPage"));
|
||||||
|
const FrameworkPage = lazy(() => import("./pages/FrameworkPage"));
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
@@ -41,6 +41,7 @@ function App() {
|
|||||||
<Route path="/peoples" element={<PeoplesPage />} />
|
<Route path="/peoples" element={<PeoplesPage />} />
|
||||||
<Route path="/vendors" element={<VendorsPage />} />
|
<Route path="/vendors" element={<VendorsPage />} />
|
||||||
<Route path="/frameworks" element={<FrameworksPage />} />
|
<Route path="/frameworks" element={<FrameworksPage />} />
|
||||||
|
<Route path="/frameworks/:frameworkId" element={<FrameworkPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="*" element={<NotFoundPage />} />
|
<Route path="*" element={<NotFoundPage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
26
apps/console/src/components/ui/progress.tsx
Normal file
26
apps/console/src/components/ui/progress.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import * as ProgressPrimitive from "@radix-ui/react-progress"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Progress = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
|
||||||
|
>(({ className, value, ...props }, ref) => (
|
||||||
|
<ProgressPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ProgressPrimitive.Indicator
|
||||||
|
className="h-full w-full flex-1 bg-primary transition-all"
|
||||||
|
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||||
|
/>
|
||||||
|
</ProgressPrimitive.Root>
|
||||||
|
))
|
||||||
|
Progress.displayName = ProgressPrimitive.Root.displayName
|
||||||
|
|
||||||
|
export { Progress }
|
||||||
206
apps/console/src/pages/FrameworkPage.tsx
Normal file
206
apps/console/src/pages/FrameworkPage.tsx
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
import { Suspense, useEffect } from "react";
|
||||||
|
import { useParams } from "react-router";
|
||||||
|
import {
|
||||||
|
graphql,
|
||||||
|
PreloadedQuery,
|
||||||
|
usePreloadedQuery,
|
||||||
|
useQueryLoader,
|
||||||
|
} from "react-relay";
|
||||||
|
import {
|
||||||
|
Building2,
|
||||||
|
Computer,
|
||||||
|
Mail,
|
||||||
|
Shield,
|
||||||
|
Network,
|
||||||
|
Database,
|
||||||
|
FileText,
|
||||||
|
Share2,
|
||||||
|
AlertTriangle,
|
||||||
|
Users,
|
||||||
|
Clock,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { Progress } from "@/components/ui/progress";
|
||||||
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||||
|
import type { FrameworkPageQuery as FrameworkPageQueryType } from "./__generated__/FrameworkPageQuery.graphql";
|
||||||
|
|
||||||
|
const FrameworkPageQuery = graphql`
|
||||||
|
query FrameworkPageQuery($frameworkId: ID!) {
|
||||||
|
node(id: $frameworkId) {
|
||||||
|
id
|
||||||
|
... on Framework {
|
||||||
|
name
|
||||||
|
description
|
||||||
|
controls {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
function FrameworkPageContent({
|
||||||
|
queryRef,
|
||||||
|
}: {
|
||||||
|
queryRef: PreloadedQuery<FrameworkPageQueryType>;
|
||||||
|
}) {
|
||||||
|
const data = usePreloadedQuery(FrameworkPageQuery, queryRef);
|
||||||
|
const framework = data.node;
|
||||||
|
const controls = framework.controls?.edges.map(edge => edge?.node) ?? [];
|
||||||
|
|
||||||
|
const controlsByCategory = {
|
||||||
|
office: controls.filter(c => c?.name.toLowerCase().includes('office')),
|
||||||
|
computer: controls.filter(c => c?.name.toLowerCase().includes('computer')),
|
||||||
|
employees: controls.filter(c => c?.name.toLowerCase().includes('employee')),
|
||||||
|
email: controls.filter(c => c?.name.toLowerCase().includes('email')),
|
||||||
|
code: controls.filter(c => c?.name.toLowerCase().includes('code')),
|
||||||
|
infrastructure: controls.filter(c => c?.name.toLowerCase().includes('infrastructure')),
|
||||||
|
network: controls.filter(c => c?.name.toLowerCase().includes('network')),
|
||||||
|
data: controls.filter(c => c?.name.toLowerCase().includes('data')),
|
||||||
|
logging: controls.filter(c => c?.name.toLowerCase().includes('log')),
|
||||||
|
incidents: controls.filter(c => c?.name.toLowerCase().includes('incident')),
|
||||||
|
vendors: controls.filter(c => c?.name.toLowerCase().includes('vendor')),
|
||||||
|
sharing: controls.filter(c => c?.name.toLowerCase().includes('share'))
|
||||||
|
};
|
||||||
|
|
||||||
|
const controlCards = [
|
||||||
|
{
|
||||||
|
icon: <Building2 className="w-4 h-4" />,
|
||||||
|
title: "Secure your offices and internet access",
|
||||||
|
controls: controlsByCategory.office,
|
||||||
|
completed: controlsByCategory.office.filter(c => c?.state === 'IMPLEMENTED').length,
|
||||||
|
total: controlsByCategory.office.length,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Computer className="w-4 h-4" />,
|
||||||
|
title: "Manage your computers",
|
||||||
|
controls: controlsByCategory.computer,
|
||||||
|
completed: controlsByCategory.computer.filter(c => c?.state === 'IMPLEMENTED').length,
|
||||||
|
total: controlsByCategory.computer.length,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const totalImplemented = controls.filter(c => c?.state === 'IMPLEMENTED').length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background p-6">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="space-y-4 mb-8">
|
||||||
|
<h1 className="text-2xl font-semibold">{framework.name}</h1>
|
||||||
|
<p className="text-muted-foreground max-w-3xl">
|
||||||
|
{framework.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Timeline */}
|
||||||
|
<div className="mb-8 space-y-4">
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<div className="bg-primary/10 text-primary px-3 py-1 rounded-md flex items-center gap-2">
|
||||||
|
<FileText className="w-4 h-4" />
|
||||||
|
Frame 153
|
||||||
|
</div>
|
||||||
|
<div className="bg-warning/10 text-warning px-3 py-1 rounded-md flex items-center gap-2">
|
||||||
|
<Clock className="w-4 h-4" />
|
||||||
|
12 hours left
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-card p-4 rounded-lg space-y-4">
|
||||||
|
<h3 className="font-medium">Preparation phase</h3>
|
||||||
|
<Progress value={30} className="h-2" />
|
||||||
|
<div className="flex justify-between text-sm text-muted-foreground">
|
||||||
|
<span>Preparation</span>
|
||||||
|
<span>Observation period: 3 month</span>
|
||||||
|
<span>Audit: 6-9 days</span>
|
||||||
|
<span>Report: 10-14 days</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6 flex justify-between items-center">
|
||||||
|
<h2 className="text-xl font-semibold">Controls</h2>
|
||||||
|
<div className="text-primary">{totalImplemented} out of {controls.length} validated</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{controlCards.map((card, index) => (
|
||||||
|
<Card key={index}>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
||||||
|
{card.icon}
|
||||||
|
{card.title}
|
||||||
|
</CardTitle>
|
||||||
|
<Avatar className="h-6 w-6">
|
||||||
|
<AvatarFallback>U</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex gap-1 my-2">
|
||||||
|
{Array(card.total)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={`h-2 w-2 rounded-sm ${
|
||||||
|
i < card.completed ? "bg-primary" : "bg-muted"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{card.completed}/{card.total} Controls validated
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FrameworkPageFallback() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background p-6">
|
||||||
|
<div className="mb-8">
|
||||||
|
<div className="h-8 w-48 bg-muted animate-pulse rounded" />
|
||||||
|
<div className="h-4 w-96 bg-muted animate-pulse rounded mt-2" />
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{[1, 2, 3].map((i) => (
|
||||||
|
<Card key={i}>
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<div className="relative mb-6">
|
||||||
|
<div className="bg-muted w-24 h-24 rounded-full animate-pulse mb-4" />
|
||||||
|
<div className="h-6 w-48 bg-muted animate-pulse rounded mb-2" />
|
||||||
|
<div className="h-20 w-full bg-muted animate-pulse rounded" />
|
||||||
|
</div>
|
||||||
|
<div className="h-4 w-32 bg-muted animate-pulse rounded" />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FrameworkPage() {
|
||||||
|
const { frameworkId } = useParams();
|
||||||
|
const [queryRef, loadQuery] = useQueryLoader<FrameworkPageQueryType>(FrameworkPageQuery);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadQuery({ frameworkId });
|
||||||
|
}, [loadQuery, frameworkId]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<FrameworkPageFallback />}>
|
||||||
|
{queryRef && <FrameworkPageContent queryRef={queryRef} />}
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
import { Globe2, CheckCircle } from "lucide-react";
|
import { Globe2, CheckCircle } from "lucide-react";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { Link } from "react-router";
|
||||||
import type { FrameworksPageQuery as FrameworksPageQueryType } from "./__generated__/FrameworksPageQuery.graphql";
|
import type { FrameworksPageQuery as FrameworksPageQueryType } from "./__generated__/FrameworksPageQuery.graphql";
|
||||||
|
|
||||||
const FrameworksPageQuery = graphql`
|
const FrameworksPageQuery = graphql`
|
||||||
@@ -60,7 +61,8 @@ function FrameworksPageContent({
|
|||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
{frameworks.map((framework) => (
|
{frameworks.map((framework) => (
|
||||||
<Card key={framework?.id} className="bg-card/50">
|
<Link key={framework?.id} to={`/frameworks/${framework.id}`}>
|
||||||
|
<Card className="bg-card/50 hover:bg-card/70 transition-colors">
|
||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<div className="relative mb-6">
|
<div className="relative mb-6">
|
||||||
<Badge className="absolute right-0 top-0 bg-green-500/10 text-green-500 hover:bg-green-500/20">
|
<Badge className="absolute right-0 top-0 bg-green-500/10 text-green-500 hover:bg-green-500/20">
|
||||||
@@ -83,6 +85,7 @@ function FrameworksPageContent({
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
191
apps/console/src/pages/__generated__/FrameworkPageQuery.graphql.ts
generated
Normal file
191
apps/console/src/pages/__generated__/FrameworkPageQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<51618c4ff52c6da6eb39cc0756d037e4>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type ControlState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED";
|
||||||
|
export type FrameworkPageQuery$variables = {
|
||||||
|
frameworkId: string;
|
||||||
|
};
|
||||||
|
export type FrameworkPageQuery$data = {
|
||||||
|
readonly node: {
|
||||||
|
readonly controls?: {
|
||||||
|
readonly edges: ReadonlyArray<{
|
||||||
|
readonly node: {
|
||||||
|
readonly description: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly name: string;
|
||||||
|
readonly state: ControlState;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
readonly description?: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly name?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type FrameworkPageQuery = {
|
||||||
|
response: FrameworkPageQuery$data;
|
||||||
|
variables: FrameworkPageQuery$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "frameworkId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v1 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "id",
|
||||||
|
"variableName": "frameworkId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v2 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v3 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v4 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "description",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v5 = {
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
(v4/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "ControlConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "controls",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "ControlEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "edges",
|
||||||
|
"plural": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Control",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
(v3/*: any*/),
|
||||||
|
(v4/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "state",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Framework",
|
||||||
|
"abstractKey": null
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "FrameworkPageQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
(v5/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Query",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "FrameworkPageQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "__typename",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
(v2/*: any*/),
|
||||||
|
(v5/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "20c37c26ec0c229a526ba1f84a0bb22e",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "FrameworkPageQuery",
|
||||||
|
"operationKind": "query",
|
||||||
|
"text": "query FrameworkPageQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n id\n ... on Framework {\n name\n description\n controls {\n edges {\n node {\n id\n name\n description\n state\n }\n }\n }\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "c018807d1942d694eceae254a3078c4d";
|
||||||
|
|
||||||
|
export default node;
|
||||||
25
package-lock.json
generated
25
package-lock.json
generated
@@ -22,6 +22,7 @@
|
|||||||
"@radix-ui/react-collapsible": "^1.1.3",
|
"@radix-ui/react-collapsible": "^1.1.3",
|
||||||
"@radix-ui/react-dialog": "^1.1.6",
|
"@radix-ui/react-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||||
|
"@radix-ui/react-progress": "^1.1.2",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
@@ -2699,6 +2700,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-progress": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-u1IgJFQ4zNAUTjGdDL5dcl/U8ntOR6jsnhxKb5RKp5Ozwl88xKR9EqRZOe/Mk8tnx0x5tNUe2F+MzsyjqMg0MA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-context": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.0.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-roving-focus": {
|
"node_modules/@radix-ui/react-roving-focus": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz",
|
||||||
|
|||||||
Reference in New Issue
Block a user