DEV Community

Rahul
Rahul

Posted on

Testcraft Studio frontend 24: src/pages/Baselines.jsx

import React, { useState } from 'react';
import Icon from '../Icon.jsx';
import { categories } from '../seed.js';
import { requestBaseline } from '../baseline.js';
import { useStudio, log } from '../store.jsx';
import { Badge, Button, Empty, Field, Heading, Modal, Note, Search, SourceDialog, Tabs, UploadBox } from '../ui.jsx';

export function CreateBaseline({ close, onCreated, baseline = null, workspaceId = '' }) {
  const { state: s, mutate, notify } = useStudio();
  const [name, setName] = useState(baseline?.ref || ''), [description, setDescription] = useState(baseline?.description || ''), [scope, setScope] = useState(baseline?.scope || '');
  const [documents, setDocuments] = useState(() => baseline ? s.documents.filter(doc => baseline.sourceIds.includes(doc.id)) : []);
  const [category, setCategory] = useState(0), [error, setError] = useState('');
  function save(event) {
    event.preventDefault();
    try {
      const prepared = structuredClone(s), request = requestBaseline(prepared, { ref: name, description, scope }, documents, workspaceId, baseline?.id);
      const record = prepared.baselines.find(item => item.id === request.baselineId);
      mutate(d => { d.baselines.push(record); d.candidates.unshift(request); documents.forEach(doc => { if (!d.documents.some(item => item.id === doc.id)) d.documents.push({ ...doc, status: 'Ready' }); }); const workspace = d.workspaces.find(item => item.id === request.workspaceId); if (workspace) workspace.pendingBaselineId = record.id; log(d, `Submitted baseline ${request.type}: ${record.ref}`); });
      onCreated?.(record.id); close(); notify('Submitted for Administrator approval.');
    }
    catch (failure) { setError(failure.message); }
  }
  return <Modal title={baseline ? 'Edit System Baseline' : 'Create a System Baseline'} close={close} wide><p className="modal-intro">{baseline ? 'Add or remove documents. Your approved version stays available until this edit is approved.' : 'Build the foundation for your workspace with at least one document.'}</p><form onSubmit={save}>
    <div className="form-grid"><Field label="System Baseline name"><input required maxLength={60} readOnly={!!baseline} placeholder="e.g. Membership and collateral" value={name} onChange={e => setName(e.target.value)}/></Field><Field label="Owning team"><input value={s.session.team} readOnly/></Field></div><Field label="Description"><textarea rows={2} value={description} onChange={e => setDescription(e.target.value)} maxLength={600} placeholder="Describe the system knowledge."/></Field><Field label="Application / process scope (optional)"><input value={scope} onChange={e => setScope(e.target.value)} maxLength={100} placeholder="e.g. Membership and collateral"/></Field>
    <div className="category-tabs document-category-picker" role="tablist" aria-label="Baseline document categories">{categories.map((label, index) => <button type="button" role="tab" aria-selected={category === index} className={category === index ? 'active' : ''} key={label} onClick={() => setCategory(index)}>{label}<span>{documents.filter(doc => doc.category === index).length}</span></button>)}</div><UploadBox scope={{ team: s.session.team, category }} onStaged={files => setDocuments(items => [...items, ...files])}/><div className="baseline-staged-files">{documents.map(doc => <div className="selected-file" key={doc.id}><Icon name="file" size={16}/><span>{doc.name}<small>{categories[doc.category]}</small></span><button type="button" className="icon-button" aria-label={`Remove ${doc.name}`} onClick={() => setDocuments(files => files.filter(file => file.id !== doc.id))}><Icon name="close" size={14}/></button></div>)}</div><Note>Any one Business, Technical, or Functional / Bug Information document is sufficient. Baseline creation and edits require Administrator approval.</Note>{error && <p className="form-error" role="alert">{error}</p>}<div className="modal-actions"><Button onClick={close}>Cancel</Button><Button type="submit" variant="primary" disabled={!documents.length || !name.trim()}>Submit for approval</Button></div>
  </form></Modal>;
}

export default function Baselines({ navigate, create = false }) {
  const { state: s, workspace: w } = useStudio();
  const [query, setQuery] = useState(''), [selected, setSelected] = useState(''), [editor, setEditor] = useState(create ? 'create' : ''), [source, setSource] = useState(''), [tab, setTab] = useState('Documents'), [category, setCategory] = useState(0);
  const list = s.baselines.filter(b => b.team === s.session.team && `${b.ref} ${b.description}`.toLowerCase().includes(query.toLowerCase()));
  const baseline = s.baselines.find(b => b.id === selected && b.team === s.session.team), docs = baseline ? s.documents.filter(doc => baseline.sourceIds.includes(doc.id)) : [];
  const pendingEdit = baseline && s.candidates.some(c => c.parentId === baseline.id && c.status === 'Pending review');
  return <><Heading eyebrow={`${s.session.team} · SYSTEM KNOWLEDGE`} title={baseline?.ref || 'System Baselines'} description={baseline?.description || 'Approved knowledge for your testing workspaces.'}>{baseline ? <div className="row-actions"><Button onClick={() => setSelected('')}>All baselines</Button>{['Active', 'Approved'].includes(baseline.status) && <Button variant="primary" icon="edit" disabled={pendingEdit} onClick={() => setEditor('edit')}>{pendingEdit ? 'Edit awaiting approval' : 'Edit baseline'}</Button>}</div> : <Button icon="plus" variant="primary" onClick={() => setEditor('create')}>Create System Baseline</Button>}</Heading>
    {!baseline ? <><div className="library-toolbar"><Search value={query} onChange={setQuery} placeholder="Search System Baselines…"/><span className="subtle">Versioned system knowledge</span></div><div className="library-grid">{list.map(b => <button className="card library-card" onClick={() => { setSelected(b.id); setTab('Documents'); }} key={b.id}><div className="library-card-top"><span className="soft-icon soft-purple"><Icon name="layers" size={21}/></span><Badge tone={['Active', 'Approved'].includes(b.status) ? 'green' : 'amber'}>{b.status}</Badge></div><h3>{b.ref}</h3><p>{b.description || 'System knowledge for your workspace.'}</p><div className="library-meta"><span>Version {b.version}</span><span>{b.sourceIds.length} documents</span></div><div className="library-footer"><span>{b.scope || 'System knowledge'}</span><Icon name="arrow" size={16}/></div></button>)}</div>{!list.length && <section className="card"><Empty title="Your system knowledge starts here" description="Create your workspace, then add a System Baseline with any one document." action={<Button onClick={() => setEditor('create')}>Create System Baseline</Button>}/></section>}</>
      : <><div className="detail-summary"><Badge tone={['Active', 'Approved'].includes(baseline.status) ? 'green' : 'amber'}>{baseline.status}</Badge><span>Owning team: <strong>{baseline.team}</strong></span><span>Version: <strong>{baseline.version}</strong></span><span>Scope: <strong>{baseline.scope || 'General'}</strong></span></div><Tabs value={tab} onChange={setTab} items={['Documents', 'Knowledge rules', 'Version history']}/>
      {tab === 'Documents' ? <div className="detail-grid"><section className="card padded"><div className="section-heading inset"><h2>System Baseline documents</h2><span className="count-pill">{docs.length}</span></div><div className="category-tabs document-category-picker" role="tablist" aria-label="System Baseline categories">{categories.map((label, index) => <button role="tab" aria-selected={category === index} className={category === index ? 'active' : ''} key={label} onClick={() => setCategory(index)}>{label}<span>{docs.filter(doc => doc.category === index).length}</span></button>)}</div>{docs.filter(doc => doc.category === category).map(doc => <div className="review-source" key={doc.id}><button className="source-link" onClick={() => setSource(doc.id)}><Icon name="file" size={19}/><span><strong>{doc.name}</strong><small>{doc.kind} · {doc.size} · Revision {doc.revision}</small></span></button><Badge>{doc.status}</Badge></div>)}{!docs.some(doc => doc.category === category) && <Empty title="No document in this category" description="One document in any category is sufficient."/>}</section><section className="card padded"><h2>Baseline lifecycle</h2><div className="lifecycle-steps"><span><Icon name="upload" size={18}/>Submit documents</span><span><Icon name="shield" size={18}/>Administrator approval</span><span><Icon name="check" size={18}/>Use approved knowledge</span></div><p className="supporting-copy">Creation and document edits follow the same approval flow. Approved versions remain available for existing workspaces.</p><Button className="full-width margin-top" onClick={() => navigate('approvals')}>View baseline approvals</Button>{['Active', 'Approved'].includes(baseline.status) && <Button className="full-width margin-top" onClick={() => navigate('workspace')}>Open workspace</Button>}</section></div>
        : tab === 'Knowledge rules' ? <section className="card"><div className="section-heading"><h2>Knowledge manifest</h2></div>{baseline.rules.map(rule => <div className="rule-row" key={rule.id}><span className="code-label">{rule.id}</span><div><strong>{rule.title}</strong><p>{rule.text}</p></div><button className="text-button" onClick={() => setSource(rule.source)}>Source <Icon name="external" size={12}/></button></div>)}{!baseline.rules.length && <Empty title="Documents are ready for your requirements" description="Record source-linked requirements in the workspace before generating test cases."/>}</section>
        : <section className="card"><div className="section-heading"><h2>System Baseline version history</h2></div>{s.baselines.filter(b => b.team === baseline.team && (b.ref === baseline.ref || b.id === baseline.parentId)).map(b => <button className="history-row" key={b.id} onClick={() => setSelected(b.id)}><span className="soft-icon soft-purple"><Icon name="layers" size={17}/></span><span><strong>{b.ref} · v{b.version}</strong><small>{new Date(b.createdAt).toLocaleDateString('en-IN')}</small></span><Badge>{b.status}</Badge><Icon name="chevron" size={15}/></button>)}</section>}
    </>}{editor && <CreateBaseline baseline={editor === 'edit' ? baseline : null} workspaceId={w?.id || ''} onCreated={setSelected} close={() => { setEditor(''); if (create) navigate('baselines'); }}/>} {source && <SourceDialog sourceId={source} close={() => setSource('')}/>}</>;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)