CODEX - Added Warning sign if Archetype is missing
This commit is contained in:
@@ -249,6 +249,7 @@ export default function MelodyDetail() {
|
||||
const speedBpm = formatBpm(speedMs);
|
||||
const minBpm = formatBpm(info.minSpeed);
|
||||
const maxBpm = formatBpm(info.maxSpeed);
|
||||
const missingArchetype = Boolean(melody.pid) && !builtMelody?.id;
|
||||
const languages = melodySettings?.available_languages || ["en"];
|
||||
const displayName = getLocalizedValue(info.name, displayLang, "Untitled Melody");
|
||||
|
||||
@@ -556,10 +557,6 @@ export default function MelodyDetail() {
|
||||
|
||||
const handleDownload = async (e) => {
|
||||
e.preventDefault();
|
||||
if (binaryUrl.startsWith("http")) {
|
||||
window.open(binaryUrl, "_blank", "noopener,noreferrer");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const token = localStorage.getItem("access_token");
|
||||
let res = null;
|
||||
@@ -586,7 +583,13 @@ export default function MelodyDetail() {
|
||||
a.click();
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
} catch (err) {
|
||||
window.open(binaryUrl, "_blank", "noopener,noreferrer");
|
||||
const a = document.createElement("a");
|
||||
a.href = binaryUrl;
|
||||
a.download = downloadName;
|
||||
a.rel = "noopener noreferrer";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -600,6 +603,15 @@ export default function MelodyDetail() {
|
||||
{downloadName}
|
||||
</span>
|
||||
)}
|
||||
{missingArchetype && (
|
||||
<span
|
||||
className="text-xs cursor-help"
|
||||
style={{ color: "#f59e0b" }}
|
||||
title="This binary does not exist in the Archetypes"
|
||||
>
|
||||
⚠
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDownload}
|
||||
|
||||
@@ -257,7 +257,13 @@ export default function MelodyForm() {
|
||||
a.click();
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
} catch (err) {
|
||||
window.open(fileUrl, "_blank", "noopener,noreferrer");
|
||||
const a = document.createElement("a");
|
||||
a.href = fileUrl;
|
||||
a.download = fallbackName || "download.file";
|
||||
a.rel = "noopener noreferrer";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -764,11 +770,21 @@ export default function MelodyForm() {
|
||||
<label className="block text-sm font-medium mb-1" style={labelStyle}>Binary File (.bsm)</label>
|
||||
{(() => {
|
||||
const { effectiveUrl: binaryUrl, effectiveName: binaryName } = getEffectiveBinary();
|
||||
const missingArchetype = Boolean(pid) && !builtMelody?.id;
|
||||
return (
|
||||
<div className="text-xs mb-2" style={{ color: "var(--text-muted)" }}>
|
||||
{binaryUrl ? (
|
||||
<span className="text-sm mr-4" style={{ color: "var(--text-secondary)" }}>
|
||||
{binaryName}
|
||||
<span className="inline-flex items-center gap-2 text-sm mr-4" style={{ color: "var(--text-secondary)" }}>
|
||||
<span>{binaryName}</span>
|
||||
{missingArchetype && (
|
||||
<span
|
||||
className="text-xs cursor-help"
|
||||
style={{ color: "#f59e0b" }}
|
||||
title="This binary does not exist in the Archetypes"
|
||||
>
|
||||
⚠
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
<span>No binary uploaded</span>
|
||||
|
||||
@@ -375,6 +375,7 @@ export default function MelodyList() {
|
||||
: `/api/${candidate}`)
|
||||
: null;
|
||||
const source = built?.binary_url ? "Archetype" : (url ? "Melody URL" : null);
|
||||
const missingArchetype = Boolean(row?.pid) && !built?.id;
|
||||
const filename = (() => {
|
||||
if (built?.pid) return `${built.pid}.bsm`;
|
||||
if (row?.pid) return `${row.pid}.bsm`;
|
||||
@@ -391,7 +392,7 @@ export default function MelodyList() {
|
||||
}
|
||||
return "melody.bsm";
|
||||
})();
|
||||
return { url, filename, source, built };
|
||||
return { url, filename, source, built, missingArchetype };
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
@@ -466,9 +467,16 @@ export default function MelodyList() {
|
||||
a.click();
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
} catch (err) {
|
||||
const fallbackUrl = resolveEffectiveBinary(row).url;
|
||||
const fallback = resolveEffectiveBinary(row);
|
||||
const fallbackUrl = fallback.url;
|
||||
if (fallbackUrl) {
|
||||
window.open(fallbackUrl, "_blank", "noopener,noreferrer");
|
||||
const a = document.createElement("a");
|
||||
a.href = fallbackUrl;
|
||||
a.download = fallback.filename || "melody.bsm";
|
||||
a.rel = "noopener noreferrer";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
} else {
|
||||
setError(err.message);
|
||||
}
|
||||
@@ -876,9 +884,13 @@ export default function MelodyList() {
|
||||
<span className="inline-flex flex-col">
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<span className="text-xs" style={{ color: "var(--text-secondary)" }}>{filename || "binary.bsm"}</span>
|
||||
{resolved.source && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded" style={{ color: "var(--text-muted)", backgroundColor: "var(--bg-card-hover)" }}>
|
||||
{resolved.source}
|
||||
{resolved.missingArchetype && (
|
||||
<span
|
||||
className="text-xs cursor-help"
|
||||
style={{ color: "#f59e0b" }}
|
||||
title="This binary does not exist in the Archetypes"
|
||||
>
|
||||
⚠
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
|
||||
@@ -110,6 +110,14 @@ function applyNoteAssignments(rawStepValue, noteAssignments) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function bellDotColor(assignedBell) {
|
||||
const bell = Number(assignedBell || 0);
|
||||
if (bell <= 0) return "rgba(148,163,184,0.7)";
|
||||
const t = Math.min(1, Math.max(0, (bell - 1) / 15));
|
||||
const light = 62 - t * 40; // bright green -> very dark green
|
||||
return `hsl(132, 74%, ${light}%)`;
|
||||
}
|
||||
|
||||
const mutedStyle = { color: "var(--text-muted)" };
|
||||
const labelStyle = { color: "var(--text-secondary)" };
|
||||
const NOTE_LABELS = "ABCDEFGHIJKLMNOP";
|
||||
@@ -460,7 +468,9 @@ export default function PlaybackModal({ open, melody, builtMelody, files, archet
|
||||
const enabled = Boolean(stepValue & (1 << noteIdx));
|
||||
const isCurrent = currentStep === stepIdx;
|
||||
const assignedBell = Number(noteAssignments[noteIdx] || 0);
|
||||
const dotLabel = assignedBell > 0 ? assignedBell : noteIdx + 1;
|
||||
const dotLabel = assignedBell > 0 ? assignedBell : "";
|
||||
const isUnassigned = assignedBell <= 0;
|
||||
const dotVisible = enabled || (isUnassigned && Boolean(stepValue & (1 << noteIdx)));
|
||||
return (
|
||||
<td
|
||||
key={`${noteIdx}-${stepIdx}`}
|
||||
@@ -479,15 +489,17 @@ export default function PlaybackModal({ open, melody, builtMelody, files, archet
|
||||
width: "68%",
|
||||
height: "68%",
|
||||
borderRadius: "9999px",
|
||||
backgroundColor: "var(--btn-primary)",
|
||||
backgroundColor: isUnassigned ? "rgba(100,116,139,0.7)" : bellDotColor(assignedBell),
|
||||
color: "var(--text-white)",
|
||||
opacity: enabled ? 1 : 0,
|
||||
transform: enabled ? "scale(1)" : "scale(0.4)",
|
||||
boxShadow: enabled ? "0 0 10px 3px rgba(116, 184, 22, 0.5)" : "none",
|
||||
opacity: dotVisible ? 1 : 0,
|
||||
transform: dotVisible ? "scale(1)" : "scale(0.4)",
|
||||
boxShadow: dotVisible
|
||||
? (isUnassigned ? "0 0 8px 2px rgba(100,116,139,0.35)" : `0 0 10px 3px ${bellDotColor(assignedBell)}66`)
|
||||
: "none",
|
||||
transition: "opacity 140ms ease, transform 140ms ease, box-shadow 180ms ease",
|
||||
}}
|
||||
>
|
||||
{enabled ? dotLabel : ""}
|
||||
{dotVisible ? dotLabel : ""}
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user