From a1e450385a4bf5c16e8fc9de939e797cfa091a5e Mon Sep 17 00:00:00 2001 From: Rowan Brooks Date: Tue, 24 Feb 2026 18:22:38 -0700 Subject: [PATCH 1/3] feat: add re-auth button to configured services cards (#329) --- src/routes/ui/services.js | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/routes/ui/services.js b/src/routes/ui/services.js index 1e3d0b4..4d6e1af 100644 --- a/src/routes/ui/services.js +++ b/src/routes/ui/services.js @@ -175,12 +175,23 @@ export function renderConfiguredCards(accounts) { const displayName = svcModule?.displayName || serviceId; const icon = getServiceIcon(serviceId); - const accountRows = svcAccounts.map(acc => ` + const accountRows = svcAccounts.map(acc => { + const retryRoute = getRetryRoute(serviceId); + const { hasToken, hasCredentials } = acc.status || {}; + const reauthBtn = (retryRoute && hasCredentials) ? ` +
+ + +
` : ''; + return `
- Details -
- `).join(''); +
+ ${reauthBtn} + Details +
+ `; + }).join(''); return `
@@ -194,6 +205,21 @@ export function renderConfiguredCards(accounts) { }).join('\n'); } +/** + * Get the OAuth retry/re-auth route for a service, or null if not an OAuth service. + */ +function getRetryRoute(service) { + const routes = { + youtube: '/ui/youtube/retry', + google_calendar: '/ui/google/retry', + fitbit: '/ui/fitbit/retry', + linkedin: '/ui/linkedin/retry', + reddit: '/ui/reddit/retry', + mastodon: '/ui/mastodon/retry' + }; + return routes[service] || null; +} + function getServiceIcon(service) { const icons = { github: '/public/icons/github.svg', From 114f93324cf2d8a5b86031d15d969f0e70117116 Mon Sep 17 00:00:00 2001 From: Rowan Brooks Date: Tue, 24 Feb 2026 18:22:39 -0700 Subject: [PATCH 2/3] feat: add re-authorize button to service detail page (#329) --- src/routes/ui/service-detail.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/routes/ui/service-detail.js b/src/routes/ui/service-detail.js index b3f2168..77ef1e2 100644 --- a/src/routes/ui/service-detail.js +++ b/src/routes/ui/service-detail.js @@ -60,6 +60,17 @@ router.get('/:id', (req, res) => { const displayName = serviceModule?.displayName || serviceInfo?.name || account.service; const icon = getServiceIcon(account.service); + // OAuth re-auth route (null for non-OAuth services) + const oauthRetryRoutes = { + youtube: '/ui/youtube/retry', + google_calendar: '/ui/google/retry', + fitbit: '/ui/fitbit/retry', + linkedin: '/ui/linkedin/retry', + reddit: '/ui/reddit/retry', + mastodon: '/ui/mastodon/retry' + }; + const retryRoute = oauthRetryRoutes[account.service] || null; + // Build credential fields const creds = account.credentials || {}; const credFields = Object.keys(creds).map(key => { @@ -79,6 +90,7 @@ router.get('/:id', (req, res) => { displayName, icon, credFields, + retryRoute, escapeHtml, renderAvatar }); From c0989f03d3d6da138ade48ee954af85758500766 Mon Sep 17 00:00:00 2001 From: Rowan Brooks Date: Tue, 24 Feb 2026 18:22:39 -0700 Subject: [PATCH 3/3] feat: add re-authorize button to service detail template (#329) --- views/pages/service-detail.ejs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/views/pages/service-detail.ejs b/views/pages/service-detail.ejs index 1a18eb5..c1fcdf8 100644 --- a/views/pages/service-detail.ejs +++ b/views/pages/service-detail.ejs @@ -8,6 +8,12 @@

Credentials

Stored credentials for this service instance.

+ <% if (retryRoute) { %> +
+ + +
+ <% } %> <% if (credFields.length === 0) { %>

No credentials stored.

<% } else { %>