Add term column

This commit is contained in:
Ian Keane 2026-06-11 17:28:14 -04:00
parent 52eb0f6189
commit dba48e90b7
2 changed files with 31 additions and 1 deletions

23
app.js
View file

@ -10,6 +10,7 @@ let allMusicians = [];
let allInstruments = [];
let allTunings = [];
let allReferenceSites = [];
let allTerms = [];
let sortCol = 'name';
let sortDir = 'asc';
@ -43,6 +44,7 @@ const sourceDatalist = $('source-list');
const musicianDatalist = $('musician-list');
const instrumentSelect = $('instrument-select');
const tuningDatalist = $('tuning-list');
const termDatalist = $('term-list');
const btnDeleteTune = $('btn-delete-tune');
const btnEditNotes = $('btn-edit-notes');
const btnBulkEdit = $('btn-bulk-edit');
@ -116,18 +118,20 @@ function setStatus(msg, isError = false) {
async function loadAll() {
setStatus('Loading…');
try {
[allTunes, allSources, allMusicians, allInstruments, allTunings, allReferenceSites] = await Promise.all([
[allTunes, allSources, allMusicians, allInstruments, allTunings, allReferenceSites, allTerms] = await Promise.all([
apiFetch('/tunes/'),
apiFetch('/sources/'),
apiFetch('/musicians/'),
apiFetch('/instruments'),
apiFetch('/tunings/'),
apiFetch('/reference_sites/'),
apiFetch('/terms/'),
]);
populateFilterOptions();
populateDatalist(sourceDatalist, allSources);
populateDatalist(musicianDatalist, allMusicians);
populateDatalist(tuningDatalist, allTunings);
populateDatalist(termDatalist, allTerms);
populateDatalist(refSiteDatalist, allReferenceSites);
populateInstrumentSelect();
renderTable();
@ -204,6 +208,12 @@ $('btn-quick-add-tuning').addEventListener('click', async () => {
});
});
$('btn-quick-add-term').addEventListener('click', async () => {
await quickAdd('/terms/', 'New term name:', allTerms, termDatalist, item => {
tuneForm.elements.inst_term.value = item.name;
});
});
$('btn-quick-add-instrument').addEventListener('click', async () => {
const item = await quickAdd('/instruments', 'New instrument name:', allInstruments, null);
if (item) {
@ -231,6 +241,11 @@ function resolveTuningId(name) {
return allTunings.find(x => x.name.toLowerCase() === name.toLowerCase())?.id ?? null;
}
function resolveTermId(name) {
if (!name) return null;
return allTerms.find(x => x.name.toLowerCase() === name.toLowerCase())?.id ?? null;
}
// ── Rows: one per instrument entry ────────────────────────────
// For tunes with no instrument entries, emit one row with empty instrument cols
function buildRows(tunes) {
@ -550,6 +565,7 @@ async function openEdit(tuneId, entryId) {
populateInstrumentSelect(entry?.instrument_id ?? null);
if (entry) {
tuneForm.elements.inst_tuning.value = entry.tuning ?? '';
tuneForm.elements.inst_term.value = entry.term ?? '';
tuneForm.elements.inst_learned_from.value = entry.learned_from ?? '';
tuneForm.elements.inst_date_learned.value = entry.date_learned ?? '';
tuneForm.elements.inst_status.value = entry.status ?? '';
@ -708,6 +724,7 @@ async function saveTune() {
const instBody = instId ? {
instrument_id: instId,
tuning_id: resolveTuningId(f.inst_tuning.value),
term_id: resolveTermId(f.inst_term.value),
learned_from_id: resolveMusicianId(f.inst_learned_from.value),
date_learned: f.inst_date_learned.value || null,
status: f.inst_status.value || null,
@ -1432,6 +1449,7 @@ async function importCSVRows(rows) {
const tunCache = new Map(); // name.lower → id (tunings)
const musCache = new Map(); // name.lower → id (musicians)
const instCache = new Map(); // name.lower → id (instruments)
const termCache = new Map(); // name.lower → id (terms)
const tuneCache = new Map(); // name.lower → id (tunes created this run)
const results = { created: 0, skipped: 0, errors: [] };
@ -1455,6 +1473,7 @@ async function importCSVRows(rows) {
const tuningId = await resolveOrCreate('/tunings/', allTunings, tunCache, row.tuning?.trim() || null);
const learnedFromId = await resolveOrCreate('/musicians/', allMusicians, musCache, row.learned_from?.trim() || null);
const instId = await resolveOrCreate('/instruments', allInstruments, instCache, row.instrument?.trim() || null);
const termId = await resolveOrCreate('/terms/', allTerms, termCache, row.term?.trim() || null);
// Find existing tune or create new
const lower = tuneName.toLowerCase();
@ -1481,6 +1500,7 @@ async function importCSVRows(rows) {
body: JSON.stringify({
instrument_id: instId,
tuning_id: tuningId,
term_id: termId,
learned_from_id: learnedFromId,
date_learned: row.date_learned?.trim() || null,
status,
@ -1537,6 +1557,7 @@ function attachTabAutocomplete(input, datalist) {
attachTabAutocomplete(sourceInput, sourceDatalist);
attachTabAutocomplete(tuneForm.elements.inst_tuning, tuningDatalist);
attachTabAutocomplete(tuneForm.elements.inst_term, termDatalist);
attachTabAutocomplete(tuneForm.elements.inst_learned_from, musicianDatalist);
// ── Boot ─────────────────────────────────────────────────────