Files
silo/internal/api/templates/schemas.html
2026-01-24 15:03:17 -06:00

400 lines
15 KiB
HTML

{{define "schemas_content"}}
<div class="card">
<div class="card-header">
<h2 class="card-title">Part Numbering Schemas</h2>
</div>
<div id="schemas-list">
<div class="loading">
<div class="spinner"></div>
</div>
</div>
</div>
<!-- Add Value Modal -->
<div class="modal-overlay" id="add-value-modal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Add New Value</h3>
<button class="modal-close" onclick="closeAddValueModal()">
&times;
</button>
</div>
<form id="add-value-form" onsubmit="addValue(event)">
<input type="hidden" id="add-schema-name" />
<input type="hidden" id="add-segment-name" />
<div class="form-group">
<label class="form-label">Code</label>
<input
type="text"
class="form-input"
id="add-code"
required
placeholder="e.g., F19"
/>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<input
type="text"
class="form-input"
id="add-description"
required
placeholder="e.g., Clamps"
/>
</div>
<div class="form-actions">
<button
type="button"
class="btn btn-secondary"
onclick="closeAddValueModal()"
>
Cancel
</button>
<button type="submit" class="btn btn-primary">Add Value</button>
</div>
</form>
</div>
</div>
<!-- Edit Value Modal -->
<div class="modal-overlay" id="edit-value-modal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Edit Value</h3>
<button class="modal-close" onclick="closeEditValueModal()">
&times;
</button>
</div>
<form id="edit-value-form" onsubmit="updateValue(event)">
<input type="hidden" id="edit-schema-name" />
<input type="hidden" id="edit-segment-name" />
<input type="hidden" id="edit-code" />
<div class="form-group">
<label class="form-label">Code</label>
<input
type="text"
class="form-input"
id="edit-code-display"
disabled
/>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<input
type="text"
class="form-input"
id="edit-description"
required
/>
</div>
<div class="form-actions">
<button
type="button"
class="btn btn-secondary"
onclick="closeEditValueModal()"
>
Cancel
</button>
<button type="submit" class="btn btn-primary">
Save Changes
</button>
</div>
</form>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div class="modal-overlay" id="delete-value-modal">
<div class="modal" style="max-width: 400px">
<div class="modal-header">
<h3 class="modal-title">Delete Value</h3>
<button class="modal-close" onclick="closeDeleteValueModal()">
&times;
</button>
</div>
<div style="margin-bottom: 1.5rem">
<p>
Are you sure you want to delete
<strong id="delete-value-code"></strong>?
</p>
<p style="color: var(--ctp-red); margin-top: 0.5rem">
This action cannot be undone.
</p>
</div>
<div class="form-actions">
<button
type="button"
class="btn btn-secondary"
onclick="closeDeleteValueModal()"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
style="background-color: var(--ctp-red)"
onclick="confirmDeleteValue()"
>
Delete
</button>
</div>
</div>
</div>
{{end}} {{define "schemas_scripts"}}
<style>
.value-actions {
display: flex;
gap: 0.25rem;
}
.value-actions button {
padding: 0.2rem 0.5rem;
font-size: 0.75rem;
}
.add-value-btn {
margin-top: 0.5rem;
}
</style>
<script>
let deleteValueInfo = null;
async function loadSchemas() {
const container = document.getElementById("schemas-list");
try {
const response = await fetch("/api/schemas");
const schemas = await response.json();
// Filter out empty schemas
const validSchemas = schemas.filter((s) => s.name);
if (validSchemas.length === 0) {
container.innerHTML =
'<div class="empty-state"><h3>No schemas found</h3></div>';
return;
}
container.innerHTML = validSchemas
.map(
(schema) => `
<div class="card" style="margin-bottom: 1rem;">
<h3 style="color: var(--ctp-mauve); margin-bottom: 0.5rem;">${schema.name}</h3>
<p style="color: var(--ctp-subtext0); margin-bottom: 1rem;">${schema.description || ""}</p>
<p style="margin-bottom: 0.5rem;"><strong>Format:</strong> <code style="background: var(--ctp-surface1); padding: 0.25rem 0.5rem; border-radius: 0.25rem;">${schema.format}</code></p>
<p style="margin-bottom: 1rem;"><strong>Version:</strong> ${schema.version}</p>
${
schema.examples && schema.examples.length > 0
? `
<p style="margin-bottom: 0.5rem;"><strong>Examples:</strong></p>
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1rem;">
${schema.examples.map((ex) => `<span class="part-number" style="background: var(--ctp-surface1); padding: 0.25rem 0.75rem; border-radius: 0.25rem;">${ex}</span>`).join("")}
</div>
`
: ""
}
<details style="margin-top: 1rem;">
<summary style="cursor: pointer; color: var(--ctp-sapphire);">View Segments (${schema.segments.length})</summary>
${schema.segments
.map(
(seg) => `
<div style="margin-top: 1rem; padding: 1rem; background: var(--ctp-surface0); border-radius: 0.5rem;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
<h4 style="margin: 0; color: var(--ctp-blue);">${seg.name}</h4>
<span class="item-type item-type-part">${seg.type}</span>
</div>
<p style="color: var(--ctp-subtext0); margin-bottom: 0.5rem;">${seg.description || ""}</p>
${seg.type === "enum" && seg.values ? renderEnumValues(schema.name, seg.name, seg.values) : ""}
</div>
`,
)
.join("")}
</details>
</div>
`,
)
.join("");
} catch (error) {
container.innerHTML = `<div class="empty-state"><h3>Error loading schemas</h3><p>${error.message}</p></div>`;
}
}
function renderEnumValues(schemaName, segmentName, values) {
const sorted = Object.entries(values).sort((a, b) =>
a[0].localeCompare(b[0]),
);
return `
<div class="table-container" style="margin-top: 0.5rem;">
<table>
<thead>
<tr>
<th>Code</th>
<th>Description</th>
<th style="width: 100px;">Actions</th>
</tr>
</thead>
<tbody>
${sorted
.map(
([code, desc]) => `
<tr>
<td><code>${code}</code></td>
<td>${desc}</td>
<td>
<div class="value-actions">
<button class="btn btn-secondary" onclick="openEditValueModal('${schemaName}', '${segmentName}', '${code}', '${desc.replace(/'/g, "\\'")}')">Edit</button>
<button class="btn btn-secondary" style="background-color: var(--ctp-surface2);" onclick="openDeleteValueModal('${schemaName}', '${segmentName}', '${code}')">Delete</button>
</div>
</td>
</tr>
`,
)
.join("")}
</tbody>
</table>
</div>
<button class="btn btn-primary add-value-btn" onclick="openAddValueModal('${schemaName}', '${segmentName}')">+ Add Value</button>
`;
}
// Add Value Modal
function openAddValueModal(schemaName, segmentName) {
document.getElementById("add-schema-name").value = schemaName;
document.getElementById("add-segment-name").value = segmentName;
document.getElementById("add-value-modal").classList.add("active");
}
function closeAddValueModal() {
document.getElementById("add-value-modal").classList.remove("active");
document.getElementById("add-value-form").reset();
}
async function addValue(event) {
event.preventDefault();
const schemaName = document.getElementById("add-schema-name").value;
const segmentName = document.getElementById("add-segment-name").value;
const code = document.getElementById("add-code").value;
const description = document.getElementById("add-description").value;
try {
const response = await fetch(
`/api/schemas/${schemaName}/segments/${segmentName}/values`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ code, description }),
},
);
if (!response.ok) {
const error = await response.json();
alert(`Error: ${error.message || error.error}`);
return;
}
closeAddValueModal();
loadSchemas();
} catch (error) {
alert(`Error: ${error.message}`);
}
}
// Edit Value Modal
function openEditValueModal(schemaName, segmentName, code, description) {
document.getElementById("edit-schema-name").value = schemaName;
document.getElementById("edit-segment-name").value = segmentName;
document.getElementById("edit-code").value = code;
document.getElementById("edit-code-display").value = code;
document.getElementById("edit-description").value = description;
document.getElementById("edit-value-modal").classList.add("active");
}
function closeEditValueModal() {
document.getElementById("edit-value-modal").classList.remove("active");
document.getElementById("edit-value-form").reset();
}
async function updateValue(event) {
event.preventDefault();
const schemaName = document.getElementById("edit-schema-name").value;
const segmentName = document.getElementById("edit-segment-name").value;
const code = document.getElementById("edit-code").value;
const description = document.getElementById("edit-description").value;
try {
const response = await fetch(
`/api/schemas/${schemaName}/segments/${segmentName}/values/${code}`,
{
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ description }),
},
);
if (!response.ok) {
const error = await response.json();
alert(`Error: ${error.message || error.error}`);
return;
}
closeEditValueModal();
loadSchemas();
} catch (error) {
alert(`Error: ${error.message}`);
}
}
// Delete Value Modal
function openDeleteValueModal(schemaName, segmentName, code) {
deleteValueInfo = { schemaName, segmentName, code };
document.getElementById("delete-value-code").textContent = code;
document.getElementById("delete-value-modal").classList.add("active");
}
function closeDeleteValueModal() {
document
.getElementById("delete-value-modal")
.classList.remove("active");
deleteValueInfo = null;
}
async function confirmDeleteValue() {
if (!deleteValueInfo) return;
const { schemaName, segmentName, code } = deleteValueInfo;
try {
const response = await fetch(
`/api/schemas/${schemaName}/segments/${segmentName}/values/${code}`,
{
method: "DELETE",
},
);
if (!response.ok && response.status !== 204) {
const error = await response.json();
alert(`Error: ${error.message || error.error}`);
return;
}
closeDeleteValueModal();
loadSchemas();
} catch (error) {
alert(`Error: ${error.message}`);
}
}
// Close modals on overlay click
document.querySelectorAll(".modal-overlay").forEach((overlay) => {
overlay.addEventListener("click", (e) => {
if (e.target === overlay) {
overlay.classList.remove("active");
}
});
});
loadSchemas();
</script>
{{end}}