mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-07-27 22:45:03 +00:00
refactor(ara-projects): make the add-document composer read as a form (#412)
Labelled cells sitting directly under the table's own headings read as a second header row: two near-identical sets of words that never quite lined up, worst of all when the table was empty and they were the only two things on screen. The composer now announces itself — a thick divider, its own "Add a document" heading — and lays its controls out as a form rather than as twelfth-aligned columns: placeholders and aria-labels instead of column captions, fields free to size themselves, a text "Add" button. The empty table points at the heading by name. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
feff631582
commit
5c94a538ed
1 changed files with 95 additions and 111 deletions
|
|
@ -214,8 +214,9 @@ export function RequirementsTable({
|
|||
data-testid="evidence-empty"
|
||||
>
|
||||
No documents required yet. This workstream is still complete
|
||||
without any — add one below if the contractor should be asked
|
||||
for something.
|
||||
without any — use <strong className="font-semibold">Add a
|
||||
document</strong> below if the contractor should be asked for
|
||||
something.
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
|
|
@ -314,9 +315,18 @@ export function RequirementsTable({
|
|||
</table>
|
||||
</div>
|
||||
|
||||
{/*
|
||||
The composer is deliberately *not* a twelfth column-aligned row.
|
||||
Labelled cells sitting under the table's own headings read as a second
|
||||
header row — two near-identical sets of words, never quite in line,
|
||||
which is at its worst when the table is empty. So it announces itself
|
||||
with its own heading and lays its controls out as a form: the fields
|
||||
carry placeholders and `aria-label`s rather than column captions, and
|
||||
they are free to size themselves.
|
||||
*/}
|
||||
{canManage && (
|
||||
<form
|
||||
className="border-t border-gray-200 bg-gray-50/70 px-5 py-4"
|
||||
className="border-t-4 border-gray-100 bg-gray-50/70 px-5 py-4"
|
||||
data-testid="evidence-add-form"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
|
|
@ -327,125 +337,99 @@ export function RequirementsTable({
|
|||
add.mutate(draft);
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
Grid children default to `min-width: auto`, so a cell narrower than
|
||||
its contents spills over its neighbour rather than shrinking. Every
|
||||
cell below is `min-w-0` for that reason, and the required toggle
|
||||
gets two columns — a checkbox and the word "Required" do not fit in
|
||||
one twelfth of the row.
|
||||
*/}
|
||||
<div className="grid grid-cols-1 items-end gap-3 md:grid-cols-12">
|
||||
<label className="min-w-0 md:col-span-3">
|
||||
<span className="mb-1 block text-xs font-semibold uppercase tracking-wide text-gray-400">
|
||||
Document
|
||||
</span>
|
||||
<select
|
||||
className={selectClass}
|
||||
value={draft.fileType}
|
||||
disabled={busy}
|
||||
data-testid="evidence-add-file-type"
|
||||
onChange={(event) =>
|
||||
setDraft({ ...draft, fileType: event.target.value })
|
||||
}
|
||||
>
|
||||
<option value="">Choose a document…</option>
|
||||
{FILE_TYPE_GROUPS.map((group) => (
|
||||
<optgroup key={group.group} label={group.group}>
|
||||
{group.options.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<p className="mb-2.5 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-gray-500">
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
Add a document
|
||||
</p>
|
||||
|
||||
<label className="min-w-0 md:col-span-3">
|
||||
<span className="mb-1 block text-xs font-semibold uppercase tracking-wide text-gray-400">
|
||||
Stage <span className="normal-case text-gray-300">optional</span>
|
||||
</span>
|
||||
<select
|
||||
className={selectClass}
|
||||
value={draft.projectWorkstreamStageId}
|
||||
disabled={busy || !hasStages}
|
||||
data-testid="evidence-add-stage"
|
||||
onChange={(event) =>
|
||||
setDraft({
|
||||
...draft,
|
||||
projectWorkstreamStageId: event.target.value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<option value={NO_STAGE}>
|
||||
{hasStages ? "Whole workstream" : "No stages yet"}
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<select
|
||||
className={`${selectClass} min-w-[11rem] flex-[2]`}
|
||||
value={draft.fileType}
|
||||
disabled={busy}
|
||||
aria-label="Document"
|
||||
data-testid="evidence-add-file-type"
|
||||
onChange={(event) =>
|
||||
setDraft({ ...draft, fileType: event.target.value })
|
||||
}
|
||||
>
|
||||
<option value="">Choose a document…</option>
|
||||
{FILE_TYPE_GROUPS.map((group) => (
|
||||
<optgroup key={group.group} label={group.group}>
|
||||
{group.options.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<select
|
||||
className={`${selectClass} min-w-[10rem] flex-1`}
|
||||
value={draft.projectWorkstreamStageId}
|
||||
disabled={busy || !hasStages}
|
||||
aria-label="Stage"
|
||||
data-testid="evidence-add-stage"
|
||||
onChange={(event) =>
|
||||
setDraft({
|
||||
...draft,
|
||||
projectWorkstreamStageId: event.target.value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<option value={NO_STAGE}>
|
||||
{hasStages ? "No stage — whole workstream" : "No stages yet"}
|
||||
</option>
|
||||
{workstream.stages.map((stage) => (
|
||||
<option key={stage.id} value={stage.id}>
|
||||
{stage.name}
|
||||
</option>
|
||||
{workstream.stages.map((stage) => (
|
||||
<option key={stage.id} value={stage.id}>
|
||||
{stage.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<label className="min-w-0 md:col-span-3">
|
||||
<span className="mb-1 block text-xs font-semibold uppercase tracking-wide text-gray-400">
|
||||
Naming rule{" "}
|
||||
<span className="normal-case text-gray-300">optional</span>
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
className={`${inputClass} min-w-[10rem] flex-1`}
|
||||
value={draft.namingRule}
|
||||
disabled={busy}
|
||||
placeholder="Naming rule, e.g. [WORef]_Cert"
|
||||
aria-label="Naming rule"
|
||||
data-testid="evidence-add-naming-rule"
|
||||
onChange={(event) =>
|
||||
setDraft({ ...draft, namingRule: event.target.value })
|
||||
}
|
||||
/>
|
||||
|
||||
<label className="flex items-center gap-2 whitespace-nowrap text-xs text-gray-600">
|
||||
<input
|
||||
type="text"
|
||||
className={inputClass}
|
||||
value={draft.namingRule}
|
||||
type="checkbox"
|
||||
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
checked={draft.required}
|
||||
disabled={busy}
|
||||
placeholder="[AssetRef]_[WORef]_Cert"
|
||||
data-testid="evidence-add-naming-rule"
|
||||
data-testid="evidence-add-required"
|
||||
onChange={(event) =>
|
||||
setDraft({ ...draft, namingRule: event.target.value })
|
||||
setDraft({ ...draft, required: event.target.checked })
|
||||
}
|
||||
/>
|
||||
Required
|
||||
</label>
|
||||
|
||||
<label className="min-w-0 md:col-span-2">
|
||||
<span className="mb-1 block text-xs font-semibold uppercase tracking-wide text-gray-400 md:text-center">
|
||||
Required
|
||||
</span>
|
||||
<span className="flex h-9 items-center gap-2 md:justify-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
checked={draft.required}
|
||||
disabled={busy}
|
||||
data-testid="evidence-add-required"
|
||||
onChange={(event) =>
|
||||
setDraft({ ...draft, required: event.target.checked })
|
||||
}
|
||||
/>
|
||||
<span className="text-xs text-gray-500 md:hidden">
|
||||
Contractors must supply this
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div className="min-w-0 md:col-span-1">
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
disabled={busy}
|
||||
className="w-full"
|
||||
data-testid="evidence-add-submit"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
<span className="ml-1.5 md:sr-only md:ml-0">Add</span>
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
disabled={busy}
|
||||
data-testid="evidence-add-submit"
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
{!hasStages && (
|
||||
<p className="mt-2 text-xs text-gray-400">
|
||||
This workstream has no stages yet, so a requirement applies to the
|
||||
workstream as a whole. Tag it with a stage once the ladder exists.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<p className="mt-2 text-xs text-gray-400">
|
||||
{hasStages
|
||||
? "Leave the stage unset to expect the document at any point in the workstream."
|
||||
: "This workstream has no stages yet, so a requirement applies to the workstream as a whole. Tag it with a stage once the ladder exists."}
|
||||
</p>
|
||||
</form>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue