176 lines
7.0 KiB
Markdown
176 lines
7.0 KiB
Markdown
# Step Library Page — Design
|
|
|
|
> **Date:** February 24, 2026
|
|
> **Status:** Approved
|
|
> **Phase:** 2.5 — Feature 1 of 3
|
|
|
|
---
|
|
|
|
## What We're Building
|
|
|
|
Replace the "Coming Soon" stub in `StepLibraryPage` with a fully functional standalone Step Library. Users can browse, search, create, edit, delete, preview, and save steps to their own library.
|
|
|
|
All backend endpoints and frontend components are already built. This is primarily a wiring and UX integration task.
|
|
|
|
---
|
|
|
|
## Scope
|
|
|
|
**In scope:**
|
|
- Full-page Step Library with header, filters, grouped results
|
|
- Create step flow (modal with `StepForm`)
|
|
- Edit step flow (same modal, pre-filled)
|
|
- Delete step with confirmation
|
|
- "Save to My Library" for steps you don't own (copies step as private)
|
|
- Preview via `StepDetailModal`
|
|
- `StepCard` actions adapted for library context (vs. session insert context)
|
|
|
|
**Out of scope:**
|
|
- Rating/reviewing steps from this page (deferred — will come when steps are used in sessions)
|
|
- Admin category management (already exists in Admin Panel)
|
|
- Session custom step insertion (Feature 2 of 3)
|
|
|
|
---
|
|
|
|
## Card Actions by Context
|
|
|
|
| Ownership | Actions |
|
|
|-----------|---------|
|
|
| Your own step | Preview · Edit · Delete |
|
|
| Team or public step | Preview · Save to My Library |
|
|
|
|
"Save to My Library" POSTs a new step copying the title, step_type, content, category, and tags — with `visibility: 'private'` and the current user as owner.
|
|
|
|
---
|
|
|
|
## Page Layout
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Step Library [+ Create Step] │
|
|
│ Reusable steps you can insert into any flow │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ [Search...] [Category ▼] [Type ▼] [Rating ▼] [Sort▼]│
|
|
│ Popular Tags: [powershell] [dns] [quick-fix] ... │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ MY STEPS (3) [▲] │
|
|
│ ┌────────────┐ ┌────────────┐ │
|
|
│ │ StepCard │ │ StepCard │ (Preview · Edit · Del) │
|
|
│ └────────────┘ └────────────┘ │
|
|
│ │
|
|
│ TEAM STEPS (12) [▲] │
|
|
│ ┌────────────┐ ┌────────────┐ │
|
|
│ │ StepCard │ │ StepCard │ (Preview · Save) │
|
|
│ └────────────┘ └────────────┘ │
|
|
│ │
|
|
│ COMMUNITY (47) [▲] │
|
|
│ ┌────────────┐ ┌────────────┐ │
|
|
│ │ StepCard │ │ StepCard │ (Preview · Save) │
|
|
│ └────────────┘ └────────────┘ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Component Architecture
|
|
|
|
### StepLibraryPage (rewritten)
|
|
- Owns modal state: `createOpen`, `editingStep`, `deletingStepId`
|
|
- Renders page header with "+ Create Step" button
|
|
- Renders `StepLibraryBrowser` with page-context props
|
|
- Renders `StepFormModal` (create/edit)
|
|
- Renders delete confirmation dialog
|
|
|
|
### StepLibraryBrowser (extend props)
|
|
Add props:
|
|
```ts
|
|
interface StepLibraryBrowserProps {
|
|
onInsert: (step: Step) => void // existing (used in session context)
|
|
onEdit?: (step: Step) => void // new — library page only
|
|
onDelete?: (stepId: string) => void // new — library page only
|
|
onSave?: (step: Step) => void // new — save to my library
|
|
onCreateNew?: () => void // existing
|
|
showCreateButton?: boolean // existing
|
|
currentUserId?: string // new — to determine ownership
|
|
}
|
|
```
|
|
|
|
### StepCard (extend props)
|
|
Add props mirroring the browser:
|
|
```ts
|
|
interface StepCardProps {
|
|
step: StepListItem
|
|
onPreview: (step: StepListItem) => void
|
|
onInsert?: (step: StepListItem) => void // optional — session context
|
|
onEdit?: (step: StepListItem) => void // library context
|
|
onDelete?: (stepId: string) => void // library context
|
|
onSave?: (step: StepListItem) => void // library context
|
|
currentUserId?: string
|
|
}
|
|
```
|
|
|
|
`StepCard` renders actions based on which callbacks are present and whether `step.created_by === currentUserId`.
|
|
|
|
### StepFormModal (new wrapper component)
|
|
Thin modal shell around the existing `StepForm`:
|
|
- Fixed header ("Create Step" or "Edit Step")
|
|
- Scrollable body with `StepForm`
|
|
- Handles create (`stepsApi.create`) and update (`stepsApi.update`) API calls
|
|
- Calls `onSuccess(step)` so the browser list can refresh
|
|
|
|
---
|
|
|
|
## Data Flow
|
|
|
|
### Create
|
|
1. User clicks "+ Create Step"
|
|
2. `StepFormModal` opens in create mode
|
|
3. On submit → `stepsApi.create(data)` → `onSuccess` → reload steps
|
|
|
|
### Edit
|
|
1. User clicks Edit on their own step card
|
|
2. `stepsApi.get(stepId)` fetches full step (need content fields)
|
|
3. `StepFormModal` opens pre-filled with step data
|
|
4. On submit → `stepsApi.update(id, data)` → `onSuccess` → reload steps
|
|
|
|
### Delete
|
|
1. User clicks Delete on their own step card
|
|
2. Confirmation dialog: "Delete '[title]'? This cannot be undone."
|
|
3. On confirm → `stepsApi.delete(id)` → remove from local state
|
|
|
|
### Save to My Library
|
|
1. User clicks "Save to My Library" on a team/public step
|
|
2. No confirmation needed — silent copy
|
|
3. `stepsApi.create({ ...step fields, visibility: 'private' })` → toast "Saved to My Steps"
|
|
4. Reload steps so the copy appears under "My Steps"
|
|
|
|
---
|
|
|
|
## Files to Change
|
|
|
|
| File | Change |
|
|
|------|--------|
|
|
| `pages/StepLibraryPage.tsx` | Rewrite — wire up browser + modals |
|
|
| `components/step-library/StepCard.tsx` | Add `onEdit`, `onDelete`, `onSave`, `currentUserId` props; render contextual buttons |
|
|
| `components/step-library/StepLibraryBrowser.tsx` | Add `onEdit`, `onDelete`, `onSave`, `currentUserId` props; pass through to cards; expose refresh trigger |
|
|
| `components/step-library/StepFormModal.tsx` | Create — thin modal wrapper around `StepForm` |
|
|
|
|
No backend changes required.
|
|
|
|
---
|
|
|
|
## StepCard Button Layout
|
|
|
|
**Own step:**
|
|
```
|
|
[Preview] [Edit] [🗑]
|
|
```
|
|
Edit and Preview are full-width-ish buttons; delete is an icon-only button in red on hover.
|
|
|
|
**Others' step:**
|
|
```
|
|
[Preview] [Save to My Library]
|
|
```
|
|
|
|
Both full-width buttons, same pattern as current Insert layout.
|