feat: add last updated timestamp to provider tokens in dashboard and API

This commit is contained in:
ramvignesh-b
2026-05-11 13:59:36 +05:30
parent 1fae60c0b3
commit 7302db69f7
3 changed files with 31 additions and 8 deletions
+1
View File
@@ -39,5 +39,6 @@ export class TokenManager {
tokens.expiresIn,
);
await this.redis.set(`provider:${providerName}:refresh_token`, tokens.refreshToken);
await this.redis.set(`provider:${providerName}:last_updated`, new Date().toISOString());
}
}
+2 -1
View File
@@ -17,7 +17,8 @@ apiRoutes.get("/status", async (c) => {
for (const provider of Object.keys(providers)) {
const accessToken = await redis.get(`provider:${provider}:access_token`);
const refreshToken = await redis.get(`provider:${provider}:refresh_token`);
status[provider] = { accessToken, refreshToken };
const lastUpdated = await redis.get(`provider:${provider}:last_updated`);
status[provider] = { accessToken, refreshToken, lastUpdated } as any;
}
return c.json(status);
+28 -7
View File
@@ -140,13 +140,14 @@
<div class="relative group">
<input type="url" id="redirectUri" readonly
class="input input-bordered w-full pr-12 focus:outline-none cursor-default opacity-80" />
<button type="button" onclick="copyRedirectUri()"
<button type="button" onclick="copyRedirectUri()"
class="btn btn-ghost btn-xs absolute right-2 top-1/2 -translate-y-1/2 text-base-content/40 hover:text-primary transition-colors">
<i class="ph ph-copy text-sm"></i>
</button>
</div>
<label class="label py-0.5">
<span class="label-text-alt opacity-40 italic text-[10px]">Must match provider's callback URL</span>
<span class="label-text-alt opacity-40 italic text-[10px]">Must match provider's
callback URL</span>
</label>
</div>
<div class="form-control">
@@ -193,12 +194,17 @@
<th
class="rounded-none font-bold uppercase tracking-wider text-[10px] opacity-60 px-6">
Provider</th>
<th class="font-bold uppercase tracking-wider text-[10px] opacity-60 px-6">Access
<th class="font-bold uppercase tracking-wider text-[10px] opacity-60 px-6 w-1/3">
Access
Token</th>
<th class="font-bold uppercase tracking-wider text-[10px] opacity-60 px-6">Refresh
<th class="font-bold uppercase tracking-wider text-[10px] opacity-60 px-6 w-1/3">
Refresh
Token</th>
<th
class="rounded-none text-right font-bold uppercase tracking-wider text-[10px] opacity-60 px-6">
class="font-bold uppercase tracking-wider text-[10px] opacity-60 px-6 whitespace-nowrap">
Last Updated</th>
<th
class="rounded-none text-right font-bold uppercase tracking-wider text-[10px] opacity-60 px-1 w-px">
Actions</th>
</tr>
</thead>
@@ -291,17 +297,29 @@
}
}
function formatTimeAgo(dateString) {
if (!dateString) return '<span class="opacity-30">Never</span>';
const date = new Date(dateString);
const now = new Date();
const diffInSeconds = Math.floor((now - date) / 1000);
if (diffInSeconds < 60) return 'Just now';
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
return date.toLocaleDateString();
}
function renderTable() {
providerTableBody.innerHTML = '';
const entries = Object.entries(providerData);
if (entries.length === 0) {
providerTableBody.innerHTML = '<tr><td colspan="4" class="text-center py-16 opacity-50 font-medium italic">No providers configured yet.</td></tr>';
providerTableBody.innerHTML = '<tr><td colspan="5" class="text-center py-16 opacity-50 font-medium italic">No providers configured yet.</td></tr>';
return;
}
for (const [name, config] of entries) {
const status = tokenStatus[name] || { accessToken: null, refreshToken: null };
const status = tokenStatus[name] || { accessToken: null, refreshToken: null, lastUpdated: null };
const row = document.createElement('tr');
row.className = "hover:bg-base-200/30 transition-colors group";
@@ -314,6 +332,9 @@
</td>
<td class="px-6 py-4">${renderTokenCell(name, 'access', status.accessToken)}</td>
<td class="px-6 py-4">${renderTokenCell(name, 'refresh', status.refreshToken)}</td>
<td class="px-6 py-4">
<span class="text-xs font-medium opacity-60">${formatTimeAgo(status.lastUpdated)}</span>
</td>
<td class="px-6 py-4 text-right">
<div class="flex gap-2 justify-end opacity-0 group-hover:opacity-100 transition-opacity">
<a href="/auth/${name}/login" target="_blank" class="btn btn-xs btn-primary shadow-sm" title="Authenticate">