import bookmarks from other platforms + many other improvements
This commit is contained in:
parent
8fc8874063
commit
f15e298cc3
|
@ -82,7 +82,7 @@ export default function DeleteCollection({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
<p className="text-black dark:text-white select-none text-center">
|
<p className="text-black dark:text-white text-center">
|
||||||
To confirm, type "
|
To confirm, type "
|
||||||
<span className="font-bold">{collection.name}</span>
|
<span className="font-bold">{collection.name}</span>
|
||||||
" in the box below:
|
" in the box below:
|
||||||
|
|
|
@ -7,8 +7,8 @@ import useLinkStore from "@/store/links";
|
||||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||||
import RequiredBadge from "../../RequiredBadge";
|
import RequiredBadge from "../../RequiredBadge";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
// import useCollectionStore from "@/store/collections";
|
import useCollectionStore from "@/store/collections";
|
||||||
// import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import SubmitButton from "../../SubmitButton";
|
import SubmitButton from "../../SubmitButton";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
@ -55,27 +55,40 @@ export default function AddOrEditLink({
|
||||||
|
|
||||||
const { updateLink, addLink } = useLinkStore();
|
const { updateLink, addLink } = useLinkStore();
|
||||||
|
|
||||||
// const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { collections } = useCollectionStore();
|
||||||
|
|
||||||
// const { collections } = useCollectionStore();
|
useEffect(() => {
|
||||||
|
if (method === "CREATE") {
|
||||||
|
if (router.query.id) {
|
||||||
|
const currentCollection = collections.find(
|
||||||
|
(e) => e.id == Number(router.query.id)
|
||||||
|
);
|
||||||
|
|
||||||
// useEffect(() => {
|
if (
|
||||||
// if (router.query.id) {
|
currentCollection &&
|
||||||
// const currentCollection = collections.find(
|
currentCollection.ownerId &&
|
||||||
// (e) => e.id == Number(router.query.id)
|
router.asPath.startsWith("/collections/")
|
||||||
// );
|
)
|
||||||
|
setLink({
|
||||||
// if (currentCollection && currentCollection.ownerId)
|
...link,
|
||||||
// setLink({
|
collection: {
|
||||||
// ...link,
|
id: currentCollection.id,
|
||||||
// collection: {
|
name: currentCollection.name,
|
||||||
// id: currentCollection.id,
|
ownerId: currentCollection.ownerId,
|
||||||
// name: currentCollection.name,
|
},
|
||||||
// ownerId: currentCollection.ownerId,
|
});
|
||||||
// },
|
} else
|
||||||
// });
|
setLink({
|
||||||
// }
|
...link,
|
||||||
// }, []);
|
collection: {
|
||||||
|
// id: ,
|
||||||
|
name: "Unorganized",
|
||||||
|
ownerId: data?.user.id as number,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const setTags = (e: any) => {
|
const setTags = (e: any) => {
|
||||||
const tagNames = e.map((e: any) => {
|
const tagNames = e.map((e: any) => {
|
||||||
|
@ -147,6 +160,7 @@ export default function AddOrEditLink({
|
||||||
<p className="text-sm text-black dark:text-white mb-2">
|
<p className="text-sm text-black dark:text-white mb-2">
|
||||||
Collection
|
Collection
|
||||||
</p>
|
</p>
|
||||||
|
{link.collection.name ? (
|
||||||
<CollectionSelection
|
<CollectionSelection
|
||||||
onChange={setCollection}
|
onChange={setCollection}
|
||||||
// defaultValue={{
|
// defaultValue={{
|
||||||
|
@ -165,9 +179,10 @@ export default function AddOrEditLink({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : undefined}
|
||||||
|
|
||||||
{optionsExpanded ? (
|
{optionsExpanded ? (
|
||||||
<div>
|
<div>
|
||||||
|
@ -187,6 +202,7 @@ export default function AddOrEditLink({
|
||||||
<p className="text-sm text-black dark:text-white mb-2">
|
<p className="text-sm text-black dark:text-white mb-2">
|
||||||
Collection
|
Collection
|
||||||
</p>
|
</p>
|
||||||
|
{link.collection.name ? (
|
||||||
<CollectionSelection
|
<CollectionSelection
|
||||||
onChange={setCollection}
|
onChange={setCollection}
|
||||||
defaultValue={
|
defaultValue={
|
||||||
|
@ -201,6 +217,7 @@ export default function AddOrEditLink({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
) : undefined}
|
||||||
</div>
|
</div>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ export default function PrivacySettings({
|
||||||
return wordsArray;
|
return wordsArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
const postJSONFile = async (e: any) => {
|
const postBookmarkFile = async (e: any) => {
|
||||||
const file: File = e.target.files[0];
|
const file: File = e.target.files[0];
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
|
@ -156,9 +156,7 @@ export default function PrivacySettings({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<p className="text-sm text-black dark:text-white mb-2">
|
<p className="text-sm text-black dark:text-white mb-2">Import Data</p>
|
||||||
Import/Export Data
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<div
|
<div
|
||||||
|
@ -178,22 +176,22 @@ export default function PrivacySettings({
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
if (target.id !== "import-dropdown") setImportDropdown(false);
|
if (target.id !== "import-dropdown") setImportDropdown(false);
|
||||||
}}
|
}}
|
||||||
className={`absolute top-7 left-0 w-36 py-1 shadow-md border border-sky-100 dark:border-neutral-700 bg-gray-50 dark:bg-neutral-800 rounded-md flex flex-col z-20`}
|
className={`absolute top-7 left-0 w-48 py-1 shadow-md border border-sky-100 dark:border-neutral-700 bg-gray-50 dark:bg-neutral-800 rounded-md flex flex-col z-20`}
|
||||||
>
|
>
|
||||||
<div className="cursor-pointer rounded-md">
|
<div className="cursor-pointer rounded-md">
|
||||||
<label
|
<label
|
||||||
htmlFor="import-file"
|
htmlFor="import-file"
|
||||||
title="JSON"
|
title="HTML File"
|
||||||
className="flex items-center gap-2 py-1 px-2 hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 cursor-pointer"
|
className="flex items-center gap-2 py-1 px-2 hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 cursor-pointer"
|
||||||
>
|
>
|
||||||
Linkwarden
|
Bookmarks HTML file...
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
name="photo"
|
name="photo"
|
||||||
id="import-file"
|
id="import-file"
|
||||||
accept=".json"
|
accept=".html"
|
||||||
className="hidden"
|
className="hidden"
|
||||||
onChange={postJSONFile}
|
onChange={postBookmarkFile}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -201,11 +199,12 @@ export default function PrivacySettings({
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link className="w-fit" href="/api/migration">
|
{/* Commented out for now. */}
|
||||||
|
{/* <Link className="w-fit" href="/api/migration">
|
||||||
<div className="border border-slate-200 dark:border-neutral-700 rounded-md bg-white dark:bg-neutral-800 px-2 text-center select-none cursor-pointer duration-100 hover:border-sky-300 hover:dark:border-sky-600">
|
<div className="border border-slate-200 dark:border-neutral-700 rounded-md bg-white dark:bg-neutral-800 px-2 text-center select-none cursor-pointer duration-100 hover:border-sky-300 hover:dark:border-sky-600">
|
||||||
Export Data
|
Export Data
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,22 @@ const useDetectPageBottom = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
const offsetHeight = document.documentElement.offsetHeight;
|
const totalHeight = document.documentElement.scrollHeight;
|
||||||
const innerHeight = window.innerHeight;
|
const scrolledHeight = window.scrollY + window.innerHeight;
|
||||||
const scrollTop = document.documentElement.scrollTop;
|
|
||||||
|
|
||||||
const hasReachedBottom = offsetHeight - (innerHeight + scrollTop) <= 100;
|
if (scrolledHeight >= totalHeight) {
|
||||||
|
setReachedBottom(true);
|
||||||
setReachedBottom(hasReachedBottom);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("scroll", handleScroll);
|
window.addEventListener("scroll", handleScroll);
|
||||||
|
|
||||||
return () => window.removeEventListener("scroll", handleScroll);
|
return () => {
|
||||||
|
window.removeEventListener("scroll", handleScroll);
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return reachedBottom;
|
return { reachedBottom, setReachedBottom };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useDetectPageBottom;
|
export default useDetectPageBottom;
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default function useLinks(
|
||||||
const { links, setLinks, resetLinks } = useLinkStore();
|
const { links, setLinks, resetLinks } = useLinkStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const hasReachedBottom = useDetectPageBottom();
|
const { reachedBottom, setReachedBottom } = useDetectPageBottom();
|
||||||
|
|
||||||
const getLinks = async (isInitialCall: boolean, cursor?: number) => {
|
const getLinks = async (isInitialCall: boolean, cursor?: number) => {
|
||||||
const requestBody: LinkRequestQuery = {
|
const requestBody: LinkRequestQuery = {
|
||||||
|
@ -48,6 +48,8 @@ export default function useLinks(
|
||||||
}, [router, sort, searchFilter]);
|
}, [router, sort, searchFilter]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasReachedBottom) getLinks(false, links?.at(-1)?.id);
|
if (reachedBottom) getLinks(false, links?.at(-1)?.id);
|
||||||
}, [hasReachedBottom]);
|
|
||||||
|
setReachedBottom(false);
|
||||||
|
}, [reachedBottom]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ export default async function updateLink(
|
||||||
link: LinkIncludingShortenedCollectionAndTags,
|
link: LinkIncludingShortenedCollectionAndTags,
|
||||||
userId: number
|
userId: number
|
||||||
) {
|
) {
|
||||||
|
console.log(link);
|
||||||
if (!link || !link.collection.id)
|
if (!link || !link.collection.id)
|
||||||
return {
|
return {
|
||||||
response: "Please choose a valid link and collection.",
|
response: "Please choose a valid link and collection.",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { prisma } from "@/lib/api/db";
|
import { prisma } from "@/lib/api/db";
|
||||||
|
|
||||||
export default async function getData(userId: number) {
|
export default async function exportData(userId: number) {
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
include: {
|
include: {
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { prisma } from "@/lib/api/db";
|
||||||
|
import { Backup } from "@/types/global";
|
||||||
|
import createFolder from "@/lib/api/storage/createFolder";
|
||||||
|
import { JSDOM } from "jsdom";
|
||||||
|
|
||||||
|
export default async function importData(userId: number, rawData: string) {
|
||||||
|
try {
|
||||||
|
const dom = new JSDOM(rawData);
|
||||||
|
const document = dom.window.document;
|
||||||
|
|
||||||
|
const folders = document.querySelectorAll("H3");
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
for (const folder of folders) {
|
||||||
|
const findCollection = await prisma.user.findUnique({
|
||||||
|
where: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
collections: {
|
||||||
|
where: {
|
||||||
|
name: folder.textContent.trim(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkIfCollectionExists = findCollection?.collections[0];
|
||||||
|
|
||||||
|
let collectionId = findCollection?.collections[0]?.id;
|
||||||
|
|
||||||
|
if (!checkIfCollectionExists || !collectionId) {
|
||||||
|
const newCollection = await prisma.collection.create({
|
||||||
|
data: {
|
||||||
|
name: folder.textContent.trim(),
|
||||||
|
description: "",
|
||||||
|
color: "#0ea5e9",
|
||||||
|
isPublic: false,
|
||||||
|
ownerId: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
createFolder({ filePath: `archives/${newCollection.id}` });
|
||||||
|
|
||||||
|
collectionId = newCollection.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
createFolder({ filePath: `archives/${collectionId}` });
|
||||||
|
|
||||||
|
const bookmarks = folder.nextElementSibling.querySelectorAll("A");
|
||||||
|
for (const bookmark of bookmarks) {
|
||||||
|
await prisma.link.create({
|
||||||
|
data: {
|
||||||
|
name: bookmark.textContent.trim(),
|
||||||
|
url: bookmark.getAttribute("HREF"),
|
||||||
|
tags: bookmark.getAttribute("TAGS")
|
||||||
|
? {
|
||||||
|
connectOrCreate: bookmark
|
||||||
|
.getAttribute("TAGS")
|
||||||
|
.split(",")
|
||||||
|
.map((tag: string) =>
|
||||||
|
tag
|
||||||
|
? {
|
||||||
|
where: {
|
||||||
|
name_ownerId: {
|
||||||
|
name: tag.trim(),
|
||||||
|
ownerId: userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
name: tag.trim(),
|
||||||
|
owner: {
|
||||||
|
connect: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
description: bookmark.getAttribute("DESCRIPTION")
|
||||||
|
? bookmark.getAttribute("DESCRIPTION")
|
||||||
|
: "",
|
||||||
|
collectionId: collectionId,
|
||||||
|
createdAt: new Date(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { response: "Success.", status: 200 };
|
||||||
|
}
|
|
@ -1,88 +0,0 @@
|
||||||
import { prisma } from "@/lib/api/db";
|
|
||||||
import { Backup } from "@/types/global";
|
|
||||||
import createFolder from "@/lib/api/storage/createFolder";
|
|
||||||
|
|
||||||
export default async function getData(userId: number, rawData: any) {
|
|
||||||
const data: Backup = JSON.parse(rawData);
|
|
||||||
|
|
||||||
// Import collections
|
|
||||||
try {
|
|
||||||
data.collections.forEach(async (e) => {
|
|
||||||
e.name = e.name.trim();
|
|
||||||
|
|
||||||
const findCollection = await prisma.user.findUnique({
|
|
||||||
where: {
|
|
||||||
id: userId,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
collections: {
|
|
||||||
where: {
|
|
||||||
name: e.name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const checkIfCollectionExists = findCollection?.collections[0];
|
|
||||||
|
|
||||||
let collectionId = findCollection?.collections[0]?.id;
|
|
||||||
|
|
||||||
if (!checkIfCollectionExists) {
|
|
||||||
const newCollection = await prisma.collection.create({
|
|
||||||
data: {
|
|
||||||
owner: {
|
|
||||||
connect: {
|
|
||||||
id: userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
name: e.name,
|
|
||||||
description: e.description,
|
|
||||||
color: e.color,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
createFolder({ filePath: `archives/${newCollection.id}` });
|
|
||||||
|
|
||||||
collectionId = newCollection.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import Links
|
|
||||||
e.links.forEach(async (e) => {
|
|
||||||
const newLink = await prisma.link.create({
|
|
||||||
data: {
|
|
||||||
url: e.url,
|
|
||||||
name: e.name,
|
|
||||||
description: e.description,
|
|
||||||
collection: {
|
|
||||||
connect: {
|
|
||||||
id: collectionId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tags: {
|
|
||||||
connectOrCreate: e.tags.map((tag) => ({
|
|
||||||
where: {
|
|
||||||
name_ownerId: {
|
|
||||||
name: tag.name.trim(),
|
|
||||||
ownerId: userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
name: tag.name.trim(),
|
|
||||||
owner: {
|
|
||||||
connect: {
|
|
||||||
id: userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { response: "Success.", status: 200 };
|
|
||||||
}
|
|
|
@ -54,6 +54,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.35.1",
|
"@playwright/test": "^1.35.1",
|
||||||
"@types/bcrypt": "^5.0.0",
|
"@types/bcrypt": "^5.0.0",
|
||||||
|
"@types/jsdom": "^21.1.3",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"postcss": "^8.4.26",
|
"postcss": "^8.4.26",
|
||||||
"prisma": "^5.1.0",
|
"prisma": "^5.1.0",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { getServerSession } from "next-auth/next";
|
import { getServerSession } from "next-auth/next";
|
||||||
import { authOptions } from "@/pages/api/auth/[...nextauth]";
|
import { authOptions } from "@/pages/api/auth/[...nextauth]";
|
||||||
import getData from "@/lib/api/controllers/migration/getData";
|
import exportData from "@/lib/api/controllers/migration/exportData";
|
||||||
import postData from "@/lib/api/controllers/migration/postData";
|
import importData from "@/lib/api/controllers/migration/importData";
|
||||||
|
|
||||||
export default async function users(req: NextApiRequest, res: NextApiResponse) {
|
export default async function users(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const session = await getServerSession(req, res, authOptions);
|
const session = await getServerSession(req, res, authOptions);
|
||||||
|
@ -16,7 +16,7 @@ export default async function users(req: NextApiRequest, res: NextApiResponse) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (req.method === "GET") {
|
if (req.method === "GET") {
|
||||||
const data = await getData(session.user.id);
|
const data = await exportData(session.user.id);
|
||||||
|
|
||||||
if (data.status === 200)
|
if (data.status === 200)
|
||||||
return res
|
return res
|
||||||
|
@ -25,7 +25,7 @@ export default async function users(req: NextApiRequest, res: NextApiResponse) {
|
||||||
.status(data.status)
|
.status(data.status)
|
||||||
.json(data.response);
|
.json(data.response);
|
||||||
} else if (req.method === "POST") {
|
} else if (req.method === "POST") {
|
||||||
const data = await postData(session.user.id, req.body);
|
const data = await importData(session.user.id, req.body);
|
||||||
return res.status(data.status).json({ response: data.response });
|
return res.status(data.status).json({ response: data.response });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,7 @@ export default function Index() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{links[0] ? (
|
{links.some((e) => e.collectionId === Number(router.query.id)) ? (
|
||||||
<div className="grid grid-cols-1 2xl:grid-cols-3 xl:grid-cols-2 gap-5">
|
<div className="grid grid-cols-1 2xl:grid-cols-3 xl:grid-cols-2 gap-5">
|
||||||
{links
|
{links
|
||||||
.filter((e) => e.collectionId === Number(router.query.id))
|
.filter((e) => e.collectionId === Number(router.query.id))
|
||||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -1466,6 +1466,15 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.1.1.tgz#602859584cecc91894eb23a4892f38cfa927890d"
|
resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.1.1.tgz#602859584cecc91894eb23a4892f38cfa927890d"
|
||||||
integrity sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==
|
integrity sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==
|
||||||
|
|
||||||
|
"@types/jsdom@^21.1.3":
|
||||||
|
version "21.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-21.1.3.tgz#a88c5dc65703e1b10b2a7839c12db49662b43ff0"
|
||||||
|
integrity sha512-1zzqSP+iHJYV4lB3lZhNBa012pubABkj9yG/GuXuf6LZH1cSPIJBqFDrm5JX65HHt6VOnNYdTui/0ySerRbMgA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
"@types/tough-cookie" "*"
|
||||||
|
parse5 "^7.0.0"
|
||||||
|
|
||||||
"@types/json5@^0.0.29":
|
"@types/json5@^0.0.29":
|
||||||
version "0.0.29"
|
version "0.0.29"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
|
@ -1521,6 +1530,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
|
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
|
||||||
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
|
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
|
||||||
|
|
||||||
|
"@types/tough-cookie@*":
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.3.tgz#3d06b6769518450871fbc40770b7586334bdfd90"
|
||||||
|
integrity sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==
|
||||||
|
|
||||||
"@typescript-eslint/parser@^5.42.0":
|
"@typescript-eslint/parser@^5.42.0":
|
||||||
version "5.49.0"
|
version "5.49.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.49.0.tgz#d699734b2f20e16351e117417d34a2bc9d7c4b90"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.49.0.tgz#d699734b2f20e16351e117417d34a2bc9d7c4b90"
|
||||||
|
@ -3946,7 +3960,7 @@ parse-json@^5.0.0:
|
||||||
json-parse-even-better-errors "^2.3.0"
|
json-parse-even-better-errors "^2.3.0"
|
||||||
lines-and-columns "^1.1.6"
|
lines-and-columns "^1.1.6"
|
||||||
|
|
||||||
parse5@^7.1.2:
|
parse5@^7.0.0, parse5@^7.1.2:
|
||||||
version "7.1.2"
|
version "7.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32"
|
resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32"
|
||||||
integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==
|
integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==
|
||||||
|
|
Ŝarĝante…
Reference in New Issue