mirror of
https://github.com/StanGirard/quivr.git
synced 2024-11-23 21:22:35 +03:00
[ShareableBrain] User email and role inputs form (#608)
* feat: add invitation emails form * test(ShareBrain): add tests
This commit is contained in:
parent
cef45ea712
commit
783f8dea76
@ -1,28 +1,16 @@
|
|||||||
import { UUID } from "crypto";
|
import { UUID } from "crypto";
|
||||||
import { MdDelete } from "react-icons/md";
|
|
||||||
|
|
||||||
import Button from "@/lib/components/ui/Button";
|
import { DeleteBrain, ShareBrain } from "./components";
|
||||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
|
||||||
|
|
||||||
import { ShareBrain } from "./ShareBrain";
|
|
||||||
|
|
||||||
type BrainActionsProps = {
|
type BrainActionsProps = {
|
||||||
brainId: UUID;
|
brainId: UUID;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BrainActions = ({ brainId }: BrainActionsProps): JSX.Element => {
|
export const BrainActions = ({ brainId }: BrainActionsProps): JSX.Element => {
|
||||||
const { deleteBrain } = useBrainContext();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute right-0 flex flex-row">
|
<div className="absolute right-0 flex flex-row">
|
||||||
<ShareBrain brainId={brainId} />
|
<ShareBrain brainId={brainId} />
|
||||||
<Button
|
<DeleteBrain brainId={brainId} />
|
||||||
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
|
|
||||||
onClick={() => void deleteBrain(brainId)}
|
|
||||||
variant={"tertiary"}
|
|
||||||
>
|
|
||||||
<MdDelete className="text-xl" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
import { UUID } from "crypto";
|
|
||||||
import { MdContentPaste, MdShare } from "react-icons/md";
|
|
||||||
|
|
||||||
import Button from "@/lib/components/ui/Button";
|
|
||||||
import Modal from "@/lib/components/ui/Modal";
|
|
||||||
import { useToast } from "@/lib/hooks";
|
|
||||||
|
|
||||||
type ShareBrainModalProps = {
|
|
||||||
brainId: UUID;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ShareBrain = ({ brainId }: ShareBrainModalProps): JSX.Element => {
|
|
||||||
const { publish } = useToast();
|
|
||||||
|
|
||||||
const baseUrl = window.location.origin;
|
|
||||||
const brainShareLink = `${baseUrl}/brain_subscription_invitation=${brainId}`;
|
|
||||||
|
|
||||||
const handleCopyInvitationLink = async () => {
|
|
||||||
await navigator.clipboard.writeText(brainShareLink);
|
|
||||||
publish({
|
|
||||||
variant: "success",
|
|
||||||
text: "Copied to clipboard",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
Trigger={
|
|
||||||
<Button
|
|
||||||
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
|
|
||||||
onClick={() => void 0}
|
|
||||||
variant={"tertiary"}
|
|
||||||
>
|
|
||||||
<MdShare className="text-xl" />
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
title="Share brain"
|
|
||||||
>
|
|
||||||
<div className="flex flex-row align-center my-5">
|
|
||||||
<p>{brainShareLink}</p>
|
|
||||||
<Button onClick={() => void handleCopyInvitationLink()}>
|
|
||||||
<MdContentPaste />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
@ -0,0 +1,19 @@
|
|||||||
|
import { UUID } from "crypto";
|
||||||
|
import { MdDelete } from "react-icons/md";
|
||||||
|
|
||||||
|
import Button from "@/lib/components/ui/Button";
|
||||||
|
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||||
|
|
||||||
|
export const DeleteBrain = ({ brainId }: { brainId: UUID }): JSX.Element => {
|
||||||
|
const { deleteBrain } = useBrainContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
|
||||||
|
onClick={() => void deleteBrain(brainId)}
|
||||||
|
variant={"tertiary"}
|
||||||
|
>
|
||||||
|
<MdDelete className="text-xl" />
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,97 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { UUID } from "crypto";
|
||||||
|
import { ImUserPlus } from "react-icons/im";
|
||||||
|
import { MdContentPaste, MdShare } from "react-icons/md";
|
||||||
|
|
||||||
|
import Button from "@/lib/components/ui/Button";
|
||||||
|
import Modal from "@/lib/components/ui/Modal";
|
||||||
|
|
||||||
|
import { InvitedUserRow } from "./components/InvitedUserRow";
|
||||||
|
import { useShareBrain } from "./hooks/useShareBrain";
|
||||||
|
|
||||||
|
type ShareBrainModalProps = {
|
||||||
|
brainId: UUID;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ShareBrain = ({ brainId }: ShareBrainModalProps): JSX.Element => {
|
||||||
|
const {
|
||||||
|
roleAssignations,
|
||||||
|
brainShareLink,
|
||||||
|
handleCopyInvitationLink,
|
||||||
|
updateRoleAssignation,
|
||||||
|
removeRoleAssignation,
|
||||||
|
inviteUsers,
|
||||||
|
addNewRoleAssignationRole,
|
||||||
|
} = useShareBrain(brainId);
|
||||||
|
|
||||||
|
const canAddNewRow =
|
||||||
|
roleAssignations.length === 0 ||
|
||||||
|
roleAssignations.filter((invitingUser) => invitingUser.email === "")
|
||||||
|
.length === 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
Trigger={
|
||||||
|
<Button
|
||||||
|
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
|
||||||
|
onClick={() => void 0}
|
||||||
|
variant={"tertiary"}
|
||||||
|
data-testId="share-brain-button"
|
||||||
|
>
|
||||||
|
<MdShare className="text-xl" />
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
CloseTrigger={<div />}
|
||||||
|
title="Share brain"
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
onSubmit={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
void inviteUsers();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="flex flex-row align-center my-5">
|
||||||
|
<div className="flex bg-gray-100 p-3 rounded flex-1 flex-row border-b border-gray-200 dark:border-gray-700 justify-space-between align-center">
|
||||||
|
<div className="flex flex-1 overflow-hidden">
|
||||||
|
<p className="flex-1 color-gray-500">{brainShareLink}</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => void handleCopyInvitationLink()}
|
||||||
|
>
|
||||||
|
<MdContentPaste />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-gray-100 h-0.5 mb-5 border-gray-200 dark:border-gray-700" />
|
||||||
|
|
||||||
|
{roleAssignations.map((roleAssignation, index) => (
|
||||||
|
<InvitedUserRow
|
||||||
|
key={roleAssignation.id}
|
||||||
|
onChange={updateRoleAssignation(index)}
|
||||||
|
removeCurrentInvitation={removeRoleAssignation(index)}
|
||||||
|
roleAssignation={roleAssignation}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<Button
|
||||||
|
className="my-5"
|
||||||
|
onClick={addNewRoleAssignationRole}
|
||||||
|
disabled={!canAddNewRow}
|
||||||
|
data-testid="add-new-row-role-button"
|
||||||
|
>
|
||||||
|
<ImUserPlus />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-3 flex flex-row justify-end">
|
||||||
|
<Button disabled={roleAssignations.length === 0} type="submit">
|
||||||
|
Share
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,50 @@
|
|||||||
|
import { fireEvent, render } from "@testing-library/react";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { ShareBrain } from "../ShareBrain";
|
||||||
|
|
||||||
|
describe("ShareBrain", () => {
|
||||||
|
it("should render ShareBrain component properly", () => {
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<ShareBrain brainId="cf9bb422-b1b6-4fd7-abc1-01bd395d2318" />
|
||||||
|
);
|
||||||
|
const shareButton = getByTestId("share-brain-button");
|
||||||
|
expect(shareButton).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render open share modal when share button is clicked", () => {
|
||||||
|
const { getByText, getByTestId } = render(
|
||||||
|
<ShareBrain brainId="cf9bb422-b1b6-4fd7-abc1-01bd395d2318" />
|
||||||
|
);
|
||||||
|
const shareButton = getByTestId("share-brain-button");
|
||||||
|
fireEvent.click(shareButton);
|
||||||
|
expect(getByText("Share brain")).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shoud add new user row when "Add new user" button is clicked and only where there is no empty field', async () => {
|
||||||
|
const { getByTestId, findAllByTestId } = render(
|
||||||
|
<ShareBrain brainId="cf9bb422-b1b6-4fd7-abc1-01bd395d2318" />
|
||||||
|
);
|
||||||
|
const shareButton = getByTestId("share-brain-button");
|
||||||
|
fireEvent.click(shareButton);
|
||||||
|
|
||||||
|
let assignationRows = await findAllByTestId("assignation-row");
|
||||||
|
|
||||||
|
expect(assignationRows.length).toBe(1);
|
||||||
|
|
||||||
|
const firstAssignationRowEmailInput = (
|
||||||
|
await findAllByTestId("role-assignation-email-input")
|
||||||
|
)[0];
|
||||||
|
|
||||||
|
fireEvent.change(firstAssignationRowEmailInput, {
|
||||||
|
target: { value: "user@quivr.app" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const addNewRoleAssignationButton = getByTestId("add-new-row-role-button");
|
||||||
|
fireEvent.click(addNewRoleAssignationButton);
|
||||||
|
|
||||||
|
assignationRows = await findAllByTestId("assignation-row");
|
||||||
|
|
||||||
|
expect(assignationRows.length).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,69 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { MdOutlineRemoveCircle } from "react-icons/md";
|
||||||
|
|
||||||
|
import Field from "@/lib/components/ui/Field";
|
||||||
|
import { Select } from "@/lib/components/ui/Select";
|
||||||
|
|
||||||
|
import { BrainRoleAssignation, BrainRoleType } from "../../../types";
|
||||||
|
|
||||||
|
type AddUserRowProps = {
|
||||||
|
onChange: (newRole: BrainRoleAssignation) => void;
|
||||||
|
removeCurrentInvitation?: () => void;
|
||||||
|
roleAssignation: BrainRoleAssignation;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectOptionsProps = {
|
||||||
|
label: string;
|
||||||
|
value: BrainRoleType;
|
||||||
|
};
|
||||||
|
const SelectOptions: SelectOptionsProps[] = [
|
||||||
|
{ label: "Viewer", value: "viewer" },
|
||||||
|
{ label: "Editor", value: "editor" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const InvitedUserRow = ({
|
||||||
|
onChange,
|
||||||
|
removeCurrentInvitation,
|
||||||
|
roleAssignation,
|
||||||
|
}: AddUserRowProps): JSX.Element => {
|
||||||
|
const [selectedRole, setSelectedRole] = useState<BrainRoleType>(
|
||||||
|
roleAssignation.role
|
||||||
|
);
|
||||||
|
const [email, setEmail] = useState(roleAssignation.email);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onChange({
|
||||||
|
...roleAssignation,
|
||||||
|
email,
|
||||||
|
role: selectedRole,
|
||||||
|
});
|
||||||
|
}, [email, selectedRole]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-testid="assignation-row"
|
||||||
|
className="flex flex-row align-center my-2 gap-3 items-center"
|
||||||
|
>
|
||||||
|
<div className="cursor-pointer" onClick={removeCurrentInvitation}>
|
||||||
|
<MdOutlineRemoveCircle />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-1">
|
||||||
|
<Field
|
||||||
|
name="email"
|
||||||
|
required
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
value={email}
|
||||||
|
onBlur={() => email === "" && removeCurrentInvitation?.()}
|
||||||
|
data-testid="role-assignation-email-input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
onChange={setSelectedRole}
|
||||||
|
value={selectedRole}
|
||||||
|
options={SelectOptions}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from "./InvitedUserRow";
|
@ -0,0 +1,83 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { useToast } from "@/lib/hooks";
|
||||||
|
|
||||||
|
import { BrainRoleAssignation } from "../../../types";
|
||||||
|
import { generateBrainAssignation } from "../utils/generateBrainAssignation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
export const useShareBrain = (brainId: string) => {
|
||||||
|
const baseUrl = window.location.origin;
|
||||||
|
const { publish } = useToast();
|
||||||
|
|
||||||
|
const brainShareLink = `${baseUrl}/brain_subscription_invitation=${brainId}`;
|
||||||
|
|
||||||
|
const [roleAssignations, setRoleAssignation] = useState<
|
||||||
|
BrainRoleAssignation[]
|
||||||
|
>([generateBrainAssignation()]);
|
||||||
|
|
||||||
|
const handleCopyInvitationLink = async () => {
|
||||||
|
await navigator.clipboard.writeText(brainShareLink);
|
||||||
|
publish({
|
||||||
|
variant: "success",
|
||||||
|
text: "Copied to clipboard",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeRoleAssignation = (assignationIndex: number) => () => {
|
||||||
|
if (roleAssignations.length === 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setRoleAssignation(
|
||||||
|
roleAssignations.filter((_, index) => index !== assignationIndex)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateRoleAssignation =
|
||||||
|
(rowIndex: number) => (data: BrainRoleAssignation) => {
|
||||||
|
const concernedRow = roleAssignations[rowIndex];
|
||||||
|
|
||||||
|
if (concernedRow !== undefined) {
|
||||||
|
setRoleAssignation(
|
||||||
|
roleAssignations.map((row, index) => {
|
||||||
|
if (index === rowIndex) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return row;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setRoleAssignation([...roleAssignations, data]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const inviteUsers = (): void => {
|
||||||
|
const inviteUsersPayload = roleAssignations
|
||||||
|
.filter(({ email }) => email !== "")
|
||||||
|
.map((assignation) => ({
|
||||||
|
email: assignation.email,
|
||||||
|
role: assignation.role,
|
||||||
|
}));
|
||||||
|
|
||||||
|
alert(
|
||||||
|
`You will soon be able to invite ${JSON.stringify(
|
||||||
|
inviteUsersPayload
|
||||||
|
)}. Wait a bit`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addNewRoleAssignationRole = () => {
|
||||||
|
setRoleAssignation([...roleAssignations, generateBrainAssignation()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
roleAssignations,
|
||||||
|
brainShareLink,
|
||||||
|
handleCopyInvitationLink,
|
||||||
|
updateRoleAssignation,
|
||||||
|
removeRoleAssignation,
|
||||||
|
inviteUsers,
|
||||||
|
addNewRoleAssignationRole,
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from "./ShareBrain";
|
@ -0,0 +1,9 @@
|
|||||||
|
import { BrainRoleAssignation } from "../../../types";
|
||||||
|
|
||||||
|
export const generateBrainAssignation = (): BrainRoleAssignation => {
|
||||||
|
return {
|
||||||
|
email: "",
|
||||||
|
role: "viewer",
|
||||||
|
id: Math.random().toString(),
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./DeleteBrain";
|
||||||
|
export * from "./ShareBrain";
|
@ -0,0 +1,9 @@
|
|||||||
|
export const roles = ["viewer", "editor"];
|
||||||
|
|
||||||
|
export type BrainRoleType = (typeof roles)[number];
|
||||||
|
|
||||||
|
export type BrainRoleAssignation = {
|
||||||
|
email: string;
|
||||||
|
role: BrainRoleType;
|
||||||
|
id: string;
|
||||||
|
};
|
96
frontend/lib/components/ui/Select.tsx
Normal file
96
frontend/lib/components/ui/Select.tsx
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/* eslint-disable max-lines */
|
||||||
|
import { BsCheckCircleFill } from "react-icons/bs";
|
||||||
|
|
||||||
|
import Popover from "@/lib/components/ui/Popover";
|
||||||
|
|
||||||
|
type SelectOptionProps = {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectProps = {
|
||||||
|
options: SelectOptionProps[];
|
||||||
|
value?: SelectOptionProps["value"];
|
||||||
|
onChange: (option: SelectOptionProps["value"]) => void;
|
||||||
|
label?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedStyle = "rounded-lg bg-black text-white";
|
||||||
|
|
||||||
|
export const Select = ({
|
||||||
|
onChange,
|
||||||
|
options,
|
||||||
|
value,
|
||||||
|
label,
|
||||||
|
}: SelectProps): JSX.Element => {
|
||||||
|
const selectedValueLabel = options.find(
|
||||||
|
(option) => option.value === value
|
||||||
|
)?.label;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{label !== undefined && (
|
||||||
|
<label
|
||||||
|
id="listbox-label"
|
||||||
|
className="block text-sm font-medium leading-6 text-gray-900 mb-2"
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
<div className="relative">
|
||||||
|
<Popover
|
||||||
|
Trigger={
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="relative w-full cursor-default rounded-md bg-white py-1.5 pl-3 pr-10 text-left text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm sm:leading-6"
|
||||||
|
aria-haspopup="listbox"
|
||||||
|
>
|
||||||
|
<span className="flex items-center">
|
||||||
|
<span className="ml-3 block truncate">
|
||||||
|
{selectedValueLabel ?? label ?? "Select"}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span className="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2">
|
||||||
|
<svg
|
||||||
|
className="h-5 w-5 text-gray-400"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
CloseTrigger={<div />}
|
||||||
|
>
|
||||||
|
<ul role="listbox">
|
||||||
|
{options.map((option) => (
|
||||||
|
<li
|
||||||
|
className="text-gray-900 relative cursor-pointer select-none py-2"
|
||||||
|
id="listbox-option-0"
|
||||||
|
key={option.value}
|
||||||
|
onClick={() => onChange(option.value)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`flex items-center px-3 py-2 ${
|
||||||
|
value === option.value && selectedStyle
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span className="font-bold block truncate mr-2">
|
||||||
|
{option.label}
|
||||||
|
</span>
|
||||||
|
{value === option.value && <BsCheckCircleFill />}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -22,6 +22,7 @@
|
|||||||
"@june-so/analytics-next": "^2.0.0",
|
"@june-so/analytics-next": "^2.0.0",
|
||||||
"@radix-ui/react-dialog": "^1.0.3",
|
"@radix-ui/react-dialog": "^1.0.3",
|
||||||
"@radix-ui/react-popover": "^1.0.6",
|
"@radix-ui/react-popover": "^1.0.6",
|
||||||
|
"@radix-ui/react-select": "^1.2.2",
|
||||||
"@radix-ui/react-toast": "^1.1.3",
|
"@radix-ui/react-toast": "^1.1.3",
|
||||||
"@radix-ui/react-tooltip": "^1.0.6",
|
"@radix-ui/react-tooltip": "^1.0.6",
|
||||||
"@sentry/nextjs": "^7.57.0",
|
"@sentry/nextjs": "^7.57.0",
|
||||||
|
@ -742,6 +742,13 @@
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
tslib "^2.5.0"
|
tslib "^2.5.0"
|
||||||
|
|
||||||
|
"@radix-ui/number@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.1.tgz#644161a3557f46ed38a042acf4a770e826021674"
|
||||||
|
integrity sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/primitive@1.0.1":
|
"@radix-ui/primitive@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
|
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
|
||||||
@ -803,6 +810,13 @@
|
|||||||
aria-hidden "^1.1.1"
|
aria-hidden "^1.1.1"
|
||||||
react-remove-scroll "2.5.5"
|
react-remove-scroll "2.5.5"
|
||||||
|
|
||||||
|
"@radix-ui/react-direction@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"
|
||||||
|
integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-dismissable-layer@1.0.4":
|
"@radix-ui/react-dismissable-layer@1.0.4":
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz#883a48f5f938fa679427aa17fcba70c5494c6978"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz#883a48f5f938fa679427aa17fcba70c5494c6978"
|
||||||
@ -904,6 +918,34 @@
|
|||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-slot" "1.0.2"
|
"@radix-ui/react-slot" "1.0.2"
|
||||||
|
|
||||||
|
"@radix-ui/react-select@^1.2.2":
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-1.2.2.tgz#caa981fa0d672cf3c1b2a5240135524e69b32181"
|
||||||
|
integrity sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/number" "1.0.1"
|
||||||
|
"@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-dismissable-layer" "1.0.4"
|
||||||
|
"@radix-ui/react-focus-guards" "1.0.1"
|
||||||
|
"@radix-ui/react-focus-scope" "1.0.3"
|
||||||
|
"@radix-ui/react-id" "1.0.1"
|
||||||
|
"@radix-ui/react-popper" "1.1.2"
|
||||||
|
"@radix-ui/react-portal" "1.0.3"
|
||||||
|
"@radix-ui/react-primitive" "1.0.3"
|
||||||
|
"@radix-ui/react-slot" "1.0.2"
|
||||||
|
"@radix-ui/react-use-callback-ref" "1.0.1"
|
||||||
|
"@radix-ui/react-use-controllable-state" "1.0.1"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.0.1"
|
||||||
|
"@radix-ui/react-use-previous" "1.0.1"
|
||||||
|
"@radix-ui/react-visually-hidden" "1.0.3"
|
||||||
|
aria-hidden "^1.1.1"
|
||||||
|
react-remove-scroll "2.5.5"
|
||||||
|
|
||||||
"@radix-ui/react-slot@1.0.2":
|
"@radix-ui/react-slot@1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
||||||
@ -980,6 +1022,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-previous@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66"
|
||||||
|
integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-use-rect@1.0.1":
|
"@radix-ui/react-use-rect@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2"
|
||||||
|
Loading…
Reference in New Issue
Block a user