DEV Community

Rahul
Rahul

Posted on

Testcraft Studio frontend 34: src/pages/Versions.jsx

import React, { useState } from 'react';
import Icon from '../Icon.jsx';
import { useStudio, resolveSelection, bumpVersion, log } from '../store.jsx';
import { Badge, Button, ContextBar, Heading, Note, SourceDialog, WorkspaceRequired } from '../ui.jsx';

export default function Versions({ navigate }) {
  const { state: s, mutate, workspace: w, notify } = useStudio();
  const [baselineId, setBaselineId] = useState(w?.baselineId || ''), [crIds, setCrs] = useState(w?.crIds || []), [source, setSource] = useState('');
  if (!w) return <WorkspaceRequired navigate={navigate}/>;
  const selection = resolveSelection(s, baselineId, crIds);
  const changed = baselineId !== w.baselineId || JSON.stringify([...crIds].sort()) !== JSON.stringify([...w.crIds].sort());
  const included = new Set(selection.diff.map(d => d.ruleId));
  return <><Heading eyebrow={`${w.ref} · KNOWLEDGE CONTEXT ${w.version}`} title="Select a knowledge version" description="Resolve the exact baseline and change revisions before using their evidence."><Button variant="primary" icon="layers" disabled={!w.crIds.length || changed || !!selection.issues.length} onClick={() => navigate('approvals?merge')}>Merge CRs into baseline</Button></Heading><ContextBar navigate={navigate}/><div className="detail-grid margin-top"><section className="card padded"><h2>Selected Baseline</h2><select className="wide-select margin-top" value={baselineId} onChange={e => setBaselineId(e.target.value)}>{s.baselines.filter(b => b.team === s.session.team && ['Active', 'Approved'].includes(b.status)).map(b => <option key={b.id} value={b.id}>{b.ref} · Baseline Version {b.version}</option>)}</select><h2 className="margin-top">Change requests</h2><p className="supporting-copy">A partial change replaces only its affected rule. Unchanged knowledge stays in the manifest.</p><div className="version-options">{s.crs.filter(c => c.team === s.session.team).map(c => { const incorporated = selection.baseline?.incorporatedCRs.includes(c.id); return <label key={c.id}><input type="checkbox" disabled={incorporated} checked={crIds.includes(c.id)} onChange={() => setCrs(ids => ids.includes(c.id) ? ids.filter(id => id !== c.id) : [...ids, c.id])}/><span><strong>{c.ref} · {c.name}</strong><small>Revision {c.revision} · {c.changes.length} changes{c.requires.length ? ` · Requires ${c.requires.map(id => s.crs.find(cr => cr.id === id)?.ref).join(', ')}` : ''}</small></span><Badge tone={incorporated ? 'neutral' : 'purple'}>{incorporated ? 'Incorporated' : 'Available'}</Badge></label>; })}</div>{!s.crs.some(c => c.team === s.session.team) && <Note>No change requests have been added to this team.</Note>}</section><section className="card padded"><h2>Resolved selection</h2><div className="selection-summary"><span>Baseline plus selected changes</span><strong>{selection.baseline?.ref || 'Choose a baseline'}{selection.changes.map(c => ` + ${c.ref}`).join('')}</strong><small>{selection.diff.length} changed rules · {selection.baseline?.rules.filter(r => !included.has(r.id)).length || 0} unchanged rules</small></div>{selection.issues.map(issue => <Note tone="amber" key={issue}>{issue}</Note>)}<p className="supporting-copy">Applying a new selection creates a fresh version-specific chat context and resets clarification readiness. Historical chats and suites retain their original version.</p><Button variant="primary" className="full-width margin-top" disabled={!changed || selection.issues.length > 0} onClick={() => { mutate(d => { const current = d.workspaces.find(item => item.id === w.id); current.baselineId = baselineId; current.crIds = crIds; bumpVersion(d, current); log(d, `Changed knowledge selection for ${w.ref}`); }); notify('New knowledge context created. Clarifications require revalidation.'); }}>Use this version</Button></section></div><section className="card margin-top"><div className="section-heading"><h2>Knowledge diff</h2><Badge tone="purple">Exact selected revisions</Badge></div>{selection.diff.map((change, i) => <div className="diff-block" key={`${change.crRef}-${i}`}><div className="diff-heading"><span className={`operation operation-${change.op.toLowerCase()}`}>{change.op}</span><strong>{change.ruleId} · {change.title}</strong><span>{change.crRef}</span><button className="text-button" onClick={() => setSource(change.source)}>Source <Icon name="external" size={12}/></button></div><div className="diff-columns"><div><small>BASELINE REVISION</small><p>{change.before || 'New rule — not present in baseline'}</p></div><div><small>SELECTED CR REVISION</small><p>{change.after || 'Removed from resolved knowledge'}</p></div></div></div>)}{selection.baseline?.rules.filter(r => !included.has(r.id)).map(r => <div className="rule-row" key={r.id}><Badge>Unchanged</Badge><div><strong>{r.id} · {r.title}</strong><p>{r.text}</p></div></div>)}{!selection.diff.length && <div className="padded"><Note>No CR changes selected. Retrieval uses the selected baseline manifest.</Note></div>}</section><section className="card padded margin-top"><h2>Shared contracts</h2><p className="supporting-copy">Select explicitly shared evidence. Changing a contract creates a fresh knowledge context.</p>{s.shares.filter(g => g.consumer === w.team && g.status === 'Active').map(g => <label className="check-label" key={g.id}><input type="checkbox" checked={(w.sharedContractIds || []).includes(g.sourceId)} onChange={e => { const checked = e.target.checked; mutate(d => { const current = d.workspaces.find(item => item.id === w.id); current.sharedContractIds = checked ? [...new Set([...current.sharedContractIds || [], g.sourceId])] : (current.sharedContractIds || []).filter(id => id !== g.sourceId); bumpVersion(d, current); log(d, 'Changed selected shared evidence for ' + w.ref); }); notify('Shared evidence selection updated. Clarifications require revalidation.'); }}/>{s.documents.find(doc => doc.id === g.sourceId)?.name} · Shared by {g.owner}</label>)}{w.sharedContractIds?.length ? w.sharedContractIds.map(id => { const doc = s.documents.find(d => d.id === id), grant = s.shares.find(g => g.sourceId === id && g.consumer === w.team); return <div className="history-row" key={id}><Icon name="lock" size={18}/><span><strong>{doc?.name}</strong><small>Owner: {doc?.team} · Revision {doc?.revision} · Shared boundary only</small></span><Badge tone={grant?.status === 'Active' ? 'green' : 'amber'}>{grant?.status || 'Unavailable'}</Badge>{grant?.status !== "Active" && <Button onClick={() => mutate(d => { const current = d.workspaces.find(item => item.id === w.id); current.sharedContractIds = current.sharedContractIds.filter(item => item !== id); bumpVersion(d, current); })}>Remove selection</Button>}</div>; }) : <p className="supporting-copy">No shared contracts are selected for this workspace.</p>}</section>{source && <SourceDialog sourceId={source} close={() => setSource('')}/>}</>;
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)