Testcraft Studio frontend 34: src/pages/Versions.jsx
importReact,{useState}from'react';importIconfrom'../Icon.jsx';import{useStudio,resolveSelection,bumpVersion,log}from'../store.jsx';import{Badge,Button,ContextBar,Heading,Note,SourceDialog,WorkspaceRequired}from'../ui.jsx';exportdefaultfunctionVersions({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<WorkspaceRequirednavigate={navigate}/>;constselection=resolveSelection(s,baselineId,crIds);constchanged=baselineId!==w.baselineId||JSON.stringify([...crIds].sort())!==JSON.stringify([...w.crIds].sort());constincluded=newSet(selection.diff.map(d=>d.ruleId));return<><Headingeyebrow={`${w.ref} · KNOWLEDGE CONTEXT ${w.version}`}title="Select a knowledge version"description="Resolve the exact baseline and change revisions before using their evidence."><Buttonvariant="primary"icon="layers"disabled={!w.crIds.length||changed||!!selection.issues.length}onClick={()=>navigate('approvals?merge')}>Merge CRs into baseline</Button></Heading><ContextBarnavigate={navigate}/><divclassName="detail-grid margin-top"><sectionclassName="card padded"><h2>Selected Baseline</h2><selectclassName="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=><optionkey={b.id}value={b.id}>{b.ref} · Baseline Version {b.version}</option>)}</select><h2className="margin-top">Change requests</h2><pclassName="supporting-copy">A partial change replaces only its affected rule. Unchanged knowledge stays in the manifest.</p><divclassName="version-options">{s.crs.filter(c=>c.team===s.session.team).map(c=>{constincorporated=selection.baseline?.incorporatedCRs.includes(c.id);return<labelkey={c.id}><inputtype="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><Badgetone={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><sectionclassName="card padded"><h2>Resolved selection</h2><divclassName="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=><Notetone="amber"key={issue}>{issue}</Note>)}<pclassName="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><Buttonvariant="primary"className="full-width margin-top"disabled={!changed||selection.issues.length>0}onClick={()=>{mutate(d=>{constcurrent=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><sectionclassName="card margin-top"><divclassName="section-heading"><h2>Knowledge diff</h2><Badgetone="purple">Exact selected revisions</Badge></div>{selection.diff.map((change,i)=><divclassName="diff-block"key={`${change.crRef}-${i}`}><divclassName="diff-heading"><spanclassName={`operation operation-${change.op.toLowerCase()}`}>{change.op}</span><strong>{change.ruleId} · {change.title}</strong><span>{change.crRef}</span><buttonclassName="text-button"onClick={()=>setSource(change.source)}>Source <Iconname="external"size={12}/></button></div><divclassName="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=><divclassName="rule-row"key={r.id}><Badge>Unchanged</Badge><div><strong>{r.id} · {r.title}</strong><p>{r.text}</p></div></div>)}{!selection.diff.length&&<divclassName="padded"><Note>No CR changes selected. Retrieval uses the selected baseline manifest.</Note></div>}</section><sectionclassName="card padded margin-top"><h2>Shared contracts</h2><pclassName="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=><labelclassName="check-label"key={g.id}><inputtype="checkbox"checked={(w.sharedContractIds||[]).includes(g.sourceId)}onChange={e=>{constchecked=e.target.checked;mutate(d=>{constcurrent=d.workspaces.find(item=>item.id===w.id);current.sharedContractIds=checked?[...newSet([...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=>{constdoc=s.documents.find(d=>d.id===id),grant=s.shares.find(g=>g.sourceId===id&&g.consumer===w.team);return<divclassName="history-row"key={id}><Iconname="lock"size={18}/><span><strong>{doc?.name}</strong><small>Owner: {doc?.team} · Revision {doc?.revision} · Shared boundary only</small></span><Badgetone={grant?.status==='Active'?'green':'amber'}>{grant?.status||'Unavailable'}</Badge>{grant?.status!=="Active"&&<ButtononClick={()=>mutate(d=>{constcurrent=d.workspaces.find(item=>item.id===w.id);current.sharedContractIds=current.sharedContractIds.filter(item=>item!==id);bumpVersion(d,current);})}>Remove selection</Button>}</div>;}):<pclassName="supporting-copy">No shared contracts are selected for this workspace.</p>}</section>{source&&<SourceDialogsourceId={source}close={()=>setSource('')}/>}</>;}
Top comments (0)
Subscribe
We're a place where coders share, stay up-to-date and grow their careers.
Top comments (0)