// Copyright © 2026 Olaf Kolkman // SPDX-License-Identifier: GPL-3.0-or-later (() => { const labelAuthNotice = document.querySelector('#label-auth-notice'); const labelControls = document.querySelector('#label-controls'); const labelForm = document.querySelector('#label-form'); const labelNameInput = document.querySelector('#label-name'); const labelStatus = document.querySelector('#label-status'); const labelList = document.querySelector('#label-list'); const accessToken = localStorage.getItem('linklogAccessToken'); let currentUserId = null; function authHeaders(includeJson = false) { return { ...(includeJson ? {'Content-Type': 'application/json'} : {}), ...(accessToken ? {Authorization: `Bearer ${accessToken}`} : {}), }; } function setStatus(message, isError = false) { if (!labelStatus) return; labelStatus.textContent = message; labelStatus.style.color = isError ? '#b91c1c' : '#166534'; } async function responseError(response, fallback) { try { const result = await response.json(); return result.detail || result.message || fallback; } catch { return fallback; } } function renderLabels(labels) { if (!labelList) return; if (!labels || labels.length === 0) { labelList.innerHTML = '

No labels found.

'; return; } labelList.replaceChildren(...labels.map((label) => { const row = document.createElement('div'); row.className = 'plugin-row'; const isOwned = label.created_by === currentUserId; const contentContainer = document.createElement('div'); contentContainer.style.display = 'flex'; contentContainer.style.alignItems = 'center'; contentContainer.style.justifySpaceBetween = 'space-between'; contentContainer.style.width = '100%'; const text = document.createElement('span'); text.textContent = `${label.name}${isOwned ? '' : (label.creator ? ` (${label.creator})` : ' (default)')}`; contentContainer.appendChild(text); if (isOwned) { const actions = document.createElement('div'); actions.style.display = 'flex'; actions.style.gap = '8px'; const editButton = document.createElement('button'); editButton.type = 'button'; editButton.textContent = 'Edit'; editButton.addEventListener('click', () => { showInlineEdit(row, label); }); const deleteButton = document.createElement('button'); deleteButton.type = 'button'; deleteButton.className = 'danger-button'; deleteButton.textContent = 'Delete'; deleteButton.addEventListener('click', async () => { if (!confirm(`Are you sure you want to delete "${label.name}"?`)) return; setStatus(''); const response = await fetch(`/api/user/labels/${label.id}`, { method: 'DELETE', headers: authHeaders(), }); if (response.ok) { setStatus(`Deleted label ${label.name}`); loadLabels(); } else { setStatus(await responseError(response, 'Could not delete label'), true); } }); actions.append(editButton, deleteButton); contentContainer.appendChild(actions); } row.appendChild(contentContainer); return row; })); } function showInlineEdit(rowContainer, label) { rowContainer.replaceChildren(); const editForm = document.createElement('form'); editForm.style.display = 'flex'; editForm.style.gap = '8px'; editForm.style.width = '100%'; editForm.style.alignItems = 'center'; const input = document.createElement('input'); input.type = 'text'; input.value = label.name; input.required = true; input.style.flex = '1'; const saveButton = document.createElement('button'); saveButton.type = 'submit'; saveButton.textContent = 'Save'; const cancelButton = document.createElement('button'); cancelButton.type = 'button'; cancelButton.textContent = 'Cancel'; cancelButton.addEventListener('click', () => { loadLabels(); }); editForm.append(input, saveButton, cancelButton); editForm.addEventListener('submit', async (e) => { e.preventDefault(); const newName = input.value.trim(); if (!newName) return; setStatus(''); const response = await fetch(`/api/user/labels/${label.id}`, { method: 'PUT', headers: authHeaders(true), body: JSON.stringify({ name: newName }), }); if (response.ok) { setStatus(`Updated label to ${newName}`); loadLabels(); } else { setStatus(await responseError(response, 'Could not update label'), true); } }); rowContainer.appendChild(editForm); input.focus(); } async function loadLabels() { try { const response = await fetch('/api/user/labels', { headers: authHeaders() }); if (!response.ok) throw new Error('Could not load labels'); const labels = await response.json(); renderLabels(labels); } catch (error) { setStatus('Error loading labels', true); } } async function init() { if (!accessToken) { if (labelAuthNotice) labelAuthNotice.classList.remove('hidden'); if (labelControls) labelControls.classList.add('hidden'); return; } if (labelAuthNotice) labelAuthNotice.classList.add('hidden'); if (labelControls) labelControls.classList.remove('hidden'); try { const meResponse = await fetch('/api/auth/me', { headers: authHeaders() }); if (meResponse.ok) { const me = await meResponse.json(); currentUserId = me.id; } } catch { // Proceed if me fails } await loadLabels(); if (labelForm) { labelForm.addEventListener('submit', async (e) => { e.preventDefault(); const name = labelNameInput.value.trim(); if (!name) return; setStatus(''); const response = await fetch('/api/user/labels', { method: 'POST', headers: authHeaders(true), body: JSON.stringify({ name }), }); if (response.ok) { labelNameInput.value = ''; setStatus(`Added label ${name}`); loadLabels(); } else { setStatus(await responseError(response, 'Could not add label'), true); } }); } } document.addEventListener('DOMContentLoaded', init); if (document.readyState !== 'loading') { init(); } })();