Sprint: Verbeteren debug mode (#179)
* feat(PBI-49): add debugProps helper + Vitest test
Adds lib/debug.ts with debugProps(id, component, file) that returns
data-debug-id and data-debug-label attrs in dev mode, empty object in
production. Adds __tests__/lib/debug.test.ts covering both modes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(PBI-49): add debug-id pattern doc + CLAUDE.md reference
Adds docs/patterns/debug-id.md documenting the named-component boundary
rule (6 punten), helper-voorbeeld, skip-criteria en motivatie voor
handmatige pad-argumenten. Voegt verwijzing toe aan CLAUDE.md
patterns-tabel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(PBI-49): migrate 17 shared/ components to debugProps helper
Replace hardcoded data-debug-id + data-debug-label attribute pairs with
{...debugProps(id, component, file)} spread in all 17 components/shared/
files. Existing debug-ids preserved unchanged.
* feat(PBI-49): add debugProps to backlog/, sprint/, solo/ components
* feat(PBI-49): add debugProps to jobs/ + ideas/ components
* feat(PBI-49): add debugProps to products/ + settings/ + notifications/ components
* feat(PBI-49): add debugProps to admin/ + dashboard/ + dialogs/ + mobile/ + split-pane/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(PBI-49): use attr(data-debug-id) for debug tooltip in globals.css
* refactor(PBI-49): remove data-debug-label from debugProps helper + test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(PBI-49): strip unused component/file args from debugProps in shared/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to StatusBar, NavBar, PanelNavBar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to components/sprint/*
- new-sprint-dialog: __submit on submit button
- sprint-backlog: __list on SprintBacklogLeft + SprintBacklogRight scroll areas
- sprint-board-client: root wrapper div (display:contents) + __drag-overlay
- sprint-header: __title on goal button, __dates on dates button, __actions on action cluster
- sprint-run-controls: root on controls div, __start/__cancel on action buttons; __blockers-dialog on dialog content
- start-sprint-button: root on trigger button, __dialog on dialog content, __submit on submit button
- sync-active-sprint-cookie: no debug-id (returns null, side-effect only), comment added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to components/backlog/*
* feat(PBI-49): add BEM sub-element data-debug-id to components/ideas/*
* feat(PBI-49): add BEM sub-element data-debug-id to components/dashboard/* + components/markdown.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to new-product-button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to components/solo/*
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-elements to nav-status-indicators
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to components/jobs/*
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to components/products/*
* feat(PBI-49): add BEM sub-element data-debug-id to components/notifications/*
- answer-modal: __content (scroll area), __submit (footer)
- notifications-bridge: skip comment (bridge, non-rendering wrapper)
- notifications-realtime-mount: skip comment (returns null)
- notifications-sheet: __header, __items (questions list)
- push-toggle: __switch (button), __label (button text) on subscribed/unsubscribed states
* feat(PBI-49): add BEM sub-element data-debug-id to components/settings/*
- leave-product-button: root only (single-button component)
- min-quota-editor: __input (number input), __save (save button)
- profile-editor: __username (bio/short-description input), __save (submit)
- role-manager: __roles (checkbox list), __add (save button)
- token-manager: __tokens (active tokens list), __generate (create button)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(PBI-49): add BEM sub-element data-debug-id to admin, auth, dialogs, entity-dialog, mobile, split-pane
* docs(PBI-49): add debug-labels BEM pattern doc + CLAUDE.md entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ce43f7720a
commit
d292e445d9
93 changed files with 600 additions and 218 deletions
|
|
@ -4,6 +4,7 @@ import { useState, useTransition } from 'react'
|
|||
import { Button } from '@/components/ui/button'
|
||||
import { DemoTooltip } from '@/components/shared/demo-tooltip'
|
||||
import { leaveProductAction } from '@/actions/products'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
|
||||
interface LeaveProductButtonProps {
|
||||
productId: string
|
||||
|
|
@ -22,7 +23,7 @@ export function LeaveProductButton({ productId, isDemo = false }: LeaveProductBu
|
|||
|
||||
if (confirming) {
|
||||
return (
|
||||
<div className="flex gap-2 shrink-0">
|
||||
<div className="flex gap-2 shrink-0" {...debugProps('leave-product-button', 'LeaveProductButton', 'components/settings/leave-product-button.tsx')}>
|
||||
<Button variant="destructive" size="sm" disabled={isPending} onClick={handleLeave}>
|
||||
{isPending ? 'Bezig…' : 'Ja, verlaten'}
|
||||
</Button>
|
||||
|
|
@ -34,16 +35,18 @@ export function LeaveProductButton({ productId, isDemo = false }: LeaveProductBu
|
|||
}
|
||||
|
||||
return (
|
||||
<DemoTooltip show={isDemo}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="shrink-0 border-error/40 text-error hover:bg-error/10"
|
||||
disabled={isDemo}
|
||||
onClick={() => !isDemo && setConfirming(true)}
|
||||
>
|
||||
Verlaten
|
||||
</Button>
|
||||
</DemoTooltip>
|
||||
<span {...debugProps('leave-product-button', 'LeaveProductButton', 'components/settings/leave-product-button.tsx')}>
|
||||
<DemoTooltip show={isDemo}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="shrink-0 border-error/40 text-error hover:bg-error/10"
|
||||
disabled={isDemo}
|
||||
onClick={() => !isDemo && setConfirming(true)}
|
||||
>
|
||||
Verlaten
|
||||
</Button>
|
||||
</DemoTooltip>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { toast } from 'sonner'
|
|||
import { Button } from '@/components/ui/button'
|
||||
import { DemoTooltip } from '@/components/shared/demo-tooltip'
|
||||
import { updateMinQuotaPctAction } from '@/actions/settings'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
|
||||
interface MinQuotaEditorProps {
|
||||
currentValue: number
|
||||
|
|
@ -27,7 +28,7 @@ export function MinQuotaEditor({ currentValue, isDemo }: MinQuotaEditorProps) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-3" {...debugProps('min-quota-editor', 'MinQuotaEditor', 'components/settings/min-quota-editor.tsx')}>
|
||||
<div>
|
||||
<label htmlFor="min-quota-pct" className="text-sm font-medium text-foreground">
|
||||
Minimaal beschikbaar Claude-quota voordat de worker een job oppakt (%)
|
||||
|
|
@ -46,10 +47,11 @@ export function MinQuotaEditor({ currentValue, isDemo }: MinQuotaEditorProps) {
|
|||
onChange={e => setValue(Number(e.target.value))}
|
||||
disabled={isDemo || isPending}
|
||||
className="w-24 rounded border border-border bg-surface-container px-3 py-1.5 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-primary disabled:opacity-50"
|
||||
data-debug-id="min-quota-editor__input"
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">%</span>
|
||||
<DemoTooltip show={isDemo}>
|
||||
<Button onClick={handleSave} disabled={isDemo || isPending} size="sm">
|
||||
<Button onClick={handleSave} disabled={isDemo || isPending} size="sm" data-debug-id="min-quota-editor__save">
|
||||
Opslaan
|
||||
</Button>
|
||||
</DemoTooltip>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Button } from '@/components/ui/button'
|
|||
import { Input } from '@/components/ui/input'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { updateProfileAction } from '@/actions/profile'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
|
||||
interface ProfileEditorProps {
|
||||
email: string | null
|
||||
|
|
@ -63,7 +64,7 @@ export function ProfileEditor({ email, bio, bioDetail, hasAvatar, avatarVersion
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="space-y-5" {...debugProps('profile-editor', 'ProfileEditor', 'components/settings/profile-editor.tsx')}>
|
||||
<div className="flex items-center gap-5">
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -137,6 +138,7 @@ export function ProfileEditor({ email, bio, bioDetail, hasAvatar, avatarVersion
|
|||
placeholder="Bijv. Full-stack developer bij Acme"
|
||||
maxLength={160}
|
||||
disabled={isPending}
|
||||
data-debug-id="profile-editor__username"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">Max. 160 tekens</p>
|
||||
</div>
|
||||
|
|
@ -158,7 +160,7 @@ export function ProfileEditor({ email, bio, bioDetail, hasAvatar, avatarVersion
|
|||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<Button type="submit" size="sm" disabled={isPending}>
|
||||
<Button type="submit" size="sm" disabled={isPending} data-debug-id="profile-editor__save">
|
||||
{isPending ? 'Opslaan…' : 'Opslaan'}
|
||||
</Button>
|
||||
{state && 'success' in state && (
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { toast } from 'sonner'
|
|||
import { Button } from '@/components/ui/button'
|
||||
import { DemoTooltip } from '@/components/shared/demo-tooltip'
|
||||
import { updateRolesAction } from '@/actions/settings'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
|
||||
const ALL_ROLES = [
|
||||
{ value: 'PRODUCT_OWNER', label: 'Product Owner' },
|
||||
|
|
@ -46,9 +47,9 @@ export function RoleManager({ currentRoles, isDemo }: RoleManagerProps) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="bg-surface-container-low border border-border rounded-xl p-5 space-y-4">
|
||||
<div className="bg-surface-container-low border border-border rounded-xl p-5 space-y-4" {...debugProps('role-manager', 'RoleManager', 'components/settings/role-manager.tsx')}>
|
||||
<h2 className="text-sm font-medium text-foreground">Mijn rollen</h2>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<div className="flex flex-wrap gap-3" data-debug-id="role-manager__roles">
|
||||
{ALL_ROLES.map(role => (
|
||||
<label key={role.value} className="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
|
|
@ -65,7 +66,7 @@ export function RoleManager({ currentRoles, isDemo }: RoleManagerProps) {
|
|||
{error && <p className="text-xs text-error">{error}</p>}
|
||||
{saved && <p className="text-xs text-success">Rollen opgeslagen.</p>}
|
||||
<DemoTooltip show={isDemo}>
|
||||
<Button size="sm" onClick={handleSave} disabled={isDemo}>Opslaan</Button>
|
||||
<Button size="sm" onClick={handleSave} disabled={isDemo} data-debug-id="role-manager__add">Opslaan</Button>
|
||||
</DemoTooltip>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Button } from '@/components/ui/button'
|
|||
import { Input } from '@/components/ui/input'
|
||||
import { DemoTooltip } from '@/components/shared/demo-tooltip'
|
||||
import { createApiTokenAction, revokeApiTokenAction } from '@/actions/api-tokens'
|
||||
import { debugProps } from '@/lib/debug'
|
||||
|
||||
interface Token {
|
||||
id: string
|
||||
|
|
@ -23,7 +24,7 @@ function CreateSubmitButton({ isDemo }: { isDemo: boolean }) {
|
|||
const { pending } = useFormStatus()
|
||||
return (
|
||||
<DemoTooltip show={isDemo}>
|
||||
<Button type="submit" disabled={isDemo || pending}>
|
||||
<Button type="submit" disabled={isDemo || pending} data-debug-id="token-manager__generate">
|
||||
{pending ? 'Aanmaken…' : 'Token aanmaken'}
|
||||
</Button>
|
||||
</DemoTooltip>
|
||||
|
|
@ -63,7 +64,7 @@ export function TokenManager({ tokens, isDemo }: TokenManagerProps) {
|
|||
const revokedTokens = tokens.filter(t => t.revoked_at)
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-6" {...debugProps('token-manager', 'TokenManager', 'components/settings/token-manager.tsx')}>
|
||||
{/* New token revealed */}
|
||||
{newToken && (
|
||||
<div className="bg-success-container border border-success/30 rounded-xl p-4 space-y-3">
|
||||
|
|
@ -103,7 +104,7 @@ export function TokenManager({ tokens, isDemo }: TokenManagerProps) {
|
|||
{activeTokens.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">Geen actieve tokens.</p>
|
||||
) : (
|
||||
<div className="bg-surface-container-low border border-border rounded-xl divide-y divide-border">
|
||||
<div className="bg-surface-container-low border border-border rounded-xl divide-y divide-border" data-debug-id="token-manager__tokens">
|
||||
{activeTokens.map(token => (
|
||||
<div key={token.id} className="flex items-center justify-between px-4 py-3 gap-3">
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue