mirror of
				https://github.com/karl0ss/homepage.git
				synced 2025-10-31 06:24:02 +00:00 
			
		
		
		
	Feature: Linkwarden service widget (#3836)
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									b9b7c482d4
								
							
						
					
					
						commit
						4d38222ba0
					
				| @ -55,6 +55,7 @@ You can also find a list of all available service widgets in the sidebar navigat | ||||
| - [Komga](komga.md) | ||||
| - [Kopia](kopia.md) | ||||
| - [Lidarr](lidarr.md) | ||||
| - [Linkwarden](linkwarden.md) | ||||
| - [Mastodon](mastodon.md) | ||||
| - [Mealie](mealie.md) | ||||
| - [Medusa](medusa.md) | ||||
|  | ||||
							
								
								
									
										15
									
								
								docs/widgets/services/linkwarden.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								docs/widgets/services/linkwarden.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| --- | ||||
| title: Linkwarden | ||||
| description: Linkwarden Widget Configuration | ||||
| --- | ||||
| 
 | ||||
| Learn more about [Linkwarden](https://linkwarden.app/). | ||||
| 
 | ||||
| Allowed fields: `["links", "collections", "tags"]`. | ||||
| 
 | ||||
| ```yaml | ||||
| widget: | ||||
|   type: linkwarden | ||||
|   url: http://linkwarden.host.or.ip | ||||
|   key: myApiKeyHere # On your Linkwarden install, go to Settings > Access Tokens. Generate a token. | ||||
| ``` | ||||
| @ -80,6 +80,7 @@ nav: | ||||
|           - widgets/services/komga.md | ||||
|           - widgets/services/kopia.md | ||||
|           - widgets/services/lidarr.md | ||||
|           - widgets/services/linkwarden.md | ||||
|           - widgets/services/mastodon.md | ||||
|           - widgets/services/mealie.md | ||||
|           - widgets/services/medusa.md | ||||
|  | ||||
| @ -905,5 +905,10 @@ | ||||
|         "cameras": "Cameras", | ||||
|         "uptime": "Uptime", | ||||
|         "version": "Version" | ||||
|     }, | ||||
|     "linkwarden": { | ||||
|         "links": "Links", | ||||
|         "collections": "Collections", | ||||
|         "tags": "Tags" | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -35,9 +35,16 @@ export default async function credentialedProxyHandler(req, res, map) { | ||||
|       } else if (widget.type === "gotify") { | ||||
|         headers["X-gotify-Key"] = `${widget.key}`; | ||||
|       } else if ( | ||||
|         ["authentik", "cloudflared", "ghostfolio", "mealie", "tailscale", "tandoor", "pterodactyl"].includes( | ||||
|           widget.type, | ||||
|         ) | ||||
|         [ | ||||
|           "authentik", | ||||
|           "cloudflared", | ||||
|           "ghostfolio", | ||||
|           "linkwarden", | ||||
|           "mealie", | ||||
|           "tailscale", | ||||
|           "tandoor", | ||||
|           "pterodactyl", | ||||
|         ].includes(widget.type) | ||||
|       ) { | ||||
|         headers.Authorization = `Bearer ${widget.key}`; | ||||
|       } else if (widget.type === "truenas") { | ||||
|  | ||||
| @ -54,6 +54,7 @@ const components = { | ||||
|   komga: dynamic(() => import("./komga/component")), | ||||
|   kopia: dynamic(() => import("./kopia/component")), | ||||
|   lidarr: dynamic(() => import("./lidarr/component")), | ||||
|   linkwarden: dynamic(() => import("./linkwarden/component")), | ||||
|   mastodon: dynamic(() => import("./mastodon/component")), | ||||
|   mealie: dynamic(() => import("./mealie/component")), | ||||
|   medusa: dynamic(() => import("./medusa/component")), | ||||
|  | ||||
							
								
								
									
										55
									
								
								src/widgets/linkwarden/component.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/widgets/linkwarden/component.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| import React, { useState, useEffect } from "react"; | ||||
| 
 | ||||
| import Container from "components/services/widget/container"; | ||||
| import Block from "components/services/widget/block"; | ||||
| import useWidgetAPI from "utils/proxy/use-widget-api"; | ||||
| 
 | ||||
| export default function Component({ service }) { | ||||
|   const { widget } = service; | ||||
| 
 | ||||
|   const [stats, setStats] = useState({ | ||||
|     totalLinks: null, | ||||
|     collections: { total: null }, | ||||
|     tags: { total: null }, | ||||
|   }); | ||||
| 
 | ||||
|   const { data: collectionsStatsData, error: collectionsStatsError } = useWidgetAPI(widget, "collections"); | ||||
|   const { data: tagsStatsData, error: tagsStatsError } = useWidgetAPI(widget, "tags"); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (collectionsStatsData?.response && tagsStatsData?.response) { | ||||
|       setStats({ | ||||
|         // eslint-disable-next-line no-underscore-dangle | ||||
|         totalLinks: collectionsStatsData.response.reduce((sum, collection) => sum + (collection._count?.links || 0), 0), | ||||
|         collections: { | ||||
|           total: collectionsStatsData.response.length, | ||||
|         }, | ||||
|         tags: { | ||||
|           total: tagsStatsData.response.length, | ||||
|         }, | ||||
|       }); | ||||
|     } | ||||
|   }, [collectionsStatsData, tagsStatsData]); | ||||
| 
 | ||||
|   if (collectionsStatsError || tagsStatsError) { | ||||
|     return <Container service={service} error={collectionsStatsError || tagsStatsError} />; | ||||
|   } | ||||
| 
 | ||||
|   if (!tagsStatsData || !collectionsStatsData) { | ||||
|     return ( | ||||
|       <Container service={service}> | ||||
|         <Block label="linkwarden.links" /> | ||||
|         <Block label="linkwarden.collections" /> | ||||
|         <Block label="linkwarden.tags" /> | ||||
|       </Container> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <Container service={service}> | ||||
|       <Block label="linkwarden.links" value={stats.totalLinks} /> | ||||
|       <Block label="linkwarden.collections" value={stats.collections.total} /> | ||||
|       <Block label="linkwarden.tags" value={stats.tags.total} /> | ||||
|     </Container> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										17
									
								
								src/widgets/linkwarden/widget.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/widgets/linkwarden/widget.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; | ||||
| 
 | ||||
| const widget = { | ||||
|   api: "{url}/api/v1/{endpoint}", | ||||
|   proxyHandler: credentialedProxyHandler, | ||||
| 
 | ||||
|   mappings: { | ||||
|     collections: { | ||||
|       endpoint: "collections", | ||||
|     }, | ||||
|     tags: { | ||||
|       endpoint: "tags", | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export default widget; | ||||
| @ -46,6 +46,7 @@ import kavita from "./kavita/widget"; | ||||
| import komga from "./komga/widget"; | ||||
| import kopia from "./kopia/widget"; | ||||
| import lidarr from "./lidarr/widget"; | ||||
| import linkwarden from "./linkwarden/widget"; | ||||
| import mastodon from "./mastodon/widget"; | ||||
| import mealie from "./mealie/widget"; | ||||
| import medusa from "./medusa/widget"; | ||||
| @ -167,6 +168,7 @@ const widgets = { | ||||
|   komga, | ||||
|   kopia, | ||||
|   lidarr, | ||||
|   linkwarden, | ||||
|   mastodon, | ||||
|   mealie, | ||||
|   medusa, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 PyrokineticDarkElf
						PyrokineticDarkElf