Sanjana Vekhande commited on
Commit
7c2f04d
Β·
1 Parent(s): 932f7e0

add species prefix mismatch validation

Browse files
Files changed (1) hide show
  1. frontend/index.html +43 -0
frontend/index.html CHANGED
@@ -339,6 +339,20 @@ input[type="range"]::-webkit-slider-thumb:hover {
339
  font-weight: 500;
340
  }
341
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  /* ── Run section ─────────────────────── */
343
  .run-section {
344
  margin-top: 2.5rem;
@@ -598,6 +612,9 @@ footer a:hover { color: var(--ink); }
598
  </div>
599
  </div>
600
 
 
 
 
601
  <!-- Run -->
602
  <div class="run-section">
603
  <button class="btn-run" id="runBtn" onclick="startJob()">
@@ -660,6 +677,30 @@ function updateSlider(val) {
660
 
661
  window.addEventListener('DOMContentLoaded', () => updateSlider(1000));
662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
  function handleFiles(type, files) {
664
  state[type] = Array.from(files);
665
  const key = { model: 'chipsModel', mapping: 'chipsMapping', expr: 'chipsExpr' }[type];
@@ -667,6 +708,7 @@ function handleFiles(type, files) {
667
  document.getElementById(key).innerHTML =
668
  state[type].map(f => `<div class="chip">βœ“ ${f.name}</div>`).join('');
669
  document.getElementById(num).classList.add('done');
 
670
  }
671
 
672
  ['dropModel','dropMapping','dropExpr'].forEach(id => {
@@ -680,6 +722,7 @@ async function startJob() {
680
  if (!state.model.length) { alert('Please upload at least one model file.'); return; }
681
  if (!state.mapping.length) { alert('Please upload at least one mapping file.'); return; }
682
  if (!state.expr.length) { alert('Please upload a gene expression CSV.'); return; }
 
683
 
684
  document.getElementById('runBtn').disabled = true;
685
  document.getElementById('progressSection').classList.remove('hidden');
 
339
  font-weight: 500;
340
  }
341
 
342
+ .mismatch-warning {
343
+ display: flex;
344
+ align-items: flex-start;
345
+ gap: 8px;
346
+ background: #FFF7ED;
347
+ border: 1.5px solid #FED7AA;
348
+ border-radius: 8px;
349
+ padding: 0.75rem 1rem;
350
+ margin-top: 0.75rem;
351
+ font-size: 13px;
352
+ color: #9A3412;
353
+ line-height: 1.5;
354
+ }
355
+
356
  /* ── Run section ─────────────────────── */
357
  .run-section {
358
  margin-top: 2.5rem;
 
612
  </div>
613
  </div>
614
 
615
+ <!-- Prefix mismatch warning -->
616
+ <div class="mismatch-warning hidden" id="prefixWarning"></div>
617
+
618
  <!-- Run -->
619
  <div class="run-section">
620
  <button class="btn-run" id="runBtn" onclick="startJob()">
 
677
 
678
  window.addEventListener('DOMContentLoaded', () => updateSlider(1000));
679
 
680
+ function getPrefix(filename) {
681
+ return filename.split('_')[0].toLowerCase();
682
+ }
683
+
684
+ function checkPrefixMatch() {
685
+ const warn = document.getElementById('prefixWarning');
686
+ if (!state.model.length || !state.mapping.length) {
687
+ warn.classList.add('hidden');
688
+ return true;
689
+ }
690
+ const modelPrefixes = state.model.map(f => getPrefix(f.name)).sort();
691
+ const mappingPrefixes = state.mapping.map(f => getPrefix(f.name)).sort();
692
+ const mismatch =
693
+ modelPrefixes.length !== mappingPrefixes.length ||
694
+ modelPrefixes.some((p, i) => p !== mappingPrefixes[i]);
695
+ if (mismatch) {
696
+ warn.innerHTML = `⚠️ <span>Species prefix mismatch β€” model files (${modelPrefixes.join(', ')}) don't match mapping files (${mappingPrefixes.join(', ')}). Make sure files are uploaded in the same order and belong to the same species.</span>`;
697
+ warn.classList.remove('hidden');
698
+ return false;
699
+ }
700
+ warn.classList.add('hidden');
701
+ return true;
702
+ }
703
+
704
  function handleFiles(type, files) {
705
  state[type] = Array.from(files);
706
  const key = { model: 'chipsModel', mapping: 'chipsMapping', expr: 'chipsExpr' }[type];
 
708
  document.getElementById(key).innerHTML =
709
  state[type].map(f => `<div class="chip">βœ“ ${f.name}</div>`).join('');
710
  document.getElementById(num).classList.add('done');
711
+ checkPrefixMatch();
712
  }
713
 
714
  ['dropModel','dropMapping','dropExpr'].forEach(id => {
 
722
  if (!state.model.length) { alert('Please upload at least one model file.'); return; }
723
  if (!state.mapping.length) { alert('Please upload at least one mapping file.'); return; }
724
  if (!state.expr.length) { alert('Please upload a gene expression CSV.'); return; }
725
+ if (!checkPrefixMatch()) { alert('Fix the species prefix mismatch before running.'); return; }
726
 
727
  document.getElementById('runBtn').disabled = true;
728
  document.getElementById('progressSection').classList.remove('hidden');