diff --git a/dashboard/src/main.js b/dashboard/src/main.js
index feb4efe..372d3cb 100644
--- a/dashboard/src/main.js
+++ b/dashboard/src/main.js
@@ -50,7 +50,7 @@ async function init() {
if (!isLoggedIn()) {
const extAuth = await getAuthFromExtension();
if (extAuth) {
- setAuth(extAuth.authToken, extAuth.authUser);
+ setAuth(extAuth.token, extAuth.user);
}
}
@@ -248,7 +248,7 @@ function renderTopPages(topUrls) {
${escHtml(page.source_title || page.source_url)}
${Number(page.count) || 0} annotation${Number(page.count) !== 1 ? 's' : ''}
`;
- if (page.source_url) {
+ if (page.source_url && /^https?:\/\//i.test(page.source_url)) {
el.addEventListener('click', () => window.open(page.source_url, '_blank'));
}
listEl.appendChild(el);
@@ -277,7 +277,15 @@ async function loadItemsList(typeFilter) {
for (const item of items.slice(0, 50)) {
const icon = item.type === 'issue' ? '\ud83d\udc1b' : '\ud83d\udcac';
const time = item.created_at ? new Date(item.created_at).toLocaleString() : '';
- const sourceLabel = item.source_title || (item.source_url ? new URL(item.source_url).hostname + new URL(item.source_url).pathname.substring(0, 30) : '');
+ let sourceLabel = item.source_title || '';
+ if (!sourceLabel && item.source_url) {
+ try {
+ const parsed = new URL(item.source_url);
+ sourceLabel = parsed.hostname + parsed.pathname.substring(0, 30);
+ } catch {
+ sourceLabel = item.source_url.substring(0, 40);
+ }
+ }
const el = document.createElement('div');
el.className = 'activity-item' + (item.source_url ? ' activity-item-link' : '');
el.innerHTML = `
@@ -288,7 +296,7 @@ async function loadItemsList(typeFilter) {
${renderItemDispatches(item.dispatches)}
${time ? escHtml(time) : ''}
`;
- if (item.source_url) {
+ if (item.source_url && /^https?:\/\//i.test(item.source_url)) {
el.addEventListener('click', (e) => {
if (e.target.closest('.dispatch-ext-link')) return;
window.open(item.source_url, '_blank');
@@ -881,7 +889,10 @@ function renderAuthsTable() {
for (const auth of allAuths) {
const creds = typeof auth.credentials === 'string' ? JSON.parse(auth.credentials) : (auth.credentials || {});
- const credSummary = Object.entries(creds).map(([k, v]) => `${k}: ${v}`).join(', ');
+ const credSummary = Object.entries(creds).map(([k, v]) => {
+ const masked = typeof v === 'string' && v.length > 4 ? '••••' + v.slice(-4) : '••••';
+ return `${k}: ${masked}`;
+ }).join(', ');
const tr = document.createElement('tr');
tr.innerHTML = `
${escHtml(auth.name)} |