Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 15:49:16 -05:00
pkg-proxy/internal/server/static/project-delete.js
Simon Chrzanowski 1c706fffd0 Review fixes for the project inventory
- GetProjectsUsingPackage no longer counts each project's components
  per row; the package page only needs names and versions. The ?purl=
  listing leaves component_count out accordingly.
- The delete button sends to DELETE /ui/api/projects/{project}, the same
  handler as the API and still behind the token, so it sits under /ui
  like the cache deletes.
- The project page answers 500 when its components can't be read,
  instead of showing an empty project.
- DELETE of a path ending in /sbom that names no project answers 400
  with a hint, since it's most likely the upload path.
- The upload endpoint lists JSON, XML and plain text (SPDX tag-value)
  as accepted.
- The docs say that versions are compared as the SBOM spells them.
2026-10-27 20:23:14 +01:00

64 lines
2.4 KiB
JavaScript

// Deleting a project needs the upload token: /ui has no authentication of its
// own, so the page sends the token the user enters with the request, the same
// as an upload. The token is kept for the browser session only.
(() => {
const root = document.getElementById('project-delete');
if (!root) {
return;
}
const start = document.getElementById('project-delete-start');
const form = document.getElementById('project-delete-form');
const input = document.getElementById('project-delete-token');
const cancel = document.getElementById('project-delete-cancel');
const errorBox = document.getElementById('project-delete-error');
const submit = form.querySelector('button[type="submit"]');
const storageKey = 'projects-token';
const show = (open) => {
start.classList.toggle('hidden', open);
form.classList.toggle('hidden', !open);
form.classList.toggle('flex', open);
errorBox.classList.add('hidden');
};
start.addEventListener('click', () => {
try {
input.value = sessionStorage.getItem(storageKey) || '';
} catch (e) {
input.value = '';
}
show(true);
input.focus();
});
cancel.addEventListener('click', () => show(false));
form.addEventListener('submit', async (event) => {
event.preventDefault();
const url = '/ui/api/projects/' + encodeURIComponent(root.dataset.project);
submit.disabled = true;
errorBox.classList.add('hidden');
try {
const resp = await fetch(url, {
method: 'DELETE',
headers: { Authorization: 'Bearer ' + input.value },
});
if (resp.status === 401) {
throw new Error('the token was rejected');
}
if (!resp.ok) {
const body = await resp.json().catch(() => ({}));
throw new Error(body.message || body.error || `HTTP ${resp.status}`);
}
try {
sessionStorage.setItem(storageKey, input.value);
} catch (e) {
// Without storage the token is just asked for again.
}
window.location.href = '/ui/projects';
} catch (err) {
errorBox.textContent = 'Delete failed: ' + err.message;
errorBox.classList.remove('hidden');
submit.disabled = false;
}
});
})();