diff --git a/docs/widgets/services/linkwarden.md b/docs/widgets/services/linkwarden.md
index d5a9fb27..bef196a9 100644
--- a/docs/widgets/services/linkwarden.md
+++ b/docs/widgets/services/linkwarden.md
@@ -13,47 +13,3 @@ widget:
url: http://linkwarden.host.or.ip
key: myApiKeyHere # On your Linkwarden install, go to Settings > Access Tokens. Generate a token.
```
-
-Use `mode` to show a list of recent bookmarks.
-
-```yaml
-widget:
- type: linkwarden
- url: http://linkwarden.host.or.ip
- key: myApiKeyHere
- mode: ["recent"]
-```
-
-Use `params` to set which collections and/or tags to display links from.
-
-Examples:
-
-```yaml
-params:
- collectionIds: ["8", "13", "6"] # ID's of collections
-```
-
-or
-
-```yaml
-params:
- tagIds: ["84", "66", "88", "69"] # ID's of tags
-```
-
-or
-
-```yaml
-params:
- collectionIds: ["8", "13", "6"] # ID's of collections
- tagIds: ["84", "66", "88", "69"] # ID's of tags
-```
-
-```yaml
-widget:
- type: linkwarden
- url: http://linkwarden.host.or.ip
- key: myApiKeyHere
- params:
- collectionIds: ["8", "13", "6"] # ID's of collections
- tagIds: ["84", "66", "88", "69"] # ID's of tags
-```
diff --git a/src/widgets/linkwarden/component.jsx b/src/widgets/linkwarden/component.jsx
index b11e9b14..657d8b11 100644
--- a/src/widgets/linkwarden/component.jsx
+++ b/src/widgets/linkwarden/component.jsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useMemo, useCallback } from "react";
+import React, { useState, useEffect } from "react";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
@@ -7,39 +7,13 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { widget } = service;
- // Assign icons. Assign recent/collections/tags to query by id(s)
- const bookmarkTypes = useMemo(
- () => ({
- recent: { ids: widget.mode?.includes("recent") ? ["0"] : [] }, // "0" Is a made-up number used to allow looping in processBookmarks()
- collection: {
- ids: widget.params?.collectionIds ? widget.params.collectionIds : [],
- },
- tag: { ids: widget.params?.tagIds ? widget.params.tagIds : [] },
- }),
- [widget],
- );
-
// State to hold Stats
const [stats, setStats] = useState({
totalLinks: null,
- collections: { list: null, total: null },
- tags: { list: null, total: null },
+ collections: { total: null },
+ tags: { total: null },
});
- // State to hold Recent/Collection/Tag Bookmarks
- const [bookmarks, setBookmarks] = useState({
- recent: { icon: "📚️", data: {} },
- collection: { icon: "📁", data: {} },
- tag: { icon: "🏷️", data: {} },
- });
-
- const [fetchingMore, setFetchingMore] = useState({
- recent: {},
- collection: {},
- tag: {},
- });
- const [error, setError] = useState(null);
-
const { data: collectionsStatsData, error: collectionsStatsError } = useWidgetAPI(widget, "collections"); // Fetch Collection Stats
const { data: tagsStatsData, error: tagsStatsError } = useWidgetAPI(widget, "tags"); // Fetch Tag Stats
@@ -50,11 +24,9 @@ export default function Component({ service }) {
setStats({
totalLinks: collectionsStatsData.response.reduce((sum, collection) => sum + (collection._count?.links || 0), 0),
collections: {
- list: collectionsStatsData.response,
total: collectionsStatsData.response.length,
},
tags: {
- list: tagsStatsData.response,
total: tagsStatsData.response.length,
},
});
@@ -62,199 +34,16 @@ export default function Component({ service }) {
}
}, [collectionsStatsData, tagsStatsData]);
- // Reusable function to fetch bookmarks based on ids.recent/ids.collection/ids.tag and type
- const fetchBookmarks = useCallback(async (ids, type, cursor, currentWidget) => {
- try {
- const promises = ids.map(async (id) => {
- const baseQuery = { sort: 0, cursor: cursor || "" };
- const query = type === "recent" ? baseQuery : { ...baseQuery, [`${type}Id`]: id };
-
- const queryParams = new URLSearchParams({
- group: currentWidget.service_group,
- service: currentWidget.service_name,
- endpoint: "links",
- query: JSON.stringify(query),
- });
-
- const response = await fetch(`/api/services/proxy?${queryParams}`);
- if (!response.ok) {
- if (response.status === 401) {
- setError("Unauthorized access. Please log in again.");
- } else {
- setError(`HTTP error! Status: ${response.status}`);
- }
- throw new Error(`HTTP error! Status: ${response.status}`);
- }
- return { id, bookmarks: await response.json() };
- });
-
- return await Promise.all(promises);
- } catch (fetchError) {
- setError("An error occurred while fetching bookmarks.");
- return [];
- }
- }, []);
-
- const processBookmarks = useCallback(
- async (ids, type, cursor, currentWidget, currentStats, updateBookmarks, append = false) => {
- try {
- const fetchedBookmarks = await fetchBookmarks(ids, type, cursor, currentWidget);
- updateBookmarks((prev) => {
- const newBookmarks = fetchedBookmarks.map((item) => ({
- id: item.id,
- title:
- type === "recent"
- ? "Recent Bookmarks"
- : currentStats[`${type}s`]?.list?.find((statItem) => statItem.id.toString() === item.id)?.name ||
- item.id,
- url: `${currentWidget.url}${type === "recent" ? "/links/" : `/${type}s/${item.id}/`}`,
- /* eslint-disable no-underscore-dangle */
- total:
- type === "recent"
- ? currentStats.totalLinks
- : currentStats[`${type}s`]?.list?.find((foundStatItem) => foundStatItem.id.toString() === item.id)
- ?._count?.links || 0,
- /* eslint-enable no-underscore-dangle */
- cursor: item.bookmarks.response.length
- ? item.bookmarks.response[item.bookmarks.response.length - 1]?.id
- : "end",
- bookmarks: append
- ? [...(prev[type].data[item.id]?.bookmarks || []), ...item.bookmarks.response]
- : item.bookmarks.response,
- }));
-
- return {
- ...prev,
- [type]: {
- ...prev[type],
- data: {
- ...prev[type].data,
- ...Object.fromEntries(newBookmarks.map((bookmark) => [bookmark.id, bookmark])),
- },
- },
- };
- });
- } catch (processError) {
- const errorMessage = `Error setting ${type} bookmarks: ${processError.message}`;
- setError(errorMessage);
- }
- },
- [fetchBookmarks],
- );
-
- // Effect to fetch and update Recent/Collection/Tag Bookmarks
- useEffect(() => {
- if (error) return; // Stop fetching if there's an error
-
- const fetchAndProcessBookmarks = async () => {
- try {
- const bookmarkFetchPromises = Object.entries(bookmarkTypes)
- .filter(([type, { ids }]) => ids.length > 0 && Object.keys(bookmarks[type].data).length === 0)
- .map(async ([type, { ids }]) => {
- // Process bookmarks for each type
- await processBookmarks(ids, type, null, widget, stats, setBookmarks);
- });
-
- await Promise.all(bookmarkFetchPromises);
- } catch (fetchError) {
- setError(`Error processing bookmarks: ${fetchError.message}`);
- }
- };
-
- fetchAndProcessBookmarks();
- }, [bookmarkTypes, processBookmarks, widget, stats, bookmarks, error]);
-
- const handleScroll = async (event, id, type, cursor) => {
- const { scrollTop, scrollHeight, clientHeight } = event.target;
- if (scrollHeight - scrollTop <= clientHeight + 1 && cursor !== "end") {
- if (!fetchingMore[type][id]) {
- setFetchingMore((prev) => ({
- ...prev,
- [type]: { ...prev[type], [id]: true },
- }));
- try {
- await processBookmarks([id], type, cursor, widget, stats, setBookmarks, true);
- } finally {
- setFetchingMore((prev) => ({
- ...prev,
- [type]: { ...prev[type], [id]: false },
- }));
- }
- }
- }
- };
-
- // Handle errors
- if (error) {
- return