Spaces:
Paused
Paused
Download src/dashboard/static/experiment-workflow.js from ThomasHeisig/Brain-5D-Space: direct link, hf CLI and curl.
- Browser
- Download file 10.2 kB
-
https://huggingface.co/spaces/ThomasHeisig/Brain-5D-Space/resolve/main/src/dashboard/static/experiment-workflow.js
- Command line
-
hf download hf://spaces/ThomasHeisig/Brain-5D-Space/src/dashboard/static/experiment-workflow.js
-
curl -L -o experiment-workflow.js https://huggingface.co/spaces/ThomasHeisig/Brain-5D-Space/resolve/main/src/dashboard/static/experiment-workflow.js
10.2 kB
| ; | |
| import { ExperimentWorkflowPanel as BaseExperimentWorkflowPanel } from "./experiment-workflow-base.js"; | |
| function byId(id) { | |
| return document.getElementById(id); | |
| } | |
| function escapeHtml(value) { | |
| const div = document.createElement("div"); | |
| div.textContent = String(value ?? ""); | |
| return div.innerHTML; | |
| } | |
| const PROFILE_LABELS = Object.freeze({ | |
| standard: "Registrierter Gesamtplan", | |
| controls: "Nur Kontrollen", | |
| treatments: "Nur Treatments", | |
| replication: "Replikation", | |
| sensitivity: "Sensitivität", | |
| pilot: "Pilot", | |
| short: "Kurzlauf", | |
| }); | |
| export class ExperimentWorkflowPanel extends BaseExperimentWorkflowPanel { | |
| _ensureResearchUX() { | |
| super._ensureResearchUX(); | |
| const question = this.elements.question; | |
| if (!question || byId("workflow-research-catalog")) return; | |
| const host = question.closest("label")?.parentElement; | |
| if (!host) return; | |
| const catalog = document.createElement("section"); | |
| catalog.id = "workflow-research-catalog"; | |
| catalog.className = "research-catalog-selector"; | |
| catalog.innerHTML = ` | |
| <div class="panel-title"> | |
| <div> | |
| <h3>Research Catalog</h3> | |
| <p>Durchsuchbare Auswahl statt langer Pulldown-Liste. Operational = frozen/preregistered; Exploratory = protokollierter Lauf ohne Evidenz-Promotion.</p> | |
| </div> | |
| <span id="workflow-research-count" class="gate-badge pending">0 RQs</span> | |
| </div> | |
| <div class="research-catalog-controls"> | |
| <input id="workflow-research-search" type="search" placeholder="RQ, Hypothese oder Begriff suchen …" autocomplete="off"> | |
| <label class="research-catalog-check"><input id="workflow-research-operational" type="checkbox"> nur operational</label> | |
| </div> | |
| <div id="workflow-research-results" class="research-catalog-results" role="listbox" aria-label="Forschungsfragen"></div> | |
| <div class="research-dimension-control"> | |
| <label>MSBA Projektions-Dimensionen | |
| <input id="workflow-projection-dimensions" type="number" min="1" max="32" value="5"> | |
| </label> | |
| <small>1–32 Dimensionen für externe/MSBA-Projektionsräume. Der persistierte produktive SNN-Core bleibt aus Kompatibilitätsgründen derzeit 5D.</small> | |
| </div>`; | |
| host.insertAdjacentElement("beforebegin", catalog); | |
| const style = document.createElement("style"); | |
| style.dataset.researchCatalogStyle = "true"; | |
| style.textContent = ` | |
| .research-catalog-selector{grid-column:1/-1;border:1px solid var(--border-color,#30363d);border-radius:12px;padding:14px;margin-bottom:10px} | |
| .research-catalog-controls{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:10px 0} | |
| .research-catalog-controls input[type=search]{flex:1 1 320px;min-width:220px} | |
| .research-catalog-check{display:flex!important;gap:7px;align-items:center!important;white-space:nowrap} | |
| .research-catalog-results{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:8px;max-height:330px;overflow:auto;padding:2px} | |
| .research-rq-card{appearance:none;text-align:left;border:1px solid var(--border-color,#30363d);border-radius:9px;padding:10px;background:transparent;color:inherit;cursor:pointer} | |
| .research-rq-card:hover,.research-rq-card.is-selected{border-color:var(--accent,#58a6ff);background:rgba(88,166,255,.08)} | |
| .research-rq-head{display:flex;gap:8px;justify-content:space-between;align-items:center;margin-bottom:6px} | |
| .research-rq-card p{margin:0;font-size:.88rem;line-height:1.35} | |
| .research-rq-badge{font-size:.72rem;padding:2px 6px;border-radius:999px;border:1px solid currentColor;white-space:nowrap} | |
| .research-rq-badge.operational{color:#3fb950}.research-rq-badge.exploratory{color:#d29922} | |
| .research-dimension-control{display:flex;gap:12px;align-items:end;flex-wrap:wrap;margin-top:12px;padding-top:10px;border-top:1px solid var(--border-color,#30363d)} | |
| .research-dimension-control label{max-width:220px}.research-dimension-control small{max-width:680px;opacity:.8} | |
| `; | |
| document.head.appendChild(style); | |
| byId("workflow-research-search")?.addEventListener("input", () => this._renderResearchCatalog()); | |
| byId("workflow-research-operational")?.addEventListener("change", () => this._renderResearchCatalog()); | |
| byId("workflow-projection-dimensions")?.addEventListener("change", (event) => { | |
| const value = Math.max(1, Math.min(32, Number(event.target.value) || 5)); | |
| event.target.value = String(value); | |
| this._syncProjectionDimensions(value); | |
| }); | |
| } | |
| _configureConditionProfiles(preset = this.activePreset) { | |
| const select = this.elements.conditionProfile; | |
| if (!select) return; | |
| const profiles = preset?.profiles || { standard: preset?.conditions || "" }; | |
| select.replaceChildren(); | |
| for (const [key, value] of Object.entries(profiles)) { | |
| if (!value) continue; | |
| select.add(new Option(PROFILE_LABELS[key] || key, key)); | |
| } | |
| if (!select.options.length) select.add(new Option("Standard", "standard")); | |
| select.value = "standard"; | |
| } | |
| _renderQuestions() { | |
| super._renderQuestions(); | |
| this._renderResearchCatalog(); | |
| } | |
| _isOperational(questionId) { | |
| return this.protocols.some( | |
| (item) => item.research_question === questionId && item.preregistration, | |
| ); | |
| } | |
| _matchingHypotheses(questionId) { | |
| return this.hypotheses.filter((item) => item.question_id === questionId); | |
| } | |
| _renderResearchCatalog() { | |
| const results = byId("workflow-research-results"); | |
| const count = byId("workflow-research-count"); | |
| if (!results) return; | |
| const search = (byId("workflow-research-search")?.value || "").trim().toLowerCase(); | |
| const operationalOnly = Boolean(byId("workflow-research-operational")?.checked); | |
| const selected = this.elements.question?.value || ""; | |
| const visible = this.questions.filter((question) => { | |
| const hypotheses = this._matchingHypotheses(question.id); | |
| const haystack = [question.id, question.label, ...hypotheses.map((item) => `${item.id} ${item.label}`)] | |
| .join(" ") | |
| .toLowerCase(); | |
| if (search && !haystack.includes(search)) return false; | |
| if (operationalOnly && !this._isOperational(question.id)) return false; | |
| return true; | |
| }); | |
| if (count) count.textContent = `${visible.length} / ${this.questions.length} RQs`; | |
| results.innerHTML = visible | |
| .map((question) => { | |
| const operational = this._isOperational(question.id); | |
| const hypotheses = this._matchingHypotheses(question.id); | |
| return `<button type="button" class="research-rq-card ${selected === question.id ? "is-selected" : ""}" data-rq-id="${escapeHtml(question.id)}" role="option" aria-selected="${selected === question.id}"> | |
| <div class="research-rq-head"><strong>${escapeHtml(question.id)}</strong><span class="research-rq-badge ${operational ? "operational" : "exploratory"}">${operational ? "OPERATIONAL" : "EXPLORATORY"}</span></div> | |
| <p>${escapeHtml(question.label)}</p> | |
| <small>${hypotheses.length} Hypothese${hypotheses.length === 1 ? "" : "n"}</small> | |
| </button>`; | |
| }) | |
| .join(""); | |
| results.querySelectorAll("[data-rq-id]").forEach((button) => { | |
| button.addEventListener("click", () => this._selectResearchQuestion(button.dataset.rqId)); | |
| }); | |
| } | |
| _selectResearchQuestion(questionId) { | |
| if (!questionId || !this.elements.question) return; | |
| this.elements.question.value = questionId; | |
| this._renderHypotheses(); | |
| this._alignProtocolWithQuestion(); | |
| if (!this._isOperational(questionId) && this.elements.protocol) { | |
| this.elements.protocol.value = "runtime_ticks_v1"; | |
| this._applyProtocol(); | |
| } | |
| this._renderContract(); | |
| this._renderResearchCatalog(); | |
| } | |
| _syncProjectionDimensions(value) { | |
| const marker = `MSBA projection_dimensions=${value}`; | |
| const notes = this.elements.notes; | |
| if (notes) { | |
| const lines = String(notes.value || "") | |
| .split("\n") | |
| .filter((line) => !line.startsWith("MSBA projection_dimensions=")); | |
| lines.push(marker); | |
| notes.value = lines.filter(Boolean).join("\n"); | |
| } | |
| } | |
| _applyProtocol() { | |
| super._applyProtocol(); | |
| const operational = this._protocolContract(this.elements.protocol?.value); | |
| if (!operational) return; | |
| const profiles = operational.condition_profiles || { | |
| standard: (operational.conditions || []) | |
| .map((item) => `${item.id || item.condition_id || item}${item.role ? ` (${item.role})` : ""}`) | |
| .join("; "), | |
| }; | |
| const defaultSeeds = operational.default_seed_expression; | |
| this.activePreset = { | |
| ...(this.activePreset || {}), | |
| question: operational.research_question, | |
| hypothesis: operational.hypothesis, | |
| title: operational.label || operational.id, | |
| ticks: String(operational.default_ticks ?? this.elements.ticks?.value ?? "100"), | |
| seeds: defaultSeeds || this.activePreset?.seeds || "101", | |
| conditions: profiles.standard || "", | |
| profiles, | |
| }; | |
| if (this.elements.seeds && this.activePreset.seeds) this.elements.seeds.value = this.activePreset.seeds; | |
| if (this.elements.ticks && this.activePreset.ticks) this.elements.ticks.value = this.activePreset.ticks; | |
| this._configureConditionProfiles(this.activePreset); | |
| this._applyConditionProfile(this.activePreset); | |
| this._renderContract(); | |
| this._renderResearchCatalog(); | |
| } | |
| _renderContract() { | |
| super._renderContract(); | |
| if (this.activeContract) return; | |
| const content = byId("workflow-contract-content"); | |
| if (!content || !this.activePreset) return; | |
| content.innerHTML = ` | |
| <details class="legacy-diagnostic-details" open> | |
| <summary><span>Exploratory / diagnostic protocol</span><small>keine automatische Evidenz-Promotion</small></summary> | |
| <div class="legacy-diagnostic-body"> | |
| <p>${escapeHtml(this.activePreset.conditions || "")}</p> | |
| <p>Dieser Lauf kann die ausgewählte RQ/H protokolliert explorieren. Er besitzt aber keinen passenden eingefrorenen Research Contract und darf deshalb nicht als bestätigende Evidenz interpretiert werden.</p> | |
| </div> | |
| </details>`; | |
| } | |
| } | |