CI surfaced react-hooks/set-state-in-effect on the synchronous setState(computeState(token)) inside the useEffect body. The earlier shape mirrored token -> state via an effect, which is exactly the "you might not need an effect" pattern React 19's eslint rule now flags. Switch to derived state: compute during render, use a useReducer tick to force re-render on the 30s cadence (so relative timestamps stay current even when token props don't change). Same observable behavior, no cascading renders. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.2 KiB
Script Template Editor — Design Document
Date: 2026-03-13 Status: Approved Depends on: Script Generator Phase 1 (backend) + Phase 2 (Script Library frontend)
Goal
Build a Script Template Editor page where engineers can create and manage their own PowerShell script templates, and owners/admins can promote personal templates to team-wide visibility via a "Share with team" toggle.
Page Structure
Route: /scripts/manage
Two modes:
- List mode — all templates the user can see/edit. Filterable by category, searchable by name. Each row: name, category, complexity badge, usage count, scope badge ("Personal" / "Team"), action buttons (Edit, Delete).
- Editor mode — full-page form for creating or editing a template. No modal — the template has too many fields. "Back to templates" link with unsaved-changes warning if dirty.
Navigation entry points:
- "Manage Templates" link on the Script Library page header (visible to engineers+)
- Direct URL
/scripts/manage
Permissions
Who sees what in the list
| Role | Visible templates |
|---|---|
| Engineer | Own templates (created_by = user.id) + team templates (team_id = user.team_id) |
| Owner / Admin | All templates in their account scope |
| Super admin | All templates across all accounts |
Who can do what
| Action | Engineer | Owner/Admin | Super Admin |
|---|---|---|---|
| Create template | Yes (personal scope) | Yes (personal or team) | Yes (any scope) |
| Edit own template | Yes | Yes | Yes |
| Edit others' templates | No | Yes (within account) | Yes (all) |
| Delete own template | Yes (soft delete) | Yes | Yes |
| Delete others' templates | No | Yes (within account) | Yes (all) |
| "Share with team" toggle | No | Yes | Yes |
Backend Changes
Permission refactor
Replace _require_team_admin() with _check_template_permission(user, template?):
- Create: engineers+ can create (personal scope)
- Edit/Delete: engineers can modify own templates (
created_by == user.id); owners/admins can modify any template in their account; super admins can modify any - Existing
POST /scripts/templatessetscreated_by = user.idandteam_id = nullfor engineers (personal scope)
New endpoint
PATCH /scripts/templates/{id}/share — owner/admin/super_admin only
- Body:
{ "shared": boolean } shared=true→ setsteam_idto the user'steam_idshared=false→ clearsteam_idtonull(reverts to personal scope for original author)- Returns updated
ScriptTemplateDetail
Query filter
Update GET /scripts/templates to support managed=true query param:
- Returns templates the user can edit (own templates + team templates for owners/admins)
- Used by the manage page list view
Template Editor Form
Single scrollable page with sections separated by dividers. Fixed bottom action bar.
Section 1: Metadata
- Name — text input, required
- Description — textarea
- Use Case — textarea ("when would you use this?")
- Category — select dropdown from existing categories
- Complexity — select: beginner / intermediate / advanced
- Tags — multi-text input (comma-separated or chip-style)
- Estimated Runtime — text input (e.g., "30 seconds")
- Requires Elevation — checkbox
- Required Modules — multi-text input
- Share with team — toggle switch, visible only to owners/admins/super_admins. Help text: "When enabled, all team members can browse and use this template."
Section 2: Script Body
- Large textarea with
PowerShellHighlighterfor syntax coloring - Monospace font (
font-label/ JetBrains Mono) {{parameter_key}}placeholders highlighted in amber so authors can see where parameters slot in- Simple textarea with highlighting overlay (no Monaco/CodeMirror dependency)
Section 3: Parameters Schema
Two modes with a toggle at the top of the section:
Visual mode (default):
- List of parameter cards, each expandable/collapsible
- "Add Parameter" button at bottom
- Each card: key, label, type (select from 7 types), required toggle, placeholder, group, order, help_text, default value, sensitive toggle
- For
selecttype: options sub-list (value + label pairs) - For types with validation: min/max/pattern fields
- Drag-to-reorder or up/down arrows for parameter ordering
JSON mode:
- Raw JSON editor showing the
parameters_schemaobject - Edits sync back to visual mode on switch
- Parse errors shown inline
Section 4: Fixed Action Bar
- Save — primary button, creates or updates template
- Cancel — back to list with dirty-state warning
- Delete — danger button (right-aligned), only in edit mode, confirmation modal, soft delete
Team Sharing Behavior
- Default for engineer-created templates:
team_id = null(personal, only visible to creator) - Shared:
team_idset to account's team — template appears in Script Library for all team members - Unsharing: reverts to personal scope for original author; author retains edit access via
created_by
Frontend Components (Expected)
| Component | Responsibility |
|---|---|
ScriptManagePage.tsx |
Page shell, list/editor mode toggle |
ScriptTemplateListView.tsx |
Template list with filters, search, action buttons |
ScriptTemplateEditor.tsx |
Full editor form — metadata, script body, parameters |
ParameterSchemaBuilder.tsx |
Visual parameter builder with add/remove/reorder |
ParameterCard.tsx |
Single parameter editor (expandable card) |
ParameterJsonEditor.tsx |
Raw JSON mode for parameters schema |
ScriptBodyEditor.tsx |
Textarea with PowerShell highlighting overlay |
ShareToggle.tsx |
Team sharing toggle (owner/admin only) |
Design System Compliance
- Dark glassmorphism theme,
.glass-card-staticcontainers - Primary actions:
bg-gradient-brand - Section labels:
font-label text-[0.625rem] uppercase tracking-[0.1em] - Form inputs:
border-border bg-card text-foregroundwith cyan focus ring - Complexity badges: emerald (beginner), amber (intermediate), rose (advanced)
- Scope badges: "Personal" (muted border) / "Team" (cyan/primary tint)