- {showCheckbox && (permissions === true || permissions?.canCreate || permissions?.canDelete) &&
-
handleCheckboxClick(link)}
- />
- }
+ {showCheckbox &&
+ (permissions === true ||
+ permissions?.canCreate ||
+ permissions?.canDelete) && (
+
handleCheckboxClick(link)}
+ />
+ )}
setShowInfo(!showInfo)}
- // linkInfo={showInfo}
+ // toggleShowInfo={() => setShowInfo(!showInfo)}
+ // linkInfo={showInfo}
/>
{showInfo ? (
diff --git a/components/ModalContent/BulkDeleteLinksModal.tsx b/components/ModalContent/BulkDeleteLinksModal.tsx
index 61c5fb3..3d76c4e 100644
--- a/components/ModalContent/BulkDeleteLinksModal.tsx
+++ b/components/ModalContent/BulkDeleteLinksModal.tsx
@@ -4,62 +4,71 @@ import toast from "react-hot-toast";
import Modal from "../Modal";
type Props = {
- onClose: Function;
+ onClose: Function;
};
export default function BulkDeleteLinksModal({ onClose }: Props) {
- const { selectedLinks, setSelectedLinks, deleteLinksById } = useLinkStore();
+ const { selectedLinks, setSelectedLinks, deleteLinksById } = useLinkStore();
- const deleteLink = async () => {
- const load = toast.loading(`Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}...`);
+ const deleteLink = async () => {
+ const load = toast.loading(
+ `Deleting ${selectedLinks.length} Link${
+ selectedLinks.length > 1 ? "s" : ""
+ }...`
+ );
- const response = await deleteLinksById(selectedLinks.map(link => link.id as number));
+ const response = await deleteLinksById(
+ selectedLinks.map((link) => link.id as number)
+ );
- toast.dismiss(load);
+ toast.dismiss(load);
- response.ok && toast.success(`Deleted ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}`);
+ response.ok &&
+ toast.success(
+ `Deleted ${selectedLinks.length} Link${
+ selectedLinks.length > 1 ? "s" : ""
+ }`
+ );
- setSelectedLinks([]);
- onClose();
- };
+ setSelectedLinks([]);
+ onClose();
+ };
- return (
-
- Delete {selectedLinks.length} Link{selectedLinks.length > 1 ? "s" : ""}
+ return (
+
+
+ Delete {selectedLinks.length} Link{selectedLinks.length > 1 ? "s" : ""}
+
-
+
-
- {selectedLinks.length > 1 ? (
-
- Are you sure you want to delete {selectedLinks.length} links?
-
- ) : (
-
- Are you sure you want to delete this link?
-
- )}
+
+ {selectedLinks.length > 1 ? (
+
Are you sure you want to delete {selectedLinks.length} links?
+ ) : (
+
Are you sure you want to delete this link?
+ )}
-
-
-
- Warning: This action is irreversible!
-
-
+
+
+
+ Warning: This action is irreversible!
+
+
-
- Hold the Shift key while clicking
- 'Delete' to bypass this confirmation in the future.
-
+
+ Hold the Shift key while clicking
+ 'Delete' to bypass this confirmation in the future.
+
-
-
-
- );
+
+
+
+ );
}
diff --git a/components/ModalContent/BulkEditLinksModal.tsx b/components/ModalContent/BulkEditLinksModal.tsx
index 0a11ac5..c161f93 100644
--- a/components/ModalContent/BulkEditLinksModal.tsx
+++ b/components/ModalContent/BulkEditLinksModal.tsx
@@ -7,72 +7,74 @@ import toast from "react-hot-toast";
import Modal from "../Modal";
type Props = {
- onClose: Function;
+ onClose: Function;
};
export default function BulkEditLinksModal({ onClose }: Props) {
- const { updateLinks, selectedLinks, setSelectedLinks } = useLinkStore();
- const [submitLoader, setSubmitLoader] = useState(false);
- const [updatedValues, setUpdatedValues] = useState>({ tags: [] });
+ const { updateLinks, selectedLinks, setSelectedLinks } = useLinkStore();
+ const [submitLoader, setSubmitLoader] = useState(false);
+ const [updatedValues, setUpdatedValues] = useState<
+ Pick
+ >({ tags: [] });
- const setCollection = (e: any) => {
- const collectionId = e?.value || null;
- setUpdatedValues((prevValues) => ({ ...prevValues, collectionId }));
- };
+ const setCollection = (e: any) => {
+ const collectionId = e?.value || null;
+ setUpdatedValues((prevValues) => ({ ...prevValues, collectionId }));
+ };
- const setTags = (e: any) => {
- const tags = e.map((tag: any) => ({ name: tag.label }));
- setUpdatedValues((prevValues) => ({ ...prevValues, tags }));
- };
+ const setTags = (e: any) => {
+ const tags = e.map((tag: any) => ({ name: tag.label }));
+ setUpdatedValues((prevValues) => ({ ...prevValues, tags }));
+ };
- const submit = async () => {
- if (!submitLoader) {
- setSubmitLoader(true);
+ const submit = async () => {
+ if (!submitLoader) {
+ setSubmitLoader(true);
- const load = toast.loading("Updating...");
+ const load = toast.loading("Updating...");
- const response = await updateLinks(selectedLinks, updatedValues);
+ const response = await updateLinks(selectedLinks, updatedValues);
- toast.dismiss(load);
+ toast.dismiss(load);
- if (response.ok) {
- toast.success(`Updated!`);
- onClose();
- } else toast.error(response.data as string);
+ if (response.ok) {
+ toast.success(`Updated!`);
+ onClose();
+ } else toast.error(response.data as string);
- setSelectedLinks([]);
- setSubmitLoader(false);
- onClose();
- return response;
- }
- };
+ setSelectedLinks([]);
+ setSubmitLoader(false);
+ onClose();
+ return response;
+ }
+ };
- return (
-
- Edit Link
-
-
-
-
+ return (
+
+ Edit Link
+
+
+
+
+
-
-
-
-
- );
+
+
+
+
+ );
}
diff --git a/components/ModalContent/NewLinkModal.tsx b/components/ModalContent/NewLinkModal.tsx
index 3fde214..503103d 100644
--- a/components/ModalContent/NewLinkModal.tsx
+++ b/components/ModalContent/NewLinkModal.tsx
@@ -197,8 +197,9 @@ export default function NewLinkModal({ onClose }: Props) {
{optionsExpanded ? "Hide" : "More"} Options
diff --git a/lib/api/archiveHandler.ts b/lib/api/archiveHandler.ts
index 88ff97e..c43b6db 100644
--- a/lib/api/archiveHandler.ts
+++ b/lib/api/archiveHandler.ts
@@ -23,8 +23,7 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
const browser = await chromium.launch();
const context = await browser.newContext({
...devices["Desktop Chrome"],
- ignoreHTTPSErrors:
- process.env.IGNORE_HTTPS_ERRORS === "true",
+ ignoreHTTPSErrors: process.env.IGNORE_HTTPS_ERRORS === "true",
});
const page = await context.newPage();
diff --git a/lib/api/controllers/links/bulk/deleteLinksById.ts b/lib/api/controllers/links/bulk/deleteLinksById.ts
index cf671a6..466db98 100644
--- a/lib/api/controllers/links/bulk/deleteLinksById.ts
+++ b/lib/api/controllers/links/bulk/deleteLinksById.ts
@@ -3,53 +3,56 @@ import { UsersAndCollections } from "@prisma/client";
import getPermission from "@/lib/api/getPermission";
import removeFile from "@/lib/api/storage/removeFile";
-export default async function deleteLinksById(userId: number, linkIds: number[]) {
- if (!linkIds || linkIds.length === 0) {
- return { response: "Please choose valid links.", status: 401 };
- }
+export default async function deleteLinksById(
+ userId: number,
+ linkIds: number[]
+) {
+ if (!linkIds || linkIds.length === 0) {
+ return { response: "Please choose valid links.", status: 401 };
+ }
- const collectionIsAccessibleArray = [];
+ const collectionIsAccessibleArray = [];
- // Check if the user has access to the collection of each link
- // if any of the links are not accessible, return an error
- // if all links are accessible, continue with the deletion
- // and add the collection to the collectionIsAccessibleArray
- for (const linkId of linkIds) {
- const collectionIsAccessible = await getPermission({ userId, linkId });
+ // Check if the user has access to the collection of each link
+ // if any of the links are not accessible, return an error
+ // if all links are accessible, continue with the deletion
+ // and add the collection to the collectionIsAccessibleArray
+ for (const linkId of linkIds) {
+ const collectionIsAccessible = await getPermission({ userId, linkId });
- const memberHasAccess = collectionIsAccessible?.members.some(
- (e: UsersAndCollections) => e.userId === userId && e.canDelete
- );
+ const memberHasAccess = collectionIsAccessible?.members.some(
+ (e: UsersAndCollections) => e.userId === userId && e.canDelete
+ );
- if (!(collectionIsAccessible?.ownerId === userId || memberHasAccess)) {
- return { response: "Collection is not accessible.", status: 401 };
- }
+ if (!(collectionIsAccessible?.ownerId === userId || memberHasAccess)) {
+ return { response: "Collection is not accessible.", status: 401 };
+ }
- collectionIsAccessibleArray.push(collectionIsAccessible);
- }
+ collectionIsAccessibleArray.push(collectionIsAccessible);
+ }
- const deletedLinks = await prisma.link.deleteMany({
- where: {
- id: { in: linkIds },
- },
- });
+ const deletedLinks = await prisma.link.deleteMany({
+ where: {
+ id: { in: linkIds },
+ },
+ });
- // Loop through each link and delete the associated files
- // if the user has access to the collection
- for (let i = 0; i < linkIds.length; i++) {
- const linkId = linkIds[i];
- const collectionIsAccessible = collectionIsAccessibleArray[i];
+ // Loop through each link and delete the associated files
+ // if the user has access to the collection
+ for (let i = 0; i < linkIds.length; i++) {
+ const linkId = linkIds[i];
+ const collectionIsAccessible = collectionIsAccessibleArray[i];
- removeFile({
- filePath: `archives/${collectionIsAccessible?.id}/${linkId}.pdf`,
- });
- removeFile({
- filePath: `archives/${collectionIsAccessible?.id}/${linkId}.png`,
- });
- removeFile({
- filePath: `archives/${collectionIsAccessible?.id}/${linkId}_readability.json`,
- });
- }
+ removeFile({
+ filePath: `archives/${collectionIsAccessible?.id}/${linkId}.pdf`,
+ });
+ removeFile({
+ filePath: `archives/${collectionIsAccessible?.id}/${linkId}.png`,
+ });
+ removeFile({
+ filePath: `archives/${collectionIsAccessible?.id}/${linkId}_readability.json`,
+ });
+ }
- return { response: deletedLinks, status: 200 };
-}
\ No newline at end of file
+ return { response: deletedLinks, status: 200 };
+}
diff --git a/lib/api/controllers/links/bulk/updateLinks.ts b/lib/api/controllers/links/bulk/updateLinks.ts
index 7a52882..8f99fdc 100644
--- a/lib/api/controllers/links/bulk/updateLinks.ts
+++ b/lib/api/controllers/links/bulk/updateLinks.ts
@@ -1,31 +1,42 @@
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
import updateLinkById from "../linkId/updateLinkById";
-export default async function updateLinks(userId: number, links: LinkIncludingShortenedCollectionAndTags[], newData: Pick
) {
- let allUpdatesSuccessful = true;
+export default async function updateLinks(
+ userId: number,
+ links: LinkIncludingShortenedCollectionAndTags[],
+ newData: Pick<
+ LinkIncludingShortenedCollectionAndTags,
+ "tags" | "collectionId"
+ >
+) {
+ let allUpdatesSuccessful = true;
- // Have to use a loop here rather than updateMany, see the following:
- // https://github.com/prisma/prisma/issues/3143
- for (const link of links) {
- const updatedData: LinkIncludingShortenedCollectionAndTags = {
- ...link,
- tags: [...link.tags, ...(newData.tags ?? [])],
- collection: {
- ...link.collection,
- id: newData.collectionId ?? link.collection.id,
- }
- };
+ // Have to use a loop here rather than updateMany, see the following:
+ // https://github.com/prisma/prisma/issues/3143
+ for (const link of links) {
+ const updatedData: LinkIncludingShortenedCollectionAndTags = {
+ ...link,
+ tags: [...link.tags, ...(newData.tags ?? [])],
+ collection: {
+ ...link.collection,
+ id: newData.collectionId ?? link.collection.id,
+ },
+ };
- const updatedLink = await updateLinkById(userId, link.id as number, updatedData);
+ const updatedLink = await updateLinkById(
+ userId,
+ link.id as number,
+ updatedData
+ );
- if (updatedLink.status !== 200) {
- allUpdatesSuccessful = false;
- }
- }
+ if (updatedLink.status !== 200) {
+ allUpdatesSuccessful = false;
+ }
+ }
- if (allUpdatesSuccessful) {
- return { response: "All links updated successfully", status: 200 };
- } else {
- return { response: "Some links failed to update", status: 400 };
- }
-}
\ No newline at end of file
+ if (allUpdatesSuccessful) {
+ return { response: "All links updated successfully", status: 200 };
+ } else {
+ return { response: "Some links failed to update", status: 400 };
+ }
+}
diff --git a/lib/api/controllers/links/linkId/updateLinkById.ts b/lib/api/controllers/links/linkId/updateLinkById.ts
index ebfe2c0..6944999 100644
--- a/lib/api/controllers/links/linkId/updateLinkById.ts
+++ b/lib/api/controllers/links/linkId/updateLinkById.ts
@@ -48,9 +48,9 @@ export default async function updateLinkById(
collection: true,
pinnedBy: isCollectionOwner
? {
- where: { id: userId },
- select: { id: true },
- }
+ where: { id: userId },
+ select: { id: true },
+ }
: undefined,
},
});
@@ -111,9 +111,9 @@ export default async function updateLinkById(
collection: true,
pinnedBy: isCollectionOwner
? {
- where: { id: userId },
- select: { id: true },
- }
+ where: { id: userId },
+ select: { id: true },
+ }
: undefined,
},
});
diff --git a/lib/api/controllers/users/userId/updateUserById.ts b/lib/api/controllers/users/userId/updateUserById.ts
index 162f246..6bb7480 100644
--- a/lib/api/controllers/users/userId/updateUserById.ts
+++ b/lib/api/controllers/users/userId/updateUserById.ts
@@ -97,18 +97,18 @@ export default async function updateUserById(
id: { not: userId },
OR: emailEnabled
? [
- {
- username: data.username.toLowerCase(),
- },
- {
- email: data.email?.toLowerCase(),
- },
- ]
+ {
+ username: data.username.toLowerCase(),
+ },
+ {
+ email: data.email?.toLowerCase(),
+ },
+ ]
: [
- {
- username: data.username.toLowerCase(),
- },
- ],
+ {
+ username: data.username.toLowerCase(),
+ },
+ ],
},
});
diff --git a/lib/client/generateLinkHref.ts b/lib/client/generateLinkHref.ts
index 5911ae7..47c1888 100644
--- a/lib/client/generateLinkHref.ts
+++ b/lib/client/generateLinkHref.ts
@@ -1,27 +1,39 @@
-import { AccountSettings, ArchivedFormat, LinkIncludingShortenedCollectionAndTags } from "@/types/global";
+import {
+ AccountSettings,
+ ArchivedFormat,
+ LinkIncludingShortenedCollectionAndTags,
+} from "@/types/global";
import { LinksRouteTo } from "@prisma/client";
-import { pdfAvailable, readabilityAvailable, screenshotAvailable } from "../shared/getArchiveValidity";
+import {
+ pdfAvailable,
+ readabilityAvailable,
+ screenshotAvailable,
+} from "../shared/getArchiveValidity";
-export const generateLinkHref = (link: LinkIncludingShortenedCollectionAndTags, account: AccountSettings): string => {
+export const generateLinkHref = (
+ link: LinkIncludingShortenedCollectionAndTags,
+ account: AccountSettings
+): string => {
+ // Return the links href based on the account's preference
+ // If the user's preference is not available, return the original link
+ switch (account.linksRouteTo) {
+ case LinksRouteTo.ORIGINAL:
+ return link.url || "";
+ case LinksRouteTo.PDF:
+ if (!pdfAvailable(link)) return link.url || "";
- // Return the links href based on the account's preference
- // If the user's preference is not available, return the original link
- switch (account.linksRouteTo) {
- case LinksRouteTo.ORIGINAL:
- return link.url || '';
- case LinksRouteTo.PDF:
- if (!pdfAvailable(link)) return link.url || '';
+ return `/preserved/${link?.id}?format=${ArchivedFormat.pdf}`;
+ case LinksRouteTo.READABLE:
+ if (!readabilityAvailable(link)) return link.url || "";
- return `/preserved/${link?.id}?format=${ArchivedFormat.pdf}`;
- case LinksRouteTo.READABLE:
- if (!readabilityAvailable(link)) return link.url || '';
+ return `/preserved/${link?.id}?format=${ArchivedFormat.readability}`;
+ case LinksRouteTo.SCREENSHOT:
+ if (!screenshotAvailable(link)) return link.url || "";
- return `/preserved/${link?.id}?format=${ArchivedFormat.readability}`;
- case LinksRouteTo.SCREENSHOT:
- if (!screenshotAvailable(link)) return link.url || '';
-
- return `/preserved/${link?.id}?format=${link?.image?.endsWith("png") ? ArchivedFormat.png : ArchivedFormat.jpeg}`;
- default:
- return link.url || '';
- }
-};
\ No newline at end of file
+ return `/preserved/${link?.id}?format=${
+ link?.image?.endsWith("png") ? ArchivedFormat.png : ArchivedFormat.jpeg
+ }`;
+ default:
+ return link.url || "";
+ }
+};
diff --git a/lib/shared/getArchiveValidity.ts b/lib/shared/getArchiveValidity.ts
index ec74b22..0da5504 100644
--- a/lib/shared/getArchiveValidity.ts
+++ b/lib/shared/getArchiveValidity.ts
@@ -1,6 +1,8 @@
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
-export function screenshotAvailable(link: LinkIncludingShortenedCollectionAndTags) {
+export function screenshotAvailable(
+ link: LinkIncludingShortenedCollectionAndTags
+) {
return (
link &&
link.image &&
@@ -15,7 +17,9 @@ export function pdfAvailable(link: LinkIncludingShortenedCollectionAndTags) {
);
}
-export function readabilityAvailable(link: LinkIncludingShortenedCollectionAndTags) {
+export function readabilityAvailable(
+ link: LinkIncludingShortenedCollectionAndTags
+) {
return (
link &&
link.readable &&
diff --git a/pages/api/v1/links/index.ts b/pages/api/v1/links/index.ts
index c5af8ce..283a66f 100644
--- a/pages/api/v1/links/index.ts
+++ b/pages/api/v1/links/index.ts
@@ -43,7 +43,11 @@ export default async function links(req: NextApiRequest, res: NextApiResponse) {
response: newlink.response,
});
} else if (req.method === "PUT") {
- const updated = await updateLinks(user.id, req.body.links, req.body.newData);
+ const updated = await updateLinks(
+ user.id,
+ req.body.links,
+ req.body.newData
+ );
return res.status(updated.status).json({
response: updated.response,
});
diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx
index cdfc78d..1236aeb 100644
--- a/pages/collections/[id].tsx
+++ b/pages/collections/[id].tsx
@@ -34,7 +34,8 @@ export default function Index() {
const router = useRouter();
- const { links, selectedLinks, setSelectedLinks, deleteLinksById } = useLinkStore();
+ const { links, selectedLinks, setSelectedLinks, deleteLinksById } =
+ useLinkStore();
const { collections } = useCollectionStore();
const [sortBy, setSortBy] = useState(Sort.DateNewestFirst);
@@ -96,7 +97,6 @@ export default function Index() {
const [bulkDeleteLinksModal, setBulkDeleteLinksModal] = useState(false);
const [bulkEditLinksModal, setBulkEditLinksModal] = useState(false);
-
const [viewMode, setViewMode] = useState(
localStorage.getItem("viewMode") || ViewMode.Card
);
@@ -119,13 +119,24 @@ export default function Index() {
};
const bulkDeleteLinks = async () => {
- const load = toast.loading(`Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}...`);
+ const load = toast.loading(
+ `Deleting ${selectedLinks.length} Link${
+ selectedLinks.length > 1 ? "s" : ""
+ }...`
+ );
- const response = await deleteLinksById(selectedLinks.map((link) => link.id as number));
+ const response = await deleteLinksById(
+ selectedLinks.map((link) => link.id as number)
+ );
toast.dismiss(load);
- response.ok && toast.success(`Deleted ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}!`);
+ response.ok &&
+ toast.success(
+ `Deleted ${selectedLinks.length} Link${
+ selectedLinks.length > 1 ? "s" : ""
+ }!`
+ );
};
return (
@@ -133,8 +144,9 @@ export default function Index() {
{activeCollection && (
@@ -312,29 +324,42 @@ export default function Index() {
type="checkbox"
className="checkbox checkbox-primary"
onChange={() => handleSelectAll()}
- checked={selectedLinks.length === links.length && links.length > 0}
+ checked={
+ selectedLinks.length === links.length && links.length > 0
+ }
/>
{selectedLinks.length > 0 && (
- {selectedLinks.length} {selectedLinks.length === 1 ? 'link' : 'links'} selected
+ {selectedLinks.length}{" "}
+ {selectedLinks.length === 1 ? "link" : "links"} selected
)}
)}
- {selectedLinks.length > 0 && (permissions === true || permissions?.canUpdate) &&
-
- }
- {selectedLinks.length > 0 && (permissions === true || permissions?.canDelete) &&
-
- }
+ {selectedLinks.length > 0 &&
+ (permissions === true || permissions?.canUpdate) && (
+
+ )}
+ {selectedLinks.length > 0 &&
+ (permissions === true || permissions?.canDelete) && (
+
+ )}
@@ -375,7 +400,9 @@ export default function Index() {
/>
)}
{bulkDeleteLinksModal && (
-