mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 20:35:24 +00:00
Organization switching & active org management (#173)
This commit is contained in:
parent
738bbaad30
commit
9c120c6b0a
21 changed files with 1115 additions and 6 deletions
|
|
@ -0,0 +1,18 @@
|
|||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_UserToOrg" (
|
||||
"joinedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"orgId" INTEGER NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"role" TEXT NOT NULL DEFAULT 'MEMBER',
|
||||
|
||||
PRIMARY KEY ("orgId", "userId"),
|
||||
CONSTRAINT "UserToOrg_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "Org" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "UserToOrg_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_UserToOrg" ("joinedAt", "orgId", "userId") SELECT "joinedAt", "orgId", "userId" FROM "UserToOrg";
|
||||
DROP TABLE "UserToOrg";
|
||||
ALTER TABLE "new_UserToOrg" RENAME TO "UserToOrg";
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "activeOrgId" INTEGER;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Repo" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"name" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
"indexedAt" DATETIME,
|
||||
"isFork" BOOLEAN NOT NULL,
|
||||
"isArchived" BOOLEAN NOT NULL,
|
||||
"metadata" JSONB NOT NULL,
|
||||
"cloneUrl" TEXT NOT NULL,
|
||||
"tenantId" INTEGER NOT NULL,
|
||||
"repoIndexingStatus" TEXT NOT NULL DEFAULT 'NEW',
|
||||
"external_id" TEXT NOT NULL,
|
||||
"external_codeHostType" TEXT NOT NULL,
|
||||
"external_codeHostUrl" TEXT NOT NULL,
|
||||
"orgId" INTEGER,
|
||||
CONSTRAINT "Repo_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "Org" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Repo" ("cloneUrl", "createdAt", "external_codeHostType", "external_codeHostUrl", "external_id", "id", "indexedAt", "isArchived", "isFork", "metadata", "name", "repoIndexingStatus", "tenantId", "updatedAt") SELECT "cloneUrl", "createdAt", "external_codeHostType", "external_codeHostUrl", "external_id", "id", "indexedAt", "isArchived", "isFork", "metadata", "name", "repoIndexingStatus", "tenantId", "updatedAt" FROM "Repo";
|
||||
DROP TABLE "Repo";
|
||||
ALTER TABLE "new_Repo" RENAME TO "Repo";
|
||||
CREATE UNIQUE INDEX "Repo_external_id_external_codeHostUrl_key" ON "Repo"("external_id", "external_codeHostUrl");
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
|
|
@ -47,6 +47,9 @@ model Repo {
|
|||
// The base url of the external service (e.g., https://github.com)
|
||||
external_codeHostUrl String
|
||||
|
||||
org Org? @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
orgId Int?
|
||||
|
||||
@@unique([external_id, external_codeHostUrl])
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +74,12 @@ model Org {
|
|||
updatedAt DateTime @updatedAt
|
||||
members UserToOrg[]
|
||||
configs Config[]
|
||||
repos Repo[]
|
||||
}
|
||||
|
||||
enum OrgRole {
|
||||
OWNER
|
||||
MEMBER
|
||||
}
|
||||
|
||||
model UserToOrg {
|
||||
|
|
@ -84,18 +93,21 @@ model UserToOrg {
|
|||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
|
||||
role OrgRole @default(MEMBER)
|
||||
|
||||
@@id([orgId, userId])
|
||||
}
|
||||
|
||||
// @see : https://authjs.dev/concepts/database-models#user
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
accounts Account[]
|
||||
orgs UserToOrg[]
|
||||
activeOrgId Int?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
"@iconify/react": "^5.1.0",
|
||||
"@iizukak/codemirror-lang-wgsl": "^0.3.0",
|
||||
"@radix-ui/react-avatar": "^1.1.2",
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
|
|
@ -69,6 +70,7 @@
|
|||
"client-only": "^0.0.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cm6-graphql": "^0.2.0",
|
||||
"cmdk": "1.0.0",
|
||||
"codemirror": "^5.65.3",
|
||||
"codemirror-lang-brainfuck": "^0.1.0",
|
||||
"codemirror-lang-elixir": "^4.0.0",
|
||||
|
|
@ -110,6 +112,7 @@
|
|||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sourcebot/db": "^0.1.0",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
|
|
@ -122,10 +125,9 @@
|
|||
"jsdom": "^25.0.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8",
|
||||
"@sourcebot/db": "^0.1.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5",
|
||||
"vite-tsconfig-paths": "^5.1.3",
|
||||
"vitest": "^2.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
packages/web/public/placeholder_avatar.png
Normal file
BIN
packages/web/public/placeholder_avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
64
packages/web/src/actions.ts
Normal file
64
packages/web/src/actions.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
'use server';
|
||||
|
||||
import { auth } from "./auth";
|
||||
import { notAuthenticated, notFound } from "./lib/serviceError";
|
||||
import { prisma } from "@/prisma";
|
||||
|
||||
|
||||
export const createOrg = async (name: string) => {
|
||||
const session = await auth();
|
||||
if (!session) {
|
||||
return notAuthenticated();
|
||||
}
|
||||
|
||||
// Create the org
|
||||
const org = await prisma.org.create({
|
||||
data: {
|
||||
name,
|
||||
members: {
|
||||
create: {
|
||||
userId: session.user.id,
|
||||
role: "OWNER",
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id: org.id,
|
||||
}
|
||||
}
|
||||
|
||||
export const switchActiveOrg = async (orgId: number) => {
|
||||
const session = await auth();
|
||||
if (!session) {
|
||||
return notAuthenticated();
|
||||
}
|
||||
|
||||
// Check to see if the user is a member of the org
|
||||
const membership = await prisma.userToOrg.findUnique({
|
||||
where: {
|
||||
orgId_userId: {
|
||||
userId: session.user.id,
|
||||
orgId,
|
||||
}
|
||||
},
|
||||
});
|
||||
if (!membership) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
// Update the user's active org
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: session.user.id,
|
||||
},
|
||||
data: {
|
||||
activeOrgId: orgId,
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id: orgId,
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import logoLight from "../../../public/sb_logo_light_small.png";
|
|||
import { SettingsDropdown } from "./settingsDropdown";
|
||||
import { GitHubLogoIcon, DiscordLogoIcon } from "@radix-ui/react-icons";
|
||||
import { redirect } from "next/navigation";
|
||||
import { OrgSelector } from "./orgSelector";
|
||||
|
||||
const SOURCEBOT_DISCORD_URL = "https://discord.gg/6Fhp27x7Pb";
|
||||
const SOURCEBOT_GITHUB_URL = "https://github.com/sourcebot-dev/sourcebot";
|
||||
|
|
@ -36,6 +37,9 @@ export const NavigationMenu = async () => {
|
|||
/>
|
||||
</Link>
|
||||
|
||||
<OrgSelector />
|
||||
<Separator orientation="vertical" className="h-6 mx-2" />
|
||||
|
||||
<NavigationMenuBase>
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
|
|
|
|||
31
packages/web/src/app/components/orgSelector/index.tsx
Normal file
31
packages/web/src/app/components/orgSelector/index.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { auth } from "@/auth";
|
||||
import { getUser, getUserOrgs } from "../../data/user";
|
||||
import { OrgSelectorDropdown } from "./orgSelectorDropdown";
|
||||
|
||||
export const OrgSelector = async () => {
|
||||
const session = await auth();
|
||||
if (!session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await getUser(session.user.id);
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const orgs = await getUserOrgs(session.user.id);
|
||||
const activeOrg = orgs.find((org) => org.id === user.activeOrgId);
|
||||
if (!activeOrg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<OrgSelectorDropdown
|
||||
orgs={orgs.map((org) => ({
|
||||
name: org.name,
|
||||
id: org.id,
|
||||
}))}
|
||||
activeOrgId={activeOrg.id}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
'use client';
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { PlusCircledIcon } from "@radix-ui/react-icons";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string().min(2).max(40),
|
||||
});
|
||||
|
||||
|
||||
interface OrgCreationDialogProps {
|
||||
onSubmit: (data: z.infer<typeof formSchema>) => void;
|
||||
isOpen: boolean;
|
||||
onOpenChange: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
export const OrgCreationDialog = ({
|
||||
onSubmit,
|
||||
isOpen,
|
||||
onOpenChange,
|
||||
}: OrgCreationDialogProps) => {
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
name: "",
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<DropdownMenuItem
|
||||
onSelect={(e) => e.preventDefault()}
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="default"
|
||||
className="w-full justify-start gap-1.5 p-0"
|
||||
>
|
||||
<PlusCircledIcon className="h-5 w-5 text-muted-foreground" />
|
||||
Create organization
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create an organization</DialogTitle>
|
||||
<DialogDescription>Organizations allow you to collaborate with team members.</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Organization name</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button className="mt-5" type="submit">Submit</Button>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
36
packages/web/src/app/components/orgSelector/orgIcon.tsx
Normal file
36
packages/web/src/app/components/orgSelector/orgIcon.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { cn } from "@/lib/utils";
|
||||
import placeholderAvatar from "@/public/placeholder_avatar.png";
|
||||
import { cva } from "class-variance-authority";
|
||||
import Image from "next/image";
|
||||
|
||||
interface OrgIconProps {
|
||||
className?: string;
|
||||
size?: "default";
|
||||
}
|
||||
|
||||
const iconVariants = cva(
|
||||
"rounded-full",
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
default: "w-5 h-5"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "default"
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
export const OrgIcon = ({
|
||||
className,
|
||||
size,
|
||||
}: OrgIconProps) => {
|
||||
return (
|
||||
<Image
|
||||
src={placeholderAvatar}
|
||||
alt="Organization avatar"
|
||||
className={cn(iconVariants({ size, className }))}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
'use client';
|
||||
import { createOrg, switchActiveOrg } from "@/actions";
|
||||
import { useToast } from "@/components/hooks/use-toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { isServiceError } from "@/lib/utils";
|
||||
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { OrgCreationDialog } from "./orgCreationDialog";
|
||||
import { OrgIcon } from "./orgIcon";
|
||||
|
||||
|
||||
interface OrgSelectorDropdownProps {
|
||||
orgs: {
|
||||
name: string,
|
||||
id: number,
|
||||
}[],
|
||||
activeOrgId: number,
|
||||
}
|
||||
|
||||
export const OrgSelectorDropdown = ({
|
||||
orgs: _orgs,
|
||||
activeOrgId
|
||||
}: OrgSelectorDropdownProps) => {
|
||||
const [searchFilter, setSearchFilter] = useState("");
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
const [isCreateOrgDialogOpen, setIsCreateOrgDialogOpen] = useState(false);
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
|
||||
const activeOrg = _orgs.find((org) => org.id === activeOrgId)!;
|
||||
const orgs = useMemo(() => {
|
||||
// always place the active org at the top
|
||||
return [
|
||||
activeOrg,
|
||||
..._orgs.filter(org => org.id !== activeOrgId),
|
||||
];
|
||||
}, [_orgs, activeOrg, activeOrgId]);
|
||||
|
||||
const onSwitchOrg = useCallback((orgId: number, orgName: string) => {
|
||||
switchActiveOrg(orgId)
|
||||
.then((response) => {
|
||||
if (isServiceError(response)) {
|
||||
toast({
|
||||
description: `❌ Failed to switch organization. Reason: ${response.message}`,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
description: `✅ Switched to ${orgName}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
setIsDropdownOpen(false);
|
||||
// Necessary to refresh the server component.
|
||||
router.refresh();
|
||||
});
|
||||
}, [router, toast]);
|
||||
|
||||
const onCreateOrg = useCallback((name: string) => {
|
||||
createOrg(name)
|
||||
.then((response) => {
|
||||
if (isServiceError(response)) {
|
||||
throw response;
|
||||
}
|
||||
|
||||
return switchActiveOrg(response.id);
|
||||
})
|
||||
.then((response) => {
|
||||
if (isServiceError(response)) {
|
||||
throw response;
|
||||
}
|
||||
|
||||
toast({
|
||||
description: `✅ Organization '${name}' created successfully.`,
|
||||
});
|
||||
|
||||
setIsDropdownOpen(false);
|
||||
// Necessary to refresh the server component.
|
||||
router.refresh();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (isServiceError(error)) {
|
||||
toast({
|
||||
description: `❌ Failed to create organization. Reason: ${error.message}`,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setIsCreateOrgDialogOpen(false);
|
||||
});
|
||||
}, [router, toast]);
|
||||
|
||||
|
||||
return (
|
||||
/*
|
||||
We need to set `modal=false` to fix a issue with having a dialog menu inside of
|
||||
a dropdown menu.
|
||||
@see : https://github.com/radix-ui/primitives/issues/1836#issuecomment-1547607143
|
||||
*/
|
||||
<DropdownMenu
|
||||
modal={false}
|
||||
open={isDropdownOpen}
|
||||
onOpenChange={setIsDropdownOpen}
|
||||
>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="default">
|
||||
<OrgIcon className="mr-1.5" />
|
||||
<p className="font-medium text-sm mr-1">{activeOrg.name}</p>
|
||||
<CaretSortIcon className="h-5 w-5 font-medium" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-64">
|
||||
<DropdownMenuGroup>
|
||||
<Command>
|
||||
<CommandInput
|
||||
className="focus-visible:ring-transparent border-none w-full"
|
||||
placeholder="Search organizations..."
|
||||
value={searchFilter}
|
||||
onValueChange={(value) => setSearchFilter(value)}
|
||||
autoFocus={true}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty className="p-3 flex flex-col gap-3">
|
||||
<p className="text-sm">No organization found</p>
|
||||
<p className="text-sm text-muted-foreground">{`Your search term "${searchFilter}" did not match any organizations.`}</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={() => setSearchFilter("")}
|
||||
>
|
||||
Clear search
|
||||
</Button>
|
||||
</CommandEmpty>
|
||||
<CommandGroup
|
||||
heading="Organizations"
|
||||
className="flex max-h-80 flex-col overflow-y-auto"
|
||||
>
|
||||
{orgs.map((org, index) => (
|
||||
<CommandItem
|
||||
key={index}
|
||||
// Need to include org id to handle duplicates.
|
||||
value={`${org.name}-${org.id}`}
|
||||
className="w-full justify-between py-3 font-medium cursor-pointer"
|
||||
onSelect={() => onSwitchOrg(org.id, org.name)}
|
||||
>
|
||||
<div className="flex flex-row gap-1.5 items-center">
|
||||
<OrgIcon />
|
||||
{org.name}
|
||||
</div>
|
||||
{org.id === activeOrgId && (
|
||||
<CheckIcon className="h-5 w-5 text-muted-foreground" />
|
||||
)}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
|
||||
</Command>
|
||||
</DropdownMenuGroup>
|
||||
{searchFilter.length === 0 && (
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<OrgCreationDialog
|
||||
isOpen={isCreateOrgDialogOpen}
|
||||
onOpenChange={setIsCreateOrgDialogOpen}
|
||||
onSubmit={({ name }) => onCreateOrg(name)}
|
||||
/>
|
||||
</DropdownMenuGroup>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
26
packages/web/src/app/data/user.ts
Normal file
26
packages/web/src/app/data/user.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import 'server-only';
|
||||
import { prisma } from "@/prisma";
|
||||
|
||||
export const getUser = async (userId: string) => {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
});
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
export const getUserOrgs = async (userId: string) => {
|
||||
const orgs = await prisma.org.findMany({
|
||||
where: {
|
||||
members: {
|
||||
some: {
|
||||
userId: userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return orgs;
|
||||
}
|
||||
|
|
@ -1,9 +1,25 @@
|
|||
import NextAuth from "next-auth"
|
||||
import 'next-auth/jwt';
|
||||
import NextAuth, { User as AuthJsUser, DefaultSession } from "next-auth"
|
||||
import GitHub from "next-auth/providers/github"
|
||||
import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
import { prisma } from "@/prisma";
|
||||
import type { Provider } from "next-auth/providers"
|
||||
import { AUTH_GITHUB_CLIENT_ID, AUTH_GITHUB_CLIENT_SECRET, AUTH_SECRET } from "./lib/environment";
|
||||
import { User } from '@sourcebot/db';
|
||||
|
||||
declare module 'next-auth' {
|
||||
interface Session {
|
||||
user: {
|
||||
id: string;
|
||||
} & DefaultSession['user'];
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'next-auth/jwt' {
|
||||
interface JWT {
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
const providers: Provider[] = [
|
||||
GitHub({
|
||||
|
|
@ -24,6 +40,46 @@ export const providerMap = providers
|
|||
})
|
||||
.filter((provider) => provider.id !== "credentials");
|
||||
|
||||
const onCreateUser = async ({ user }: { user: AuthJsUser }) => {
|
||||
if (!user.id) {
|
||||
throw new Error("User ID is required.");
|
||||
}
|
||||
|
||||
const orgName = (() => {
|
||||
if (user.name) {
|
||||
return `${user.name}'s Org`;
|
||||
} else {
|
||||
return `Default Org`;
|
||||
}
|
||||
})();
|
||||
|
||||
await prisma.$transaction((async (tx) => {
|
||||
const org = await tx.org.create({
|
||||
data: {
|
||||
name: orgName,
|
||||
members: {
|
||||
create: {
|
||||
role: "OWNER",
|
||||
user: {
|
||||
connect: {
|
||||
id: user.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await tx.user.update({
|
||||
where: {
|
||||
id: user.id,
|
||||
},
|
||||
data: {
|
||||
activeOrgId: org.id,
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
secret: AUTH_SECRET,
|
||||
|
|
@ -31,8 +87,32 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
|||
session: {
|
||||
strategy: "jwt",
|
||||
},
|
||||
events: {
|
||||
createUser: onCreateUser,
|
||||
},
|
||||
callbacks: {
|
||||
async jwt({ token, user: _user }) {
|
||||
const user = _user as User | undefined;
|
||||
// @note: `user` will be available on signUp or signIn triggers.
|
||||
// Cache the userId in the JWT for later use.
|
||||
if (user) {
|
||||
token.userId = user.id;
|
||||
}
|
||||
return token;
|
||||
},
|
||||
async session({ session, token }) {
|
||||
// @WARNING: Anything stored in the session will be sent over
|
||||
// to the client.
|
||||
session.user = {
|
||||
...session.user,
|
||||
// Propogate the userId to the session.
|
||||
id: token.userId,
|
||||
}
|
||||
return session;
|
||||
}
|
||||
},
|
||||
providers: providers,
|
||||
pages: {
|
||||
signIn: "/login"
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
|
|||
153
packages/web/src/components/ui/command.tsx
Normal file
153
packages/web/src/components/ui/command.tsx
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import { Search } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
const CommandDialog = ({ children, ...props }: DialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty
|
||||
ref={ref}
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 h-px bg-border", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
122
packages/web/src/components/ui/dialog.tsx
Normal file
122
packages/web/src/components/ui/dialog.tsx
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal
|
||||
|
||||
const DialogClose = DialogPrimitive.Close
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogHeader.displayName = "DialogHeader"
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogClose,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
}
|
||||
|
|
@ -6,4 +6,5 @@ export enum ErrorCode {
|
|||
FILE_NOT_FOUND = 'FILE_NOT_FOUND',
|
||||
INVALID_REQUEST_BODY = 'INVALID_REQUEST_BODY',
|
||||
NOT_AUTHENTICATED = 'NOT_AUTHENTICATED',
|
||||
NOT_FOUND = 'NOT_FOUND',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,4 +75,12 @@ export const notAuthenticated = (): ServiceError => {
|
|||
errorCode: ErrorCode.NOT_AUTHENTICATED,
|
||||
message: "Not authenticated",
|
||||
}
|
||||
}
|
||||
|
||||
export const notFound = (): ServiceError => {
|
||||
return {
|
||||
statusCode: StatusCodes.NOT_FOUND,
|
||||
errorCode: ErrorCode.NOT_FOUND,
|
||||
message: "Not found",
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,9 @@ const defaultMiddleware = (req: NextAuthRequest) => {
|
|||
if (!req.auth && req.nextUrl.pathname !== "/login") {
|
||||
const newUrl = new URL("/login", req.nextUrl.origin);
|
||||
return NextResponse.redirect(newUrl);
|
||||
} else if (req.auth && req.nextUrl.pathname === "/login") {
|
||||
const newUrl = new URL("/", req.nextUrl.origin);
|
||||
return NextResponse.redirect(newUrl);
|
||||
}
|
||||
|
||||
return NextResponse.next();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'server-only';
|
||||
import { PrismaClient } from "@sourcebot/db";
|
||||
|
||||
// @see: https://authjs.dev/getting-started/adapters/prisma
|
||||
|
|
|
|||
263
yarn.lock
263
yarn.lock
|
|
@ -47,6 +47,13 @@
|
|||
dependencies:
|
||||
"@auth/core" "0.37.4"
|
||||
|
||||
"@babel/runtime@^7.13.10":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
|
||||
integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/runtime@^7.18.6":
|
||||
version "7.25.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.7.tgz#7ffb53c37a8f247c8c4d335e89cdf16a2e0d0fb6"
|
||||
|
|
@ -1357,11 +1364,23 @@
|
|||
resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.0.tgz#1e95610461a09cdf8bb05c152e76ca1278d5da46"
|
||||
integrity sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==
|
||||
|
||||
"@radix-ui/primitive@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
|
||||
integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/primitive@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2"
|
||||
integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==
|
||||
|
||||
"@radix-ui/primitive@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.1.tgz#fc169732d755c7fbad33ba8d0cd7fd10c90dc8e3"
|
||||
integrity sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==
|
||||
|
||||
"@radix-ui/react-arrow@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz#744f388182d360b86285217e43b6c63633f39e7a"
|
||||
|
|
@ -1389,6 +1408,13 @@
|
|||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-slot" "1.1.0"
|
||||
|
||||
"@radix-ui/react-compose-refs@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
|
||||
integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-compose-refs@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74"
|
||||
|
|
@ -1399,6 +1425,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec"
|
||||
integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==
|
||||
|
||||
"@radix-ui/react-context@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c"
|
||||
integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-context@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8"
|
||||
|
|
@ -1409,11 +1442,64 @@
|
|||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a"
|
||||
integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==
|
||||
|
||||
"@radix-ui/react-dialog@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300"
|
||||
integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==
|
||||
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-dismissable-layer" "1.0.5"
|
||||
"@radix-ui/react-focus-guards" "1.0.1"
|
||||
"@radix-ui/react-focus-scope" "1.0.4"
|
||||
"@radix-ui/react-id" "1.0.1"
|
||||
"@radix-ui/react-portal" "1.0.4"
|
||||
"@radix-ui/react-presence" "1.0.1"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
"@radix-ui/react-slot" "1.0.2"
|
||||
"@radix-ui/react-use-controllable-state" "1.0.1"
|
||||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "2.5.5"
|
||||
|
||||
"@radix-ui/react-dialog@^1.1.4":
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz#d68e977acfcc0d044b9dab47b6dd2c179d2b3191"
|
||||
integrity sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.1"
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-context" "1.1.1"
|
||||
"@radix-ui/react-dismissable-layer" "1.1.3"
|
||||
"@radix-ui/react-focus-guards" "1.1.1"
|
||||
"@radix-ui/react-focus-scope" "1.1.1"
|
||||
"@radix-ui/react-id" "1.1.0"
|
||||
"@radix-ui/react-portal" "1.1.3"
|
||||
"@radix-ui/react-presence" "1.1.2"
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-slot" "1.1.1"
|
||||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "^2.6.1"
|
||||
|
||||
"@radix-ui/react-direction@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.0.tgz#a7d39855f4d077adc2a1922f9c353c5977a09cdc"
|
||||
integrity sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==
|
||||
|
||||
"@radix-ui/react-dismissable-layer@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4"
|
||||
integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "1.0.1"
|
||||
"@radix-ui/react-compose-refs" "1.0.1"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.1"
|
||||
"@radix-ui/react-use-escape-keydown" "1.0.3"
|
||||
|
||||
"@radix-ui/react-dismissable-layer@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz#cbdcb739c5403382bdde5f9243042ba643883396"
|
||||
|
|
@ -1425,6 +1511,17 @@
|
|||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.1.0"
|
||||
|
||||
"@radix-ui/react-dismissable-layer@1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz#4ee0f0f82d53bf5bd9db21665799bb0d1bad5ed8"
|
||||
integrity sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.1"
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.1.0"
|
||||
|
||||
"@radix-ui/react-dropdown-menu@^2.1.1":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz#acc49577130e3c875ef0133bd1e271ea3392d924"
|
||||
|
|
@ -1438,11 +1535,28 @@
|
|||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||
|
||||
"@radix-ui/react-focus-guards@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad"
|
||||
integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-focus-guards@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe"
|
||||
integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==
|
||||
|
||||
"@radix-ui/react-focus-scope@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525"
|
||||
integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-compose-refs" "1.0.1"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.1"
|
||||
|
||||
"@radix-ui/react-focus-scope@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz#ebe2891a298e0a33ad34daab2aad8dea31caf0b2"
|
||||
|
|
@ -1452,11 +1566,28 @@
|
|||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
|
||||
"@radix-ui/react-focus-scope@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz#5c602115d1db1c4fcfa0fae4c3b09bb8919853cb"
|
||||
integrity sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
|
||||
"@radix-ui/react-icons@^1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.3.0.tgz#c61af8f323d87682c5ca76b856d60c2312dbcb69"
|
||||
integrity sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==
|
||||
|
||||
"@radix-ui/react-id@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0"
|
||||
integrity sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-layout-effect" "1.0.1"
|
||||
|
||||
"@radix-ui/react-id@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.0.tgz#de47339656594ad722eb87f94a6b25f9cffae0ed"
|
||||
|
|
@ -1531,6 +1662,14 @@
|
|||
"@radix-ui/react-use-size" "1.1.0"
|
||||
"@radix-ui/rect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-portal@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15"
|
||||
integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
|
||||
"@radix-ui/react-portal@1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.2.tgz#51eb46dae7505074b306ebcb985bf65cc547d74e"
|
||||
|
|
@ -1539,6 +1678,23 @@
|
|||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-portal@1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.3.tgz#b0ea5141103a1671b715481b13440763d2ac4440"
|
||||
integrity sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-presence@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba"
|
||||
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"
|
||||
|
||||
"@radix-ui/react-presence@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.1.tgz#98aba423dba5e0c687a782c0669dcd99de17f9b1"
|
||||
|
|
@ -1547,6 +1703,22 @@
|
|||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-presence@1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.2.tgz#bb764ed8a9118b7ec4512da5ece306ded8703cdc"
|
||||
integrity sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-primitive@1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
|
||||
integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-slot" "1.0.2"
|
||||
|
||||
"@radix-ui/react-primitive@2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz#fe05715faa9203a223ccc0be15dc44b9f9822884"
|
||||
|
|
@ -1598,6 +1770,14 @@
|
|||
dependencies:
|
||||
"@radix-ui/react-primitive" "2.0.0"
|
||||
|
||||
"@radix-ui/react-slot@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
||||
integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-compose-refs" "1.0.1"
|
||||
|
||||
"@radix-ui/react-slot@1.1.0", "@radix-ui/react-slot@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84"
|
||||
|
|
@ -1657,11 +1837,26 @@
|
|||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||
"@radix-ui/react-visually-hidden" "1.1.0"
|
||||
|
||||
"@radix-ui/react-use-callback-ref@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
|
||||
integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-use-callback-ref@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz#bce938ca413675bc937944b0d01ef6f4a6dc5bf1"
|
||||
integrity sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==
|
||||
|
||||
"@radix-ui/react-use-controllable-state@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286"
|
||||
integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.1"
|
||||
|
||||
"@radix-ui/react-use-controllable-state@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz#1321446857bb786917df54c0d4d084877aab04b0"
|
||||
|
|
@ -1669,6 +1864,14 @@
|
|||
dependencies:
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
|
||||
"@radix-ui/react-use-escape-keydown@1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755"
|
||||
integrity sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-use-callback-ref" "1.0.1"
|
||||
|
||||
"@radix-ui/react-use-escape-keydown@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz#31a5b87c3b726504b74e05dac1edce7437b98754"
|
||||
|
|
@ -1676,6 +1879,13 @@
|
|||
dependencies:
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
|
||||
"@radix-ui/react-use-layout-effect@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399"
|
||||
integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-use-layout-effect@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27"
|
||||
|
|
@ -2715,6 +2925,14 @@ cm6-graphql@^0.2.0:
|
|||
dependencies:
|
||||
graphql-language-service "^5.3.0"
|
||||
|
||||
cmdk@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cmdk/-/cmdk-1.0.0.tgz#0a095fdafca3dfabed82d1db78a6262fb163ded9"
|
||||
integrity sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==
|
||||
dependencies:
|
||||
"@radix-ui/react-dialog" "1.0.5"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
|
||||
codemirror-lang-brainfuck@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/codemirror-lang-brainfuck/-/codemirror-lang-brainfuck-0.1.0.tgz#528d8a4dd4c7c1f57151f6f1c8141719e7313c18"
|
||||
|
|
@ -5374,6 +5592,14 @@ react-is@^16.13.1:
|
|||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.7:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223"
|
||||
integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==
|
||||
dependencies:
|
||||
react-style-singleton "^2.2.2"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-remove-scroll-bar@^2.3.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz#3e585e9d163be84a010180b18721e851ac81a29c"
|
||||
|
|
@ -5382,6 +5608,17 @@ react-remove-scroll-bar@^2.3.6:
|
|||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-remove-scroll@2.5.5:
|
||||
version "2.5.5"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77"
|
||||
integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==
|
||||
dependencies:
|
||||
react-remove-scroll-bar "^2.3.3"
|
||||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.1.0"
|
||||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-remove-scroll@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz#fb03a0845d7768a4f1519a99fdb84983b793dc07"
|
||||
|
|
@ -5393,6 +5630,17 @@ react-remove-scroll@2.6.0:
|
|||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-remove-scroll@^2.6.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz#2518d2c5112e71ea8928f1082a58459b5c7a2a97"
|
||||
integrity sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==
|
||||
dependencies:
|
||||
react-remove-scroll-bar "^2.3.7"
|
||||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.1.0"
|
||||
use-callback-ref "^1.3.3"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-resizable-panels@^2.1.1:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-2.1.4.tgz#ae1803a916ba759e483336c7bd49830f1b0cd16f"
|
||||
|
|
@ -5407,6 +5655,14 @@ react-style-singleton@^2.2.1:
|
|||
invariant "^2.2.4"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-style-singleton@^2.2.2:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388"
|
||||
integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==
|
||||
dependencies:
|
||||
get-nonce "^1.0.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
react@^18:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
|
|
@ -6348,6 +6604,13 @@ use-callback-ref@^1.3.0:
|
|||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-callback-ref@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf"
|
||||
integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-sidecar@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
|
||||
|
|
|
|||
Loading…
Reference in a new issue