Files
Gitpub-Desktop/frontend/js/gitea-api.js
T
andrew f0358dbdfe Add read-only repository viewer (UI + backend)
Implements a read-only repository viewer for remote Gitea repos and local clones. Adds UI/CSS for viewer panels, breadcrumb/branch controls, file table, code/Markdown preview, and readme rendering (frontend/css/components.css, frontend/js/app.js). Extends app state and wiring (state.js, app.js) with viewer actions, branch/content loading, local/remote navigation, and preview helpers (base64 decoding, markdown rendering, syntax highlighting, 256 KB preview limit). Adds Gitea API helpers to fetch repo branches and contents (frontend/js/gitea-api.js) and Tauri JS bindings for local repo operations (tauri-api.js). Implements Rust backend commands to list branches, tree entries, and file contents (with size/binary checks and helper utilities) and wires them into the Tauri command registry (src-tauri/src/lib.rs). Also updates README to mention the new read-only viewer.
2026-05-09 18:45:51 +12:00

104 lines
3.0 KiB
JavaScript

function normalizeServerUrl(serverUrl) {
return serverUrl.trim().replace(/\/+$/, "");
}
export function buildApiBaseUrl(serverUrl) {
const normalized = normalizeServerUrl(serverUrl);
return normalized.endsWith("/api/v1") ? normalized : `${normalized}/api/v1`;
}
export function buildHeaders(serverConfig) {
const headers = {
Accept: "application/json",
};
if (serverConfig.authMethod === "token" && serverConfig.token) {
headers.Authorization = `token ${serverConfig.token}`;
} else if (
serverConfig.authMethod === "password" &&
serverConfig.username &&
serverConfig.password
) {
headers.Authorization = `Basic ${btoa(
`${serverConfig.username}:${serverConfig.password}`
)}`;
}
return headers;
}
export async function fetchCurrentUser(serverConfig) {
const apiBase = buildApiBaseUrl(serverConfig.serverUrl);
const response = await fetch(`${apiBase}/user`, {
headers: buildHeaders(serverConfig),
});
if (!response.ok) {
throw new Error(`Gitea API error: ${response.status}`);
}
return response.json();
}
export async function fetchRepositories(serverConfig, page = 1, limit = 50) {
const apiBase = buildApiBaseUrl(serverConfig.serverUrl);
const url = `${apiBase}/user/repos?page=${page}&limit=${limit}&sort=updated`;
const response = await fetch(url, {
headers: buildHeaders(serverConfig),
});
if (!response.ok) {
throw new Error(`Gitea API error: ${response.status}`);
}
return response.json();
}
function encodePathSegment(value = "") {
return encodeURIComponent(value);
}
function encodeRepoPath(path = "") {
return path
.split("/")
.filter(Boolean)
.map(encodePathSegment)
.join("/");
}
function splitRepoFullName(fullName = "") {
const [owner, repo] = fullName.split("/");
if (!owner || !repo) {
throw new Error("Repository full name must be in owner/repo format.");
}
return { owner, repo };
}
export async function fetchRepoBranches(serverConfig, fullName) {
const apiBase = buildApiBaseUrl(serverConfig.serverUrl);
const { owner, repo } = splitRepoFullName(fullName);
const url = `${apiBase}/repos/${encodePathSegment(owner)}/${encodePathSegment(repo)}/branches`;
const response = await fetch(url, {
headers: buildHeaders(serverConfig),
});
if (!response.ok) {
throw new Error(`Gitea API error: ${response.status}`);
}
return response.json();
}
export async function fetchRepoContents(serverConfig, fullName, path = "", ref = "") {
const apiBase = buildApiBaseUrl(serverConfig.serverUrl);
const { owner, repo } = splitRepoFullName(fullName);
const encodedPath = encodeRepoPath(path);
const pathSuffix = encodedPath ? `/${encodedPath}` : "";
const query = ref ? `?ref=${encodeURIComponent(ref)}` : "";
const url = `${apiBase}/repos/${encodePathSegment(owner)}/${encodePathSegment(repo)}/contents${pathSuffix}${query}`;
const response = await fetch(url, {
headers: buildHeaders(serverConfig),
});
if (!response.ok) {
throw new Error(`Gitea API error: ${response.status}`);
}
return response.json();
}