Plugin Studio: the Experimental section no longer reads CAP 0, and clicking a plugin no longer unfolds it

The Experimental section is a stage, not a tier, so its heading showed CAP 0
and the Research Gallery (capability 5) looked like a capability-0 plugin. The
heading now reads EXP and each of its rows names its own capability. Clicking a
plugin opens it without unfolding its folder or its parts; only the twisty
folds and unfolds, and a closed folder that stands for the plugin stays closed.
This commit is contained in:
Doxa Maps 2026-09-27 22:13:27 +00:00
parent b03c8d4bd4
commit 22440899d5
2 changed files with 22 additions and 10 deletions

View file

@ -632,7 +632,8 @@ export default defineComponent({
const pushElement = (r, depth, parent) => {
const t = treeOf.get(r.key)
nodes.push({
id: r.key, parent, depth, label: r.label, desc: r.tag, icon: r.icon, target: r.key, canonical: true,
// In the Experimental section the heading carries no tier, so each row says its own.
id: r.key, parent, depth, label: r.label, desc: cap === 'experimental' ? 'CAP ' + r.cap + ' · ' + r.tag : r.tag, icon: r.icon, target: r.key, canonical: true,
kids: t ? t.nodes[0].kids : 0, title: r.label + ' · <' + r.tag + '> · CAP ' + r.cap + ' ' + this.tr('cap' + r.cap)
})
if (!t) return
@ -660,7 +661,9 @@ export default defineComponent({
})
for (const r of rows) pushElement(r, 1, fid)
}
if (cap === 'experimental') return { id: 'stage-experimental', cap: 0, label: this.tr('stageExperimental'), title: this.tr('stageExperimental'), icon: 'layers', nodes }
// The Experimental section is a STAGE, not a tier: it has no capability number of its own (it read
// "CAP 0", and the Driver took the Research Gallery for a capability-0 plugin).
if (cap === 'experimental') return { id: 'stage-experimental', cap: 0, badge: 'EXP', short: 'E', label: this.tr('stageExperimental'), title: this.tr('stageExperimental'), icon: 'layers', nodes }
return { id: 'cap-' + cap, cap, label: this.tr('cap' + cap), title: this.tr('cap' + cap) + ' · ' + (MACHINE_TYPE[cap] || ''), icon: CAP_ICON[cap] || 'embed', nodes }
}).filter(Boolean)
},

View file

@ -36,10 +36,10 @@
<div v-if="collapsed" class="st-activity">
<button v-for="s in sections" :key="s.id" type="button" class="st-act"
:class="{ active: s.id === activeSectionId }"
:aria-label="str('openSection', { cap: 'CAP ' + s.cap, label: s.label })"
:aria-label="str('openSection', { cap: s.badge || 'CAP ' + s.cap, label: s.label })"
@click="openSectionFromActivity(s.id)">
<span class="st-act-ic" aria-hidden="true" v-html="svg(s.icon)"></span>
<span class="st-act-n" aria-hidden="true">{{ s.cap }}</span>
<span class="st-act-n" aria-hidden="true">{{ s.short || s.cap }}</span>
</button>
</div>
@ -70,7 +70,7 @@
@focus="focusId = item.id">
<template v-if="item.section">
<span class="st-twisty" aria-hidden="true" v-html="chev"></span>
<span class="st-cap">CAP {{ item.cap }}</span>
<span class="st-cap">{{ item.badge }}</span>
<span class="st-sec-label">{{ item.label }}</span>
<span class="st-count">{{ item.count }}</span>
</template>
@ -209,7 +209,7 @@ export default defineComponent({
if (this.kept && !nodes.length) continue
out.push({
id: 'sec:' + s.id, section: true, sectionId: s.id, level: 1, depth: 0, expandable: true,
cap: s.cap, label: s.label, title: s.title || '', count: s.nodes.filter(n => n.depth === 0).length
cap: s.cap, badge: s.badge || 'CAP ' + s.cap, label: s.label, title: s.title || '', count: s.nodes.filter(n => n.depth === 0).length
})
if (!this.kept && this.secClosed[s.id]) continue
for (const n of nodes) {
@ -273,11 +273,11 @@ export default defineComponent({
},
setRow(id, el) { if (!this._rows) this._rows = {}; if (el) this._rows[id] = el; else delete this._rows[id] },
// Choosing a plugin opens it in the pane (through the layout's pick, which also closes the mobile
// drawer) and unfolds its parts — you asked for that plugin, so show what it is made of. Only the
// twisty or ← folds. A part with no page of its own opens the composite it lives in.
// drawer). It does NOT unfold the row: the Driver clicks UPG 100 List to see UPG 100 List, not every
// element inside it. Only the twisty (or → / ←) folds and unfolds. A part with no page of its own
// opens the composite it lives in.
activate(item) {
if (item.section) { this.toggle(item); return }
if (item.expandable && !this.isOpen(item)) this.setOpen(item, true)
if (!item.target) return
if (this.pick) this.pick(item.target); else this.$emit('select', item.target)
},
@ -333,7 +333,16 @@ export default defineComponent({
row = s.nodes.find(n => isCanonical(n) && n.target === this.active)
if (row) { if (this.secClosed[s.id]) { this.secClosed = { ...this.secClosed, [s.id]: false }; this.saveState() } break }
}
// A plugin inside a BUNDLE FOLDER: open the folder(s) above it, or it cannot be seen.
// A closed bundle folder whose own target IS this plugin already stands for it: highlight the folder,
// don't unfold it. Otherwise open the folder(s) above the plugin, or it cannot be seen.
if (row) {
for (let p = row.parent; p;) {
const pn = this.byId.get(p)
if (!pn) break
if (pn.target === this.active && !this.nodeOpen[p]) { row = pn; break }
p = pn.parent
}
}
if (row) {
let p = row.parent, opened = false
while (p) { if (!this.nodeOpen[p]) { this.nodeOpen = { ...this.nodeOpen, [p]: true }; opened = true } p = this.byId.get(p) && this.byId.get(p).parent }