style: apply gofmt across Go sources
Repo-wide gofmt sweep: const-block alignment, doc-comment spacing, statement-after-brace fix in media.go, trailing blank lines. No semantic changes — whitespace-insensitive diff is empty for every file in this commit.
This commit is contained in:
1 parent
dd2ab4ea96
commit
8733e83f1f
29 files changed
+91
-1725
No files matched your search
@@ -1,160 +0,0 @@
|
||||
import { Alpine } from "./alpine";
|
||||
import { getToken } from "./storage";
|
||||
|
||||
let endpointPath = "";
|
||||
let exampleResponse: unknown = null;
|
||||
|
||||
function initAPIExplorerDoc(path: string, response: string): void {
|
||||
endpointPath = path;
|
||||
exampleResponse = JSON.parse(response);
|
||||
}
|
||||
|
||||
function showDocMode(mode: "mock" | "real"): void {
|
||||
const mockBtn = document.getElementById("mock-btn");
|
||||
const realBtn = document.getElementById("real-btn");
|
||||
const responseBody = document.getElementById("response-body");
|
||||
const responseStatus = document.getElementById("response-status");
|
||||
const responseTime = document.getElementById("response-time");
|
||||
const apiResponse = document.querySelector(".api-response");
|
||||
const requestBody = document.getElementById("request-body") as HTMLTextAreaElement;
|
||||
const tryItOut = document.getElementById("try-it-out");
|
||||
|
||||
if (
|
||||
!mockBtn ||
|
||||
!realBtn ||
|
||||
!responseBody ||
|
||||
!responseStatus ||
|
||||
!responseTime ||
|
||||
!apiResponse ||
|
||||
!requestBody ||
|
||||
!tryItOut
|
||||
)
|
||||
return;
|
||||
|
||||
if (mode === "mock") {
|
||||
mockBtn.classList.add("bg-accent", "text-white");
|
||||
mockBtn.classList.remove("bg-background-primary", "text-text-primary");
|
||||
realBtn.classList.remove("bg-accent", "text-white");
|
||||
realBtn.classList.add("bg-background-primary", "text-text-primary");
|
||||
|
||||
apiResponse.classList.remove("hidden");
|
||||
requestBody.readOnly = true;
|
||||
tryItOut.classList.add("hidden");
|
||||
responseBody.textContent = JSON.stringify(exampleResponse, null, 2);
|
||||
responseStatus.textContent = "200 OK";
|
||||
responseTime.textContent = "Mock";
|
||||
} else {
|
||||
realBtn.classList.add("bg-accent", "text-white");
|
||||
realBtn.classList.remove("bg-background-primary", "text-text-primary");
|
||||
mockBtn.classList.remove("bg-accent", "text-white");
|
||||
mockBtn.classList.add("bg-background-primary", "text-text-primary");
|
||||
|
||||
apiResponse.classList.add("hidden");
|
||||
requestBody.readOnly = false;
|
||||
tryItOut.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
async function tryDocEndpoint(): Promise<void> {
|
||||
const methodSelect = document.getElementById("http-method") as HTMLSelectElement;
|
||||
const requestBody = document.getElementById("request-body") as HTMLTextAreaElement;
|
||||
const responseBody = document.getElementById("response-body");
|
||||
const responseStatus = document.getElementById("response-status");
|
||||
const responseTime = document.getElementById("response-time");
|
||||
const apiResponse = document.querySelector(".api-response");
|
||||
|
||||
if (
|
||||
!methodSelect ||
|
||||
!requestBody ||
|
||||
!responseBody ||
|
||||
!responseStatus ||
|
||||
!responseTime ||
|
||||
!apiResponse
|
||||
)
|
||||
return;
|
||||
|
||||
const method = methodSelect.value;
|
||||
const body = requestBody.value;
|
||||
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
throw new Error("No authentication token found");
|
||||
}
|
||||
|
||||
const response = await fetch(endpointPath, {
|
||||
method: method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: ["GET", "DELETE"].includes(method) ? undefined : body,
|
||||
});
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
const data = await response.json();
|
||||
|
||||
responseStatus.textContent = `${response.status} (${response.statusText})`;
|
||||
responseTime.textContent = `${duration}ms`;
|
||||
responseBody.textContent = JSON.stringify(data, null, 2);
|
||||
apiResponse.classList.remove("hidden");
|
||||
} catch (error) {
|
||||
responseStatus.textContent = "Error";
|
||||
responseBody.textContent = (error as Error).message;
|
||||
apiResponse.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function copyDocRequest(): void {
|
||||
const requestBody = document.getElementById("request-body") as HTMLTextAreaElement;
|
||||
if (requestBody) {
|
||||
navigator.clipboard.writeText(requestBody.value);
|
||||
}
|
||||
}
|
||||
|
||||
function copyDocResponse(): void {
|
||||
const responseBody = document.getElementById("response-body");
|
||||
if (responseBody) {
|
||||
navigator.clipboard.writeText(responseBody.textContent || "");
|
||||
}
|
||||
}
|
||||
|
||||
function generateDocCURL(): void {
|
||||
const methodSelect = document.getElementById("http-method") as HTMLSelectElement;
|
||||
const requestBody = document.getElementById("request-body") as HTMLTextAreaElement;
|
||||
|
||||
if (!methodSelect || !requestBody) return;
|
||||
|
||||
const method = methodSelect.value;
|
||||
const body = requestBody.value;
|
||||
const token = getToken();
|
||||
|
||||
let curl = `curl -X ${method} \\n -H "Content-Type: application/json" \\n -H "Authorization: Bearer ${token}"`;
|
||||
|
||||
if (!["GET", "DELETE"].includes(method) && body.trim()) {
|
||||
curl += ` \\n -d '${body}'`;
|
||||
}
|
||||
|
||||
curl += ` \\n ${endpointPath}`;
|
||||
|
||||
navigator.clipboard.writeText(curl);
|
||||
}
|
||||
|
||||
export {
|
||||
copyDocRequest,
|
||||
copyDocResponse,
|
||||
generateDocCURL,
|
||||
initAPIExplorerDoc,
|
||||
showDocMode,
|
||||
tryDocEndpoint,
|
||||
};
|
||||
|
||||
Alpine.data("apiExplorerDoc", () => ({
|
||||
copyDocRequest,
|
||||
copyDocResponse,
|
||||
generateDocCURL,
|
||||
initAPIExplorerDoc,
|
||||
showDocMode,
|
||||
tryDocEndpoint,
|
||||
}));
|
||||
@@ -1,174 +0,0 @@
|
||||
import { showToast } from "./toast";
|
||||
|
||||
interface ApiExplorerRequest {
|
||||
method: string;
|
||||
endpoint: string;
|
||||
headers: Record<string, string>;
|
||||
body?: string;
|
||||
}
|
||||
|
||||
const requestHistory: ApiExplorerRequest[] = [];
|
||||
|
||||
function sendApiRequest(): void {
|
||||
const method = (document.getElementById("api-method") as HTMLSelectElement)?.value || "GET";
|
||||
const endpoint = (document.getElementById("api-endpoint") as HTMLInputElement)?.value || "";
|
||||
const bodyText = (document.getElementById("api-body") as HTMLTextAreaElement)?.value || "";
|
||||
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
if (token) {
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const request: ApiExplorerRequest = {
|
||||
method,
|
||||
endpoint,
|
||||
headers,
|
||||
body: bodyText || undefined,
|
||||
};
|
||||
|
||||
addToHistory(request);
|
||||
|
||||
const startTime = performance.now();
|
||||
|
||||
fetch(endpoint, {
|
||||
method,
|
||||
headers,
|
||||
body: bodyText || undefined,
|
||||
})
|
||||
.then(async (response) => {
|
||||
const endTime = performance.now();
|
||||
const duration = Math.round(endTime - startTime);
|
||||
|
||||
const responseText = await response.text();
|
||||
let responseData: unknown;
|
||||
try {
|
||||
responseData = JSON.parse(responseText);
|
||||
} catch {
|
||||
responseData = responseText;
|
||||
}
|
||||
|
||||
displayResponse(response, responseData, duration);
|
||||
generateCurl(request);
|
||||
})
|
||||
.catch((error) => {
|
||||
displayError(error);
|
||||
});
|
||||
}
|
||||
|
||||
function displayResponse(response: Response, data: unknown, duration: number): void {
|
||||
const container = document.getElementById("api-response");
|
||||
if (!container) return;
|
||||
|
||||
const statusColor = response.ok ? "var(--accent)" : "var(--error)";
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="mb-4">
|
||||
<span class="px-2 py-1 rounded text-sm" style="background-color: ${statusColor}; color: var(--bg-primary)">
|
||||
${response.status} ${response.statusText}
|
||||
</span>
|
||||
<span class="text-sm ml-2" style="color: var(--text-secondary)">${duration}ms</span>
|
||||
</div>
|
||||
<pre class="p-4 rounded overflow-auto max-h-96" style="background-color: var(--bg-primary); color: var(--text-primary)">${JSON.stringify(data, null, 2)}</pre>
|
||||
`;
|
||||
}
|
||||
|
||||
function displayError(error: Error): void {
|
||||
const container = document.getElementById("api-response");
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="p-4 rounded" style="background-color: var(--bg-primary)">
|
||||
<p style="color: var(--error)">Error: ${error.message}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function generateCurl(request: ApiExplorerRequest): void {
|
||||
const container = document.getElementById("curl-command");
|
||||
if (!container) return;
|
||||
|
||||
let curl = `curl -X ${request.method} '${request.endpoint}'`;
|
||||
|
||||
Object.entries(request.headers).forEach(([key, value]) => {
|
||||
curl += ` \\\n -H '${key}: ${value}'`;
|
||||
});
|
||||
|
||||
if (request.body) {
|
||||
curl += ` \\\n -d '${request.body}'`;
|
||||
}
|
||||
|
||||
container.textContent = curl;
|
||||
}
|
||||
|
||||
function addToHistory(request: ApiExplorerRequest): void {
|
||||
requestHistory.unshift(request);
|
||||
if (requestHistory.length > 20) {
|
||||
requestHistory.pop();
|
||||
}
|
||||
renderHistory();
|
||||
}
|
||||
|
||||
function renderHistory(): void {
|
||||
const container = document.getElementById("request-history");
|
||||
if (!container) return;
|
||||
|
||||
if (requestHistory.length === 0) {
|
||||
container.innerHTML =
|
||||
'<p class="text-sm p-2" style="color: var(--text-secondary)">No requests yet</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = requestHistory
|
||||
.slice(0, 10)
|
||||
.map(
|
||||
(req, i) => `
|
||||
<div class="p-2 rounded cursor-pointer hover:bg-opacity-50 transition-colors"
|
||||
style="background-color: var(--bg-secondary)"
|
||||
onclick="window.loadFromHistory(${i})">
|
||||
<span class="text-xs font-mono" style="color: ${req.method === "GET" ? "var(--accent)" : req.method === "POST" ? "var(--success)" : req.method === "DELETE" ? "var(--error)" : "var(--text-primary)"}">${req.method}</span>
|
||||
<span class="text-xs ml-2" style="color: var(--text-secondary)">${req.endpoint}</span>
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
function loadFromHistory(index: number): void {
|
||||
const request = requestHistory[index];
|
||||
if (!request) return;
|
||||
|
||||
const methodSelect = document.getElementById("api-method") as HTMLSelectElement;
|
||||
const endpointInput = document.getElementById("api-endpoint") as HTMLInputElement;
|
||||
const bodyInput = document.getElementById("api-body") as HTMLTextAreaElement;
|
||||
|
||||
if (methodSelect) methodSelect.value = request.method;
|
||||
if (endpointInput) endpointInput.value = request.endpoint;
|
||||
if (bodyInput) bodyInput.value = request.body || "";
|
||||
}
|
||||
|
||||
function copyCurl(): void {
|
||||
const curl = document.getElementById("curl-command")?.textContent;
|
||||
if (curl) {
|
||||
navigator.clipboard.writeText(curl);
|
||||
showToast("cURL copied to clipboard", "success");
|
||||
}
|
||||
}
|
||||
|
||||
function formatJson(): void {
|
||||
const bodyInput = document.getElementById("api-body") as HTMLTextAreaElement;
|
||||
if (!bodyInput) return;
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(bodyInput.value);
|
||||
bodyInput.value = JSON.stringify(parsed, null, 2);
|
||||
} catch {
|
||||
showToast("Invalid JSON", "error");
|
||||
}
|
||||
}
|
||||
|
||||
export { sendApiRequest, loadFromHistory, copyCurl, formatJson };
|
||||
-120
@@ -1,120 +0,0 @@
|
||||
function escapeHtml(text: string): string {
|
||||
const div = document.createElement("div");
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function querySelector<T extends Element>(selector: string): T | null {
|
||||
return document.querySelector<T>(selector);
|
||||
}
|
||||
|
||||
function querySelectorAll<T extends Element>(selector: string): NodeListOf<T> {
|
||||
return document.querySelectorAll<T>(selector);
|
||||
}
|
||||
|
||||
function getElementById<T extends HTMLElement>(id: string): T | null {
|
||||
return document.getElementById(id) as T | null;
|
||||
}
|
||||
|
||||
function createElement<K extends keyof HTMLElementTagNameMap>(
|
||||
tagName: K,
|
||||
attributes?: Record<string, string>,
|
||||
children?: (string | Node)[],
|
||||
): HTMLElementTagNameMap[K] {
|
||||
const element = document.createElement(tagName);
|
||||
|
||||
if (attributes) {
|
||||
Object.entries(attributes).forEach(([key, value]) => {
|
||||
if (key === "className") {
|
||||
element.className = value;
|
||||
} else if (key === "dataset") {
|
||||
Object.entries(JSON.parse(value)).forEach(([dataKey, dataValue]) => {
|
||||
element.dataset[dataKey] = String(dataValue);
|
||||
});
|
||||
} else {
|
||||
element.setAttribute(key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (children) {
|
||||
children.forEach((child) => {
|
||||
if (typeof child === "string") {
|
||||
element.appendChild(document.createTextNode(child));
|
||||
} else {
|
||||
element.appendChild(child);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function showElement(element: HTMLElement | null): void {
|
||||
if (element) {
|
||||
element.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function hideElement(element: HTMLElement | null): void {
|
||||
if (element) {
|
||||
element.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleElement(element: HTMLElement | null): void {
|
||||
if (element) {
|
||||
element.classList.toggle("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function setTextContent(element: HTMLElement | null, text: string): void {
|
||||
if (element) {
|
||||
element.textContent = text;
|
||||
}
|
||||
}
|
||||
|
||||
function setInnerHTML(element: HTMLElement | null, html: string): void {
|
||||
if (element) {
|
||||
element.innerHTML = html;
|
||||
}
|
||||
}
|
||||
|
||||
function addClass(element: HTMLElement | null, className: string): void {
|
||||
if (element) {
|
||||
element.classList.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
function removeClass(element: HTMLElement | null, className: string): void {
|
||||
if (element) {
|
||||
element.classList.remove(className);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleClass(element: HTMLElement | null, className: string): void {
|
||||
if (element) {
|
||||
element.classList.toggle(className);
|
||||
}
|
||||
}
|
||||
|
||||
function hasClass(element: HTMLElement | null, className: string): boolean {
|
||||
return element ? element.classList.contains(className) : false;
|
||||
}
|
||||
|
||||
export {
|
||||
addClass,
|
||||
createElement,
|
||||
escapeHtml,
|
||||
getElementById,
|
||||
hasClass,
|
||||
hideElement,
|
||||
querySelector,
|
||||
querySelectorAll,
|
||||
removeClass,
|
||||
setInnerHTML,
|
||||
setTextContent,
|
||||
showElement,
|
||||
toggleClass,
|
||||
toggleElement,
|
||||
};
|
||||
@@ -1,113 +0,0 @@
|
||||
function onDelegatedClick(
|
||||
selector: string,
|
||||
handler: (element: HTMLElement, event: MouseEvent) => void,
|
||||
): void {
|
||||
document.addEventListener("click", (event: MouseEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const element = target.closest(selector) as HTMLElement | null;
|
||||
if (element) {
|
||||
handler(element, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onDelegatedSubmit(
|
||||
selector: string,
|
||||
handler: (form: HTMLFormElement, event: Event) => void,
|
||||
): void {
|
||||
document.addEventListener("submit", (event: Event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const form = target.closest(selector) as HTMLFormElement | null;
|
||||
if (form) {
|
||||
handler(form, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onDelegatedChange(
|
||||
selector: string,
|
||||
handler: (element: HTMLElement, event: Event) => void,
|
||||
): void {
|
||||
document.addEventListener("change", (event: Event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const element = target.closest(selector) as HTMLElement | null;
|
||||
if (element) {
|
||||
handler(element, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onDelegatedKeydown(
|
||||
selector: string,
|
||||
handler: (element: HTMLElement, event: KeyboardEvent) => void,
|
||||
): void {
|
||||
document.addEventListener("keydown", (event: KeyboardEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const element = target.closest(selector) as HTMLElement | null;
|
||||
if (element) {
|
||||
handler(element, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getDataAttribute(element: HTMLElement, name: string): string | undefined {
|
||||
return element.dataset[name];
|
||||
}
|
||||
|
||||
function setDataAttribute(element: HTMLElement, name: string, value: string): void {
|
||||
element.dataset[name] = value;
|
||||
}
|
||||
|
||||
function onClick(element: HTMLElement | null, handler: (event: MouseEvent) => void): void {
|
||||
if (element) {
|
||||
element.addEventListener("click", handler);
|
||||
}
|
||||
}
|
||||
|
||||
function onSubmit(element: HTMLFormElement | null, handler: (event: Event) => void): void {
|
||||
if (element) {
|
||||
element.addEventListener("submit", handler);
|
||||
}
|
||||
}
|
||||
|
||||
function onChange(element: HTMLElement | null, handler: (event: Event) => void): void {
|
||||
if (element) {
|
||||
element.addEventListener("change", handler);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeydown(element: HTMLElement | null, handler: (event: KeyboardEvent) => void): void {
|
||||
if (element) {
|
||||
element.addEventListener("keydown", handler);
|
||||
}
|
||||
}
|
||||
|
||||
function onInput(element: HTMLElement | null, handler: (event: Event) => void): void {
|
||||
if (element) {
|
||||
element.addEventListener("input", handler);
|
||||
}
|
||||
}
|
||||
|
||||
function preventDefault(event: Event): void {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function stopPropagation(event: Event): void {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
export {
|
||||
getDataAttribute,
|
||||
onChange,
|
||||
onClick,
|
||||
onDelegatedChange,
|
||||
onDelegatedClick,
|
||||
onDelegatedKeydown,
|
||||
onDelegatedSubmit,
|
||||
onInput,
|
||||
onKeydown,
|
||||
onSubmit,
|
||||
preventDefault,
|
||||
setDataAttribute,
|
||||
stopPropagation,
|
||||
};
|
||||
@@ -1,204 +0,0 @@
|
||||
import { Alpine } from "./alpine";
|
||||
import { showToast } from "./toast";
|
||||
|
||||
async function refreshQueue(): Promise<void> {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) return;
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/queue/all", {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
renderQueueItems(data.items || []);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to refresh queue:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function processPendingItems(): Promise<void> {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) return;
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/queue/process", {
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showToast("Processing queue items", "success");
|
||||
refreshQueue();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to process queue:", error);
|
||||
showToast("Failed to process queue", "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function clearFailedItems(): Promise<void> {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) return;
|
||||
|
||||
if (!confirm("Are you sure you want to clear all failed items?")) return;
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/queue/failed", {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showToast("Failed items cleared", "success");
|
||||
refreshQueue();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to clear failed items:", error);
|
||||
showToast("Failed to clear items", "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function clearAllItems(): Promise<void> {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) return;
|
||||
|
||||
if (!confirm("Are you sure you want to clear all queue items?")) return;
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/queue/all", {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showToast("Queue cleared", "success");
|
||||
refreshQueue();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to clear queue:", error);
|
||||
showToast("Failed to clear queue", "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function retryQueueItem(itemId: string): Promise<void> {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/queue/items/${itemId}/retry`, {
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showToast("Item queued for retry", "success");
|
||||
refreshQueue();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to retry item:", error);
|
||||
showToast("Failed to retry item", "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteQueueItem(itemId: string): Promise<void> {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/queue/items/${itemId}`, {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showToast("Item deleted", "success");
|
||||
refreshQueue();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to delete item:", error);
|
||||
showToast("Failed to delete item", "error");
|
||||
}
|
||||
}
|
||||
|
||||
function renderQueueItems(items: QueueItemResponse[]): void {
|
||||
const container = document.getElementById("queue-items");
|
||||
if (!container) return;
|
||||
|
||||
if (items.length === 0) {
|
||||
container.innerHTML =
|
||||
'<p class="text-center p-4" style="color: var(--text-secondary)">Queue is empty</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = items
|
||||
.map(
|
||||
(item) => `
|
||||
<div class="p-3 rounded-lg border mb-2" style="background-color: var(--bg-secondary); border-color: var(--border)">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<p class="font-medium" style="color: var(--text-primary)">${item.media_title || "Unknown"}</p>
|
||||
<p class="text-sm" style="color: var(--text-secondary)">${item.status} - ${item.sync_type}</p>
|
||||
<p class="text-xs" style="color: var(--text-secondary)">Attempts: ${item.attempts}/${item.max_attempts}</p>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
${item.status === "failed" ? `<button onclick="window.retryQueueItem('${item.id}')" class="btn-secondary px-2 py-1 rounded text-sm">Retry</button>` : ""}
|
||||
<button onclick="window.deleteQueueItem('${item.id}')" class="btn-secondary px-2 py-1 rounded text-sm">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
${item.error_message ? `<p class="text-xs mt-2" style="color: var(--accent)">${item.error_message}</p>` : ""}
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
function showQueueItemModal(): void {
|
||||
const modal = document.getElementById("queue-item-modal");
|
||||
const detailsContainer = document.getElementById("queue-item-details");
|
||||
|
||||
if (modal && detailsContainer) {
|
||||
// TODO: Fetch and display item details
|
||||
detailsContainer.innerHTML = "<p>Loading item details...</p>";
|
||||
modal.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function hideQueueItemModal(): void {
|
||||
const modal = document.getElementById("queue-item-modal");
|
||||
if (modal) {
|
||||
modal.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function filterQueue(status: string): void {
|
||||
const filterValue = status || "all";
|
||||
// TODO: Implement filtering logic
|
||||
console.log("Filter queue by:", filterValue);
|
||||
}
|
||||
|
||||
export {
|
||||
clearAllItems,
|
||||
clearFailedItems,
|
||||
deleteQueueItem,
|
||||
processPendingItems,
|
||||
refreshQueue,
|
||||
retryQueueItem,
|
||||
showQueueItemModal,
|
||||
hideQueueItemModal,
|
||||
filterQueue,
|
||||
};
|
||||
|
||||
Alpine.data("queue", () => ({
|
||||
clearAllItems,
|
||||
clearFailedItems,
|
||||
deleteQueueItem,
|
||||
processPendingItems,
|
||||
refreshQueue,
|
||||
retryQueueItem,
|
||||
showQueueItemModal,
|
||||
hideQueueItemModal,
|
||||
filterQueue,
|
||||
}));
|
||||
Reference in new issue
Block a user