Employees + USB default-disabled with an enable-time provisioning note

Both plugins provision extra tables, so they now install disabled and explain
themselves before a site opts in.

- Plugin contract gains get_provisioning_note() -> {tables, note, docs}.
  Employees and USB implement it (what tables get created in shopdb, how they
  are referenced, link to the schema README; USB references the captured
  DLP/reminder plans).
- Manifest default_enabled=false for employees + usb; the plugins list API
  returns provisioning_note + default_enabled; install now registers a plugin
  disabled when default_enabled is false.
- Setup wizard Features step renders the provisioning note the moment a plugin
  with one is enabled.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-10 09:53:43 -04:00
parent f04deba011
commit 0e0bbc0604
8 changed files with 92 additions and 20 deletions

View File

@@ -36,11 +36,22 @@
<h2>Features</h2>
<p class="hint">Turn features on or off. Changes to routes take effect after the app restarts.</p>
<div v-if="plugins.length" class="plugin-list">
<label v-for="p in plugins" :key="p.name" class="plugin-row">
<input type="checkbox" :checked="p.enabled" @change="togglePlugin(p, $event.target.checked)" />
<span class="plugin-name">{{ p.name }}</span>
<span class="plugin-desc">{{ p.description }}</span>
</label>
<div v-for="p in plugins" :key="p.name" class="plugin-item">
<label class="plugin-row">
<input type="checkbox" :checked="p.enabled" @change="togglePlugin(p, $event.target.checked)" />
<span class="plugin-name">{{ p.name }}</span>
<span class="plugin-desc">{{ p.description }}</span>
</label>
<!-- Transparency note for plugins that provision extra tables -->
<div v-if="p.enabled && p.provisioning_note" class="provision-note">
<p>{{ p.provisioning_note.note }}</p>
<p class="provision-tables">
Creates in shopdb:
<code v-for="t in p.provisioning_note.tables" :key="t">{{ t }}</code>
</p>
<p v-if="p.provisioning_note.docs" class="provision-docs">Schema: <code>{{ p.provisioning_note.docs }}</code></p>
</div>
</div>
</div>
<p v-else class="hint">No optional plugins found.</p>
@@ -308,6 +319,10 @@ async function finish() {
.plugin-row { display: grid; grid-template-columns: auto auto 1fr; gap: 0.6rem; align-items: baseline; padding: 0.5rem 0.6rem; background: var(--bg); border-radius: 6px; }
.plugin-name { font-weight: 600; text-transform: capitalize; }
.plugin-desc { color: var(--text-light); font-size: 0.85rem; }
.provision-note { margin: 0.3rem 0 0.2rem 1.9rem; padding: 0.6rem 0.75rem; background: var(--bg); border-left: 3px solid var(--warning); border-radius: 4px; font-size: 0.82rem; }
.provision-note p { margin: 0 0 0.35rem; }
.provision-note p:last-child { margin-bottom: 0; }
.provision-tables code, .provision-docs code { background: var(--bg-card); border: 1px solid var(--border); border-radius: 3px; padding: 0 0.3rem; margin-right: 0.3rem; font-size: 0.78rem; }
.seed-result { margin-top: 0.75rem; color: var(--success); font-size: 0.88rem; }
.config-block { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.config-title { margin: 0 0 0.75rem; font-size: 1rem; text-transform: capitalize; }