added basic heroku pipeline integration

This commit is contained in:
Vladyslav Matsiiako
2024-02-17 21:04:26 -08:00
parent a8678c14e8
commit 9012012503
14 changed files with 909 additions and 14 deletions

View File

@ -513,6 +513,37 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
}
});
server.route({
url: "/:integrationAuthId/heroku/pipelines",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
integrationAuthId: z.string().trim()
}),
response: {
200: z.object({
pipelines: z
.object({
app: z.object({ appId: z.string() }),
stage: z.string(),
pipeline: z.object({ name: z.string(), pipelineId: z.string() })
})
.array()
})
}
},
handler: async (req) => {
const pipelines = await server.services.integrationAuth.getHerokuPipelines({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
return { pipelines };
}
});
server.route({
url: "/:integrationAuthId/railway/environments",
method: "GET",

View File

@ -109,7 +109,7 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string })
*/
const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => {
const res = (
await request.get<{ name: string }[]>(`${IntegrationUrls.HEROKU_API_URL}/apps`, {
await request.get<{ name: string; id: string }[]>(`${IntegrationUrls.HEROKU_API_URL}/apps`, {
headers: {
Accept: "application/vnd.heroku+json; version=3",
Authorization: `Bearer ${accessToken}`
@ -118,7 +118,8 @@ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => {
).data;
const apps = res.map((a) => ({
name: a.name
name: a.name,
appId: a.id
}));
return apps;

View File

@ -20,9 +20,11 @@ import {
TDeleteIntegrationAuthsDTO,
TGetIntegrationAuthDTO,
TGetIntegrationAuthTeamCityBuildConfigDTO,
THerokuPipelineCoupling,
TIntegrationAuthAppsDTO,
TIntegrationAuthBitbucketWorkspaceDTO,
TIntegrationAuthChecklyGroupsDTO,
TIntegrationAuthHerokuPipelinesDTO,
TIntegrationAuthNorthflankSecretGroupDTO,
TIntegrationAuthQoveryEnvironmentsDTO,
TIntegrationAuthQoveryOrgsDTO,
@ -576,6 +578,37 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getHerokuPipelines = async ({ id, actor, actorId, actorOrgId }: TIntegrationAuthHerokuPipelinesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
const { data } = await request.get<THerokuPipelineCoupling[]>(
`${IntegrationUrls.HEROKU_API_URL}/pipeline-couplings`,
{
headers: {
Accept: "application/vnd.heroku+json; version=3",
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
);
return data.map(({ app: { id: appId }, stage, pipeline: { id: pipelineId, name } }) => ({
app: { appId },
stage,
pipeline: { pipelineId, name }
}));
};
const getRailwayEnvironments = async ({ id, actor, actorId, actorOrgId, appId }: TIntegrationAuthRailwayEnvDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
@ -915,6 +948,7 @@ export const integrationAuthServiceFactory = ({
getQoveryApps,
getQoveryEnvs,
getQoveryJobs,
getHerokuPipelines,
getQoveryOrgs,
getQoveryProjects,
getQoveryContainers,

View File

@ -62,6 +62,10 @@ export type TIntegrationAuthQoveryScopesDTO = {
environmentId: string;
} & Omit<TProjectPermission, "projectId">;
export type TIntegrationAuthHerokuPipelinesDTO = {
id: string;
} & Omit<TProjectPermission, "projectId">;
export type TIntegrationAuthRailwayEnvDTO = {
id: string;
appId: string;
@ -129,6 +133,12 @@ export type TNorthflankSecretGroup = {
projectId: string;
};
export type THerokuPipelineCoupling = {
app: { id: string };
stage: string;
pipeline: { id: string; name: string };
};
export type TTeamCityBuildConfig = {
id: string;
name: string;

View File

@ -31,6 +31,7 @@
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-popper": "^1.1.3",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
@ -4783,6 +4784,38 @@
}
}
},
"node_modules/@radix-ui/react-radio-group": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.1.3.tgz",
"integrity": "sha512-x+yELayyefNeKeTx4fjK6j99Fs6c4qKm3aY38G3swQVTN6xMpsrbigC0uHs2L//g8q4qR7qOcww8430jJmi2ag==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-roving-focus": "1.0.4",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-previous": "1.0.1",
"@radix-ui/react-use-size": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",

View File

@ -39,6 +39,7 @@
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-popper": "^1.1.3",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",

View File

@ -0,0 +1,40 @@
/* eslint-disable jsx-a11y/label-has-associated-control */
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
import { twMerge } from "tailwind-merge";
export type RadioGroupProps = RadioGroupPrimitive.RadioGroupProps;
// Note this component is not customizable (Heroku integration and potentially other pages depend on it)
export const RadioGroup = ({ className, children, ...props }: RadioGroupProps) => (
<RadioGroupPrimitive.Root
className={twMerge("flex flex-row gap-5 px-6 mb-6", className)}
defaultValue="App"
aria-label="View density"
{...props}
>
<div className="flex items-center">
<RadioGroupPrimitive.Item
className="bg-bunker-400/20 w-[20px] h-[20px] rounded-full hover:bg-bunker-400/40 border border-bunker-400/60 duration-200 outline-none cursor-default"
value="App"
id="r1"
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center w-full h-full relative after:content-[''] after:block after:w-[11px] after:h-[11px] after:rounded-[50%] after:bg-primary" />
</RadioGroupPrimitive.Item>
<label className="text-bunker-200 text-sm leading-none pl-2" htmlFor="r1">
App
</label>
</div>
<div className="flex items-center">
<RadioGroupPrimitive.Item
className="bg-bunker-400/20 w-[22px] h-[22px] rounded-full hover:bg-bunker-400/40 border border-bunker-400/60 duration-200 outline-none cursor-default"
value="Pipeline"
id="r2"
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center w-full h-full relative after:content-[''] after:block after:w-[13px] after:h-[13px] after:rounded-[50%] after:bg-primary" />
</RadioGroupPrimitive.Item>
<label className="text-bunker-200 text-sm leading-none pl-2" htmlFor="r2">
Pipeline
</label>
</div>
</RadioGroupPrimitive.Root>
);

View File

@ -0,0 +1,2 @@
export type { RadioGroupProps } from "./RadioGroup";
export { RadioGroup } from "./RadioGroup";

View File

@ -8,6 +8,7 @@ import {
BitBucketWorkspace,
ChecklyGroup,
Environment,
HerokuPipelineCoupling,
IntegrationAuth,
NorthflankSecretGroup,
Org,
@ -63,6 +64,8 @@ const integrationAuthKeys = {
environmentId: string;
scope: "job" | "application" | "container";
}) => [{ integrationAuthId, environmentId, scope }, "integrationAuthQoveryScopes"] as const,
getIntegrationAuthHerokuPipelines: ({ integrationAuthId }: { integrationAuthId: string; }) =>
[{ integrationAuthId}, "integrationAuthHerokuPipelines"] as const,
getIntegrationAuthRailwayEnvironments: ({
integrationAuthId,
appId
@ -289,6 +292,20 @@ const fetchIntegrationAuthQoveryScopes = async ({
return undefined;
};
const fetchIntegrationAuthHerokuPipelines = async ({ integrationAuthId }: {
integrationAuthId: string;
}) => {
const {
data: { pipelines }
} = await apiRequest.get<{ pipelines: HerokuPipelineCoupling[] }>(
`/api/v1/integration-auth/${integrationAuthId}/heroku/pipelines`
);
console.log(99999, pipelines)
return pipelines;
};
const fetchIntegrationAuthRailwayEnvironments = async ({
integrationAuthId,
appId
@ -540,6 +557,23 @@ export const useGetIntegrationAuthQoveryScopes = ({
});
};
export const useGetIntegrationAuthHerokuPipelines = ({
integrationAuthId
}: {
integrationAuthId: string;
}) => {
return useQuery({
queryKey: integrationAuthKeys.getIntegrationAuthHerokuPipelines({
integrationAuthId
}),
queryFn: () =>
fetchIntegrationAuthHerokuPipelines({
integrationAuthId
}),
enabled: true
});
};
export const useGetIntegrationAuthRailwayEnvironments = ({
integrationAuthId,
appId

View File

@ -17,6 +17,17 @@ export type App = {
secretGroups?: string[];
};
export type Pipeline = {
pipelineId: string;
name: string;
};
export type HerokuPipelineCoupling = {
app: { appId: string };
stage: string;
pipeline: { pipelineId: string; name: string };
};
export type Team = {
name: string;
teamId: string;

View File

@ -7,7 +7,10 @@ import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@for
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import { RadioGroup } from "@app/components/v2/RadioGroup";
import { useCreateIntegration } from "@app/hooks/api";
import { useGetIntegrationAuthHerokuPipelines } from "@app/hooks/api/integrationAuth/queries";
import { App, Pipeline } from "@app/hooks/api/integrationAuth/types";
import {
Button,
@ -22,11 +25,12 @@ import {
useGetIntegrationAuthApps,
useGetIntegrationAuthById
} from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace";
import { useCreateWsEnvironment, useGetWorkspaceById } from "../../../hooks/api/workspace";
export default function HerokuCreateIntegrationPage() {
const router = useRouter();
const { mutateAsync } = useCreateIntegration();
const { mutateAsync: mutateAsyncEnv } = useCreateWsEnvironment();
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
@ -36,9 +40,17 @@ export default function HerokuCreateIntegrationPage() {
integrationAuthId: (integrationAuthId as string) ?? ""
});
const { data: integrationAuthPipelineCouplings } = useGetIntegrationAuthHerokuPipelines({
integrationAuthId: (integrationAuthId as string) ?? ""
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [uniquePipelines, setUniquePipelines] = useState<Pipeline[]>();
const [selectedPipeline, setSelectedPipeline] = useState("");
const [selectedPipelineApps, setSelectedPipelineApps] = useState<App[]>();
const [targetApp, setTargetApp] = useState("");
const [secretPath, setSecretPath] = useState("/");
const [integrationType, setIntegrationType] = useState("App");
const [isLoading, setIsLoading] = useState(false);
@ -48,6 +60,36 @@ export default function HerokuCreateIntegrationPage() {
}
}, [workspace]);
useEffect(() => {
if (integrationAuthPipelineCouplings) {
const uniquePipelinesConst = Array.from(
new Set(
integrationAuthPipelineCouplings
.map(({ pipeline: { pipelineId, name } }) => ({
name,
pipelineId
}))
.map((obj) => JSON.stringify(obj))
)).map((str) => JSON.parse(str)) as { pipelineId: string; name: string }[]
setUniquePipelines(uniquePipelinesConst);
if (uniquePipelinesConst) {
if (uniquePipelinesConst!.length > 0) {
setSelectedPipeline(uniquePipelinesConst![0].name);
} else {
setSelectedPipeline("none");
}
}
}
}, [integrationAuthPipelineCouplings]);
useEffect(() => {
if (integrationAuthPipelineCouplings) {
setSelectedPipelineApps(integrationAuthApps?.filter(app => integrationAuthPipelineCouplings
.filter((pipelineCoupling) => pipelineCoupling.pipeline.name === selectedPipeline)
.map(coupling => coupling.app.appId).includes(String(app.appId))))
}
}, [selectedPipeline]);
useEffect(() => {
if (integrationAuthApps) {
if (integrationAuthApps.length > 0) {
@ -64,13 +106,32 @@ export default function HerokuCreateIntegrationPage() {
if (!integrationAuth?.id) return;
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
app: targetApp,
sourceEnvironment: selectedSourceEnvironment,
secretPath
});
if (integrationType === "App") {
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
app: targetApp,
sourceEnvironment: selectedSourceEnvironment,
secretPath
});
} else if (integrationType === "Pipeline") {
selectedPipelineApps?.map(async (app, index) => {
setTimeout(async () => {
await mutateAsyncEnv({
workspaceId: String(localStorage.getItem("projectData.id")),
name: app.name,
slug: app.name.toLowerCase().replaceAll(" ", "-")
});
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
app: app.name,
sourceEnvironment: app.name.toLowerCase().replaceAll(" ", "-"),
secretPath
})
}, 1000*index)
})
}
setIsLoading(false);
router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
@ -118,6 +179,36 @@ export default function HerokuCreateIntegrationPage() {
</Link>
</div>
</CardTitle>
<RadioGroup
value={integrationType}
onValueChange={(val) => setIntegrationType(val)}
/>
{integrationType === "Pipeline" && <>
<FormControl label="Heroku Pipeline" className="px-6">
<Select
value={selectedPipeline}
onValueChange={(val) => setSelectedPipeline(val)}
className="w-full border border-mineshaft-500"
>
{uniquePipelines?.map((pipeline) => (
<SelectItem
value={pipeline.name}
key={`source-environment-${pipeline.name}`}
>
{pipeline.name}
</SelectItem>
))}
</Select>
</FormControl>
<div className="px-6 text-sm mb-4 inline-block text-bunker-300">
After creating the integration, the following Heroku apps will be automatically synced to Infisical:
<div className="flex flex-col">
{selectedPipelineApps?.map(app => <p key={app.name} className="text-bunker-200 pl-0.5 inline-flex"><span className="text-primary pr-1">-&gt;</span> {app.name}</p>)}
</div>
From then on, every new app in the selected pipeline will be synced to Infisical, too.
</div>
</>}
{integrationType === "App" && <>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
@ -163,7 +254,7 @@ export default function HerokuCreateIntegrationPage() {
</SelectItem>
)}
</Select>
</FormControl>
</FormControl></>}
<Button
onClick={handleButtonClick}
color="mineshaft"
@ -175,6 +266,7 @@ export default function HerokuCreateIntegrationPage() {
Create Integration
</Button>
</Card>
{integrationType === "App" && <>
<div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<div className="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<div className="flex flex-row items-center">
@ -185,7 +277,7 @@ export default function HerokuCreateIntegrationPage() {
After creating an integration, your secrets will start syncing immediately. This might
cause an unexpected override of current secrets in Heroku with secrets from Infisical.
</span>
</div>
</div></>}
</div>
) : (
<div className="flex h-full w-full items-center justify-center">

View File

@ -62,7 +62,7 @@ export const IntegrationsSection = ({
<Link href={`/project/${workspaceId}/settings`} passHref>
<a className="underline underline-offset-2">project settings </a>
</Link>
to re-enable it .
to re-enable it.
</AlertDescription>
</Alert>
</div>
@ -80,7 +80,7 @@ export const IntegrationsSection = ({
<div className="flex flex-col space-y-4 p-6 pt-0">
{integrations?.map((integration) => (
<div
className="max-w-8xl flex justify-between rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 pb-2"
className="max-w-8xl flex justify-between rounded-md border border-mineshaft-600 bg-mineshaft-800 p-3 pb-0"
key={`integration-${integration?.id.toString()}`}
>
<div className="flex">

603
package-lock.json generated
View File

@ -6,12 +6,26 @@
"": {
"name": "infisical",
"license": "ISC",
"dependencies": {
"@radix-ui/react-radio-group": "^1.1.3"
},
"devDependencies": {
"@types/uuid": "^9.0.7",
"eslint": "^8.29.0",
"husky": "^8.0.3"
}
},
"node_modules/@babel/runtime": {
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
"integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@eslint/eslintrc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
@ -103,6 +117,324 @@
"node": ">= 8"
}
},
"node_modules/@radix-ui/primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
"integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==",
"dependencies": {
"@babel/runtime": "^7.13.10"
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
"integrity": "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
"integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-context": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz",
"integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
"integrity": "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-id": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz",
"integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-presence": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz",
"integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-primitive": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz",
"integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-radio-group": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.1.3.tgz",
"integrity": "sha512-x+yELayyefNeKeTx4fjK6j99Fs6c4qKm3aY38G3swQVTN6xMpsrbigC0uHs2L//g8q4qR7qOcww8430jJmi2ag==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-roving-focus": "1.0.4",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-previous": "1.0.1",
"@radix-ui/react-use-size": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",
"integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
"integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
"integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz",
"integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-callback-ref": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz",
"integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-previous": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz",
"integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-size": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz",
"integrity": "sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@types/uuid": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
@ -719,6 +1051,12 @@
"url": "https://opencollective.com/js-sdsl"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"peer": true
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@ -777,6 +1115,18 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -934,6 +1284,36 @@
}
]
},
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
},
"peerDependencies": {
"react": "^18.2.0"
}
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/regexpp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@ -1003,6 +1383,15 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -1143,6 +1532,14 @@
}
},
"dependencies": {
"@babel/runtime": {
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
"integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
"requires": {
"regenerator-runtime": "^0.14.0"
}
},
"@eslint/eslintrc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
@ -1209,6 +1606,164 @@
"fastq": "^1.6.0"
}
},
"@radix-ui/primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
"integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-collection": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
"integrity": "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2"
}
},
"@radix-ui/react-compose-refs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
"integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-context": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz",
"integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-direction": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
"integrity": "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-id": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz",
"integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.1"
}
},
"@radix-ui/react-presence": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz",
"integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1"
}
},
"@radix-ui/react-primitive": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz",
"integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.2"
}
},
"@radix-ui/react-radio-group": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.1.3.tgz",
"integrity": "sha512-x+yELayyefNeKeTx4fjK6j99Fs6c4qKm3aY38G3swQVTN6xMpsrbigC0uHs2L//g8q4qR7qOcww8430jJmi2ag==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-roving-focus": "1.0.4",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-previous": "1.0.1",
"@radix-ui/react-use-size": "1.0.1"
}
},
"@radix-ui/react-roving-focus": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",
"integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.1"
}
},
"@radix-ui/react-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
"integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1"
}
},
"@radix-ui/react-use-callback-ref": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
"integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-use-controllable-state": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz",
"integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-callback-ref": "1.0.1"
}
},
"@radix-ui/react-use-layout-effect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz",
"integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-use-previous": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz",
"integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-use-size": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz",
"integrity": "sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.1"
}
},
"@types/uuid": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
@ -1665,6 +2220,12 @@
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
"dev": true
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"peer": true
},
"js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@ -1711,6 +2272,15 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -1818,6 +2388,30 @@
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true
},
"react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"peer": true,
"requires": {
"loose-envify": "^1.1.0"
}
},
"react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"peer": true,
"requires": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
}
},
"regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"regexpp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@ -1854,6 +2448,15 @@
"queue-microtask": "^1.2.2"
}
},
"scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
"peer": true,
"requires": {
"loose-envify": "^1.1.0"
}
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",

View File

@ -22,5 +22,8 @@
"@types/uuid": "^9.0.7",
"eslint": "^8.29.0",
"husky": "^8.0.3"
},
"dependencies": {
"@radix-ui/react-radio-group": "^1.1.3"
}
}