400 lines
15 KiB
HTML
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()">
|
|
×
|
|
</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()">
|
|
×
|
|
</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()">
|
|
×
|
|
</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}}
|