many bug fixes and improvements
This commit is contained in:
parent
b65787358f
commit
55c43d6f9e
|
@ -16,6 +16,7 @@ NEXT_PUBLIC_CREDENTIALS_ENABLED=
|
|||
DISABLE_NEW_SSO_USERS=
|
||||
RE_ARCHIVE_LIMIT=
|
||||
NEXT_PUBLIC_MAX_FILE_SIZE=
|
||||
MAX_LINKS_PER_USER=
|
||||
|
||||
# AWS S3 Settings
|
||||
SPACES_KEY=
|
||||
|
|
|
@ -15,7 +15,7 @@ type Props = {
|
|||
link: LinkIncludingShortenedCollectionAndTags;
|
||||
collection: CollectionIncludingMembersAndLinkCount;
|
||||
position?: string;
|
||||
}
|
||||
};
|
||||
|
||||
export default function LinkActions({ link, collection, position }: Props) {
|
||||
const permissions = usePermissions(link.collection.id as number);
|
||||
|
@ -23,7 +23,6 @@ export default function LinkActions({ link, collection, position }: Props) {
|
|||
const [editLinkModal, setEditLinkModal] = useState(false);
|
||||
const [deleteLinkModal, setDeleteLinkModal] = useState(false);
|
||||
const [preservedFormatsModal, setPreservedFormatsModal] = useState(false);
|
||||
const [expandedLink, setExpandedLink] = useState(false);
|
||||
|
||||
const { account } = useAccountStore();
|
||||
|
||||
|
@ -57,9 +56,6 @@ export default function LinkActions({ link, collection, position }: Props) {
|
|||
|
||||
return (
|
||||
<div>
|
||||
{permissions === true ||
|
||||
permissions?.canUpdate ||
|
||||
permissions?.canDelete ? (
|
||||
<div
|
||||
className={`dropdown dropdown-left absolute ${
|
||||
position || "top-3 right-3"
|
||||
|
@ -70,10 +66,13 @@ export default function LinkActions({ link, collection, position }: Props) {
|
|||
role="button"
|
||||
className="btn btn-ghost btn-sm btn-square text-neutral"
|
||||
>
|
||||
<i id={"expand-dropdown" + collection.id} title="More" className="bi-three-dots text-xl"/>
|
||||
<i
|
||||
id={"expand-dropdown" + collection.id}
|
||||
title="More"
|
||||
className="bi-three-dots text-xl"
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
className="dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1">
|
||||
<ul className="dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1">
|
||||
{permissions === true ? (
|
||||
<li>
|
||||
<div
|
||||
|
@ -104,7 +103,6 @@ export default function LinkActions({ link, collection, position }: Props) {
|
|||
</div>
|
||||
</li>
|
||||
) : undefined}
|
||||
{permissions === true ? (
|
||||
<li>
|
||||
<div
|
||||
role="button"
|
||||
|
@ -118,7 +116,6 @@ export default function LinkActions({ link, collection, position }: Props) {
|
|||
Preserved Formats
|
||||
</div>
|
||||
</li>
|
||||
) : undefined}
|
||||
{permissions === true || permissions?.canDelete ? (
|
||||
<li>
|
||||
<div
|
||||
|
@ -135,7 +132,6 @@ export default function LinkActions({ link, collection, position }: Props) {
|
|||
) : undefined}
|
||||
</ul>
|
||||
</div>
|
||||
) : undefined}
|
||||
|
||||
{editLinkModal ? (
|
||||
<EditLinkModal
|
||||
|
|
|
@ -34,6 +34,8 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
|
||||
|
||||
const [collectionOwner, setCollectionOwner] = useState({
|
||||
id: null as unknown as number,
|
||||
name: "",
|
||||
|
@ -78,12 +80,8 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
let isPublicRoute = router.pathname.startsWith("/public")
|
||||
? true
|
||||
: undefined;
|
||||
|
||||
(async () => {
|
||||
const data = await getLink(link.id as number, isPublicRoute);
|
||||
const data = await getLink(link.id as number, isPublic);
|
||||
setLink(
|
||||
(data as any).response as LinkIncludingShortenedCollectionAndTags
|
||||
);
|
||||
|
@ -93,7 +91,7 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
|||
|
||||
if (!isReady()) {
|
||||
interval = setInterval(async () => {
|
||||
const data = await getLink(link.id as number, isPublicRoute);
|
||||
const data = await getLink(link.id as number, isPublic);
|
||||
setLink(
|
||||
(data as any).response as LinkIncludingShortenedCollectionAndTags
|
||||
);
|
||||
|
@ -123,8 +121,11 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
|||
toast.dismiss(load);
|
||||
|
||||
if (response.ok) {
|
||||
const newLink = await getLink(link?.id as number);
|
||||
setLink(
|
||||
(newLink as any).response as LinkIncludingShortenedCollectionAndTags
|
||||
);
|
||||
toast.success(`Link is being archived...`);
|
||||
await getLink(link?.id as number);
|
||||
} else toast.error(data.response);
|
||||
};
|
||||
|
||||
|
@ -148,20 +149,15 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
|||
<div className={`flex flex-col gap-3`}>
|
||||
{isReady() ? (
|
||||
<>
|
||||
{readabilityAvailable(link) ? (
|
||||
<PreservedFormatRow
|
||||
name={"Readable"}
|
||||
icon={"bi-file-earmark-text"}
|
||||
format={ArchivedFormat.readability}
|
||||
activeLink={link}
|
||||
/>
|
||||
) : undefined}
|
||||
|
||||
{screenshotAvailable(link) ? (
|
||||
<PreservedFormatRow
|
||||
name={"Screenshot"}
|
||||
icon={"bi-file-earmark-image"}
|
||||
format={ArchivedFormat.png}
|
||||
format={
|
||||
link?.screenshotPath?.endsWith("png")
|
||||
? ArchivedFormat.png
|
||||
: ArchivedFormat.jpeg
|
||||
}
|
||||
activeLink={link}
|
||||
downloadable={true}
|
||||
/>
|
||||
|
@ -176,6 +172,15 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
|||
downloadable={true}
|
||||
/>
|
||||
) : undefined}
|
||||
|
||||
{readabilityAvailable(link) ? (
|
||||
<PreservedFormatRow
|
||||
name={"Readable"}
|
||||
icon={"bi-file-earmark-text"}
|
||||
format={ArchivedFormat.readability}
|
||||
activeLink={link}
|
||||
/>
|
||||
) : undefined}
|
||||
</>
|
||||
) : (
|
||||
<div
|
||||
|
@ -183,7 +188,7 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
|||
>
|
||||
<i className="bi-stack drop-shadow text-primary text-8xl mx-auto mb-5"></i>
|
||||
<p className="text-center text-2xl">
|
||||
The Link preservation is in the queue
|
||||
Link preservation is in the queue
|
||||
</p>
|
||||
<p className="text-center text-lg">
|
||||
Please check back later to see the result
|
||||
|
|
|
@ -32,13 +32,11 @@ export default function PreservedFormatRow({
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
let isPublicRoute = router.pathname.startsWith("/public")
|
||||
? true
|
||||
: undefined;
|
||||
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const data = await getLink(link.id as number, isPublicRoute);
|
||||
const data = await getLink(link.id as number, isPublic);
|
||||
setLink(
|
||||
(data as any).response as LinkIncludingShortenedCollectionAndTags
|
||||
);
|
||||
|
@ -47,7 +45,7 @@ export default function PreservedFormatRow({
|
|||
let interval: any;
|
||||
if (link?.screenshotPath === "pending" || link?.pdfPath === "pending") {
|
||||
interval = setInterval(async () => {
|
||||
const data = await getLink(link.id as number, isPublicRoute);
|
||||
const data = await getLink(link.id as number, isPublic);
|
||||
setLink(
|
||||
(data as any).response as LinkIncludingShortenedCollectionAndTags
|
||||
);
|
||||
|
@ -65,23 +63,6 @@ export default function PreservedFormatRow({
|
|||
};
|
||||
}, [link?.screenshotPath, link?.pdfPath, link?.readabilityPath]);
|
||||
|
||||
const updateArchive = async () => {
|
||||
const load = toast.loading("Sending request...");
|
||||
|
||||
const response = await fetch(`/api/v1/links/${link?.id}/archive`, {
|
||||
method: "PUT",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
toast.dismiss(load);
|
||||
|
||||
if (response.ok) {
|
||||
toast.success(`Link is being archived...`);
|
||||
getLink(link?.id as number);
|
||||
} else toast.error(data.response);
|
||||
};
|
||||
|
||||
const handleDownload = () => {
|
||||
const path = `/api/v1/archives/${link?.id}?format=${format}`;
|
||||
fetch(path)
|
||||
|
@ -121,7 +102,9 @@ export default function PreservedFormatRow({
|
|||
) : undefined}
|
||||
|
||||
<Link
|
||||
href={`/preserved/${link?.id}?format=${format}`}
|
||||
href={`${isPublic ? "/public" : ""}/preserved/${
|
||||
link?.id
|
||||
}?format=${format}`}
|
||||
target="_blank"
|
||||
className="btn btn-sm btn-square"
|
||||
>
|
||||
|
|
|
@ -4,6 +4,8 @@ import isValidUrl from "@/lib/shared/isValidUrl";
|
|||
import unescapeString from "@/lib/client/unescapeString";
|
||||
import { TagIncludingLinkCount } from "@/types/global";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import PreservedFormatsModal from "../ModalContent/PreservedFormatsModal";
|
||||
|
||||
interface LinksIncludingTags extends LinkType {
|
||||
tags: TagIncludingLinkCount[];
|
||||
|
@ -25,6 +27,8 @@ export default function LinkCard({ link, count }: Props) {
|
|||
day: "numeric",
|
||||
});
|
||||
|
||||
const [preservedFormatsModal, setPreservedFormatsModal] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="border border-solid border-neutral-content bg-base-200 shadow hover:shadow-none duration-100 rounded-lg p-3 flex items-start relative gap-3 group/item">
|
||||
<div className="flex justify-between items-end gap-5 w-full h-full z-0">
|
||||
|
@ -77,15 +81,52 @@ export default function LinkCard({ link, count }: Props) {
|
|||
<div className="w-full">
|
||||
{unescapeString(link.description)}{" "}
|
||||
<Link
|
||||
href={`/public/links/${link.id}`}
|
||||
href={link.url || ""}
|
||||
target="_blank"
|
||||
className="flex gap-1 items-center flex-wrap text-sm text-neutral hover:opacity-50 duration-100 min-w-fit float-right mt-1 ml-2"
|
||||
>
|
||||
<p>Read</p>
|
||||
<p>Visit</p>
|
||||
<i className={"bi-chevron-right"}></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`dropdown dropdown-left absolute ${"top-3 right-3"} z-20`}
|
||||
>
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
className="btn btn-ghost btn-sm btn-square text-neutral"
|
||||
>
|
||||
<i
|
||||
id={"expand-dropdown" + link.id}
|
||||
title="More"
|
||||
className="bi-three-dots text-xl"
|
||||
/>
|
||||
</div>
|
||||
<ul className="dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1">
|
||||
<li>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => {
|
||||
(document?.activeElement as HTMLElement)?.blur();
|
||||
setPreservedFormatsModal(true);
|
||||
// updateArchive();
|
||||
}}
|
||||
>
|
||||
Preserved Formats
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{preservedFormatsModal ? (
|
||||
<PreservedFormatsModal
|
||||
onClose={() => setPreservedFormatsModal(false)}
|
||||
activeLink={link as any}
|
||||
/>
|
||||
) : undefined}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { JSDOM } from "jsdom";
|
|||
import DOMPurify from "dompurify";
|
||||
import { Collection, Link, User } from "@prisma/client";
|
||||
import validateUrlSize from "./validateUrlSize";
|
||||
import removeFile from "./storage/removeFile";
|
||||
|
||||
type LinksAndCollectionAndOwner = Link & {
|
||||
collection: Collection & {
|
||||
|
@ -74,7 +75,7 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
|
|||
|
||||
const content = await page.content();
|
||||
|
||||
// TODO Webarchive
|
||||
// TODO single file
|
||||
// const session = await page.context().newCDPSession(page);
|
||||
// const doc = await session.send("Page.captureSnapshot", {
|
||||
// format: "mhtml",
|
||||
|
@ -189,6 +190,13 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
|
|||
: undefined,
|
||||
},
|
||||
});
|
||||
else {
|
||||
removeFile({ filePath: `archives/${link.collectionId}/${link.id}.png` });
|
||||
removeFile({ filePath: `archives/${link.collectionId}/${link.id}.pdf` });
|
||||
removeFile({
|
||||
filePath: `archives/${link.collectionId}/${link.id}_readability.json`,
|
||||
});
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import getPermission from "@/lib/api/getPermission";
|
|||
import createFolder from "@/lib/api/storage/createFolder";
|
||||
import validateUrlSize from "../../validateUrlSize";
|
||||
|
||||
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
|
||||
|
||||
export default async function postLink(
|
||||
link: LinkIncludingShortenedCollectionAndTags,
|
||||
userId: number
|
||||
|
@ -24,6 +26,20 @@ export default async function postLink(
|
|||
link.collection.name = "Unorganized";
|
||||
}
|
||||
|
||||
const numberOfLinksTheUserHas = await prisma.link.count({
|
||||
where: {
|
||||
collection: {
|
||||
ownerId: userId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (numberOfLinksTheUserHas + 1 > MAX_LINKS_PER_USER)
|
||||
return {
|
||||
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
|
||||
status: 400,
|
||||
};
|
||||
|
||||
link.collection.name = link.collection.name.trim();
|
||||
|
||||
if (link.collection.id) {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { prisma } from "@/lib/api/db";
|
||||
import { Backup } from "@/types/global";
|
||||
import createFolder from "@/lib/api/storage/createFolder";
|
||||
import { JSDOM } from "jsdom";
|
||||
|
||||
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
|
||||
|
||||
export default async function importFromHTMLFile(
|
||||
userId: number,
|
||||
rawData: string
|
||||
|
@ -10,6 +11,23 @@ export default async function importFromHTMLFile(
|
|||
const dom = new JSDOM(rawData);
|
||||
const document = dom.window.document;
|
||||
|
||||
const bookmarks = document.querySelectorAll("A");
|
||||
const totalImports = bookmarks.length;
|
||||
|
||||
const numberOfLinksTheUserHas = await prisma.link.count({
|
||||
where: {
|
||||
collection: {
|
||||
ownerId: userId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER)
|
||||
return {
|
||||
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
|
||||
status: 400,
|
||||
};
|
||||
|
||||
const folders = document.querySelectorAll("H3");
|
||||
|
||||
await prisma
|
||||
|
|
|
@ -2,9 +2,34 @@ 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: string) {
|
||||
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
|
||||
|
||||
export default async function importFromLinkwarden(
|
||||
userId: number,
|
||||
rawData: string
|
||||
) {
|
||||
const data: Backup = JSON.parse(rawData);
|
||||
|
||||
let totalImports = 0;
|
||||
|
||||
data.collections.forEach((collection) => {
|
||||
totalImports += collection.links.length;
|
||||
});
|
||||
|
||||
const numberOfLinksTheUserHas = await prisma.link.count({
|
||||
where: {
|
||||
collection: {
|
||||
ownerId: userId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER)
|
||||
return {
|
||||
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
|
||||
status: 400,
|
||||
};
|
||||
|
||||
await prisma
|
||||
.$transaction(
|
||||
async () => {
|
||||
|
|
|
@ -75,7 +75,7 @@ export default async function getPublicUser(
|
|||
username: lessSensitiveInfo.username,
|
||||
image: lessSensitiveInfo.image,
|
||||
archiveAsScreenshot: lessSensitiveInfo.archiveAsScreenshot,
|
||||
archiveAsPdf: lessSensitiveInfo.archiveAsPDF,
|
||||
archiveAsPDF: lessSensitiveInfo.archiveAsPDF,
|
||||
};
|
||||
|
||||
return { response: data, status: 200 };
|
||||
|
|
|
@ -46,7 +46,14 @@ export default function Index() {
|
|||
<img
|
||||
alt=""
|
||||
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.png}`}
|
||||
className="object-contain w-full h-screen"
|
||||
className="w-fit mx-auto"
|
||||
/>
|
||||
)}
|
||||
{link && Number(router.query.format) === ArchivedFormat.jpeg && (
|
||||
<img
|
||||
alt=""
|
||||
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.jpeg}`}
|
||||
className="w-fit mx-auto"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -96,11 +96,11 @@ export default function PublicCollections() {
|
|||
|
||||
return collection ? (
|
||||
<div
|
||||
className="h-screen"
|
||||
className="h-96"
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(${collection?.color}30 10%, ${
|
||||
settings.theme === "dark" ? "#262626" : "#f3f4f6"
|
||||
} 18rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`,
|
||||
} 13rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`,
|
||||
}}
|
||||
>
|
||||
{collection ? (
|
||||
|
@ -208,6 +208,11 @@ export default function PublicCollections() {
|
|||
{links
|
||||
?.filter((e) => e.collectionId === Number(router.query.id))
|
||||
.map((e, i) => {
|
||||
const linkWithCollectionData = {
|
||||
...e,
|
||||
collection: collection, // Append collection data
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={i}
|
||||
|
@ -216,7 +221,10 @@ export default function PublicCollections() {
|
|||
viewport={{ once: true, amount: 0.8 }}
|
||||
>
|
||||
<motion.div variants={cardVariants}>
|
||||
<PublicLinkCard link={e as any} count={i} />
|
||||
<PublicLinkCard
|
||||
link={linkWithCollectionData as any}
|
||||
count={i}
|
||||
/>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import useLinkStore from "@/store/links";
|
||||
import { useRouter } from "next/router";
|
||||
import {
|
||||
ArchivedFormat,
|
||||
LinkIncludingShortenedCollectionAndTags,
|
||||
} from "@/types/global";
|
||||
import ReadableView from "@/components/ReadableView";
|
||||
|
||||
export default function Index() {
|
||||
const { links, getLink } = useLinkStore();
|
||||
|
||||
const [link, setLink] = useState<LinkIncludingShortenedCollectionAndTags>();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
let isPublic = router.pathname.startsWith("/public") ? true : false;
|
||||
|
||||
useEffect(() => {
|
||||
const fetchLink = async () => {
|
||||
if (router.query.id) {
|
||||
await getLink(Number(router.query.id), isPublic);
|
||||
}
|
||||
};
|
||||
|
||||
fetchLink();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (links[0]) setLink(links.find((e) => e.id === Number(router.query.id)));
|
||||
}, [links]);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
{/* <div className="fixed left-1/2 transform -translate-x-1/2 w-fit py-1 px-3 bg-base-200 border border-neutral-content rounded-md">
|
||||
Readable
|
||||
</div> */}
|
||||
{link && Number(router.query.format) === ArchivedFormat.readability && (
|
||||
<ReadableView link={link} />
|
||||
)}
|
||||
{link && Number(router.query.format) === ArchivedFormat.pdf && (
|
||||
<iframe
|
||||
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.pdf}`}
|
||||
className="w-full h-screen border-none"
|
||||
></iframe>
|
||||
)}
|
||||
{link && Number(router.query.format) === ArchivedFormat.png && (
|
||||
<img
|
||||
alt=""
|
||||
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.png}`}
|
||||
className="w-fit mx-auto"
|
||||
/>
|
||||
)}
|
||||
{link && Number(router.query.format) === ArchivedFormat.jpeg && (
|
||||
<img
|
||||
alt=""
|
||||
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.jpeg}`}
|
||||
className="w-fit mx-auto"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -10,7 +10,6 @@ import SubmitButton from "@/components/SubmitButton";
|
|||
import React from "react";
|
||||
import { MigrationFormat, MigrationRequest } from "@/types/global";
|
||||
import Link from "next/link";
|
||||
import ClickAwayHandler from "@/components/ClickAwayHandler";
|
||||
import Checkbox from "@/components/Checkbox";
|
||||
|
||||
export default function Account() {
|
||||
|
@ -85,9 +84,9 @@ export default function Account() {
|
|||
setSubmitLoader(false);
|
||||
};
|
||||
|
||||
const [importDropdown, setImportDropdown] = useState(false);
|
||||
|
||||
const importBookmarks = async (e: any, format: MigrationFormat) => {
|
||||
setSubmitLoader(true);
|
||||
|
||||
const file: File = e.target.files[0];
|
||||
|
||||
if (file) {
|
||||
|
@ -112,18 +111,19 @@ export default function Account() {
|
|||
|
||||
toast.dismiss(load);
|
||||
|
||||
if (response.ok) {
|
||||
toast.success("Imported the Bookmarks! Reloading the page...");
|
||||
|
||||
setImportDropdown(false);
|
||||
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 2000);
|
||||
} else toast.error(data.response as string);
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
console.log("Error:", e);
|
||||
};
|
||||
}
|
||||
|
||||
setSubmitLoader(false);
|
||||
};
|
||||
|
||||
const [whitelistedUsersTextbox, setWhiteListedUsersTextbox] = useState("");
|
||||
|
|
|
@ -10,6 +10,7 @@ declare global {
|
|||
AUTOSCROLL_TIMEOUT?: string;
|
||||
RE_ARCHIVE_LIMIT?: string;
|
||||
NEXT_PUBLIC_MAX_FILE_SIZE?: string;
|
||||
MAX_LINKS_PER_USER?: string;
|
||||
|
||||
SPACES_KEY?: string;
|
||||
SPACES_SECRET?: string;
|
||||
|
|
Ŝarĝante…
Reference in New Issue