Skip to content

Commit 353df7a

Browse files
authored
Improve modals in Sources page in Processor (#7664)
# Description of Changes Various changes throughout to try and convert the bulk of the dev UI sources modals to production quality. Changes include: - Fixing inconsistencies between different modals - Hide things users will rarely need to change behind advanced - Removed clutter in the UI - Renaming settings in terms that the user will understand and care about <img width="2360" height="3068" alt="image" src="https://github.com/user-attachments/assets/2c637e8f-bc1b-4c7e-98cb-d836ae626ba5" /> <img width="2360" height="3008" alt="image" src="https://github.com/user-attachments/assets/d894aadc-7c83-41d1-b614-881637a6bd34" />
1 parent 0d75715 commit 353df7a

25 files changed

Lines changed: 512 additions & 354 deletions

frontend/editor/public/locales/en-US/translation.toml

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8833,7 +8833,9 @@ title = "Sources"
88338833
connectSource = "Connect source"
88348834

88358835
[portal.sources.builder]
8836+
advanced = "Advanced"
88368837
back = "Back to sources"
8838+
backToSource = "Back to source setup"
88378839
backToTypes = "All source types"
88388840
cancel = "Cancel"
88398841
chooseHint = "Choose where documents come from. Greyed-out connectors are on the way."
@@ -8843,7 +8845,6 @@ create = "Create source"
88438845
createTitle = "Connect a source"
88448846
delete = "Delete"
88458847
editTitle = "Edit source"
8846-
enabled = "Enabled"
88478848
save = "Save changes"
88488849

88498850
[portal.sources.builder.folderAccess]
@@ -8863,23 +8864,24 @@ total = "Connections"
88638864
unused = "Unused"
88648865

88658866
[portal.sources.networkFields.connection]
8866-
helperText = "The stored connection with the server address and credentials. Reused by every source that references it."
8867+
helperText = "The saved connection with the server address and credentials. Shared by every source that uses it."
88678868
label = "Connection"
88688869

88698870
[portal.sources.networkFields.directory]
8870-
helperText = "Folder on the server to poll, relative to the login home or share root. Leave blank for the root."
8871+
helperText = "The folder on the server to watch, relative to the login home or share root."
88718872
label = "Folder"
8872-
placeholder = "incoming/"
8873+
placeholder = "Login home or share root"
88738874

88748875
[portal.sources.networkFields.mode]
8875-
helperText = "Consume removes each file from the server once every policy has processed it."
8876-
label = "Read mode"
8876+
helperText = "Whether to leave the original file in place after it has been processed. If the original file is left in place, it will be re-processed next time the pipeline scans the source."
8877+
label = "After processing"
88778878

88788879
[portal.sources.networkFields.mode.options]
8879-
consume = "Consume: process each file once"
8880-
snapshot = "Snapshot: re-read the folder every run"
8880+
consume = "Delete the file"
8881+
snapshot = "Leave it in place"
88818882

88828883
[portal.sources.networkFields.recursive]
8884+
helperText = "Include subfolders if your files are organised into nested folders, or watch only the top level."
88838885
label = "Folder depth"
88848886

88858887
[portal.sources.networkFields.recursive.options]
@@ -8920,26 +8922,28 @@ description = "Watch a directory on the server for new documents."
89208922
label = "Folder"
89218923

89228924
[portal.sources.types.folder.fields.directory]
8923-
helperText = "Absolute path Stirling watches for files to process."
8924-
label = "Directory path"
8925+
helperText = "The absolute path to the folder to watch for new files."
8926+
label = "Folder"
89258927
placeholder = "/data/incoming"
89268928

89278929
[portal.sources.types.folder.fields.identity]
8928-
helperText = "Content check reads each changed file, so renames and touches that don't alter content are not reprocessed."
8930+
helperText = "Using the file contents for change detection is slower but more accurate."
89298931
label = "Change detection"
89308932

89318933
[portal.sources.types.folder.fields.identity.options]
8932-
hash = "Size, date and content check"
8933-
stat = "Size and date modified"
8934+
hash = "File Metadata & Content"
8935+
stat = "File Metadata"
89348936

89358937
[portal.sources.types.folder.fields.mode]
8936-
label = "Read mode"
8938+
helperText = "Whether to leave the original file in place after it has been processed. If the original file is left in place, it will be re-processed next time the pipeline scans the source."
8939+
label = "After processing"
89378940

89388941
[portal.sources.types.folder.fields.mode.options]
8939-
consume = "Consume: process each file once"
8940-
snapshot = "Snapshot: re-read the folder every run"
8942+
consume = "Delete the file"
8943+
snapshot = "Leave it in place"
89418944

89428945
[portal.sources.types.folder.fields.recursive]
8946+
helperText = "Include subfolders if your files are organised into nested folders, or watch only the top level."
89438947
label = "Folder depth"
89448948

89458949
[portal.sources.types.folder.fields.recursive.options]
@@ -8967,21 +8971,21 @@ description = "Pull documents from an Amazon S3 or S3-compatible bucket."
89678971
label = "Amazon S3"
89688972

89698973
[portal.sources.types.s3.fields.connection]
8970-
helperText = "The stored connection holding the bucket and credentials. Reused by every source and pipeline output that references it."
8974+
helperText = "The saved connection with the bucket and credentials. Shared by every source and pipeline output that uses it."
89718975
label = "Connection"
89728976

89738977
[portal.sources.types.s3.fields.mode]
8974-
helperText = "Consume removes each object from the bucket once every policy has processed it."
8975-
label = "Read mode"
8978+
helperText = "Whether to leave the original object in place after it has been processed. If the original object is left in place, it will be re-processed next time the pipeline scans the source."
8979+
label = "After processing"
89768980

89778981
[portal.sources.types.s3.fields.mode.options]
8978-
consume = "Consume: process each object once"
8979-
snapshot = "Snapshot: re-read the bucket every run"
8982+
consume = "Delete the object"
8983+
snapshot = "Leave it in place"
89808984

89818985
[portal.sources.types.s3.fields.prefix]
8982-
helperText = "Only objects whose keys start with this prefix are processed."
8983-
label = "Key prefix"
8984-
placeholder = "incoming/"
8986+
helperText = "The folder (key prefix) within the bucket to watch."
8987+
label = "Folder"
8988+
placeholder = "Whole bucket"
89858989

89868990
[portal.sources.types.sftp]
89878991
description = "Poll an SFTP drop folder for new documents."

frontend/editor/src/core/theme/colors.css

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* COLORS — canonical semantic core (~21 --c-* tokens) mapped from primitives.css per theme; compat.css aliases legacy names onto these. Editor: always data-app-theme="custom" + data-mantine-color-scheme=light|dark. Portal/Storybook: data-theme=light|dark → LIGHT/MIDNIGHT. */
2-
/* Surface elevation: --c-bg (canvas) < --c-bg-raised (sidebars) < --c-surface (cards) < --c-surface-raised < --c-surface-sunken; plus --c-input-bg, --c-hover, --c-active, --c-overlay. */
2+
/* Surface elevation: --c-bg (canvas) < --c-bg-raised (sidebars) < --c-surface (cards) < --c-surface-raised < --c-surface-sunken; plus --c-modal-surface (modal panels), --c-input-bg, --c-hover, --c-active, --c-overlay. */
33

44
/* ── LIGHT ───────────────────────────────────────────────────────────────── */
55
:root,
@@ -11,6 +11,7 @@ html[data-app-theme="light"] {
1111
--c-surface-raised: var(--p-white);
1212
--c-surface-sunken: var(--p-gray-100);
1313
--c-input-bg: var(--p-white);
14+
--c-modal-surface: var(--p-white);
1415
--c-hover: var(--p-gray-50);
1516
--c-active: var(--p-gray-100);
1617
--c-overlay: rgba(0, 0, 0, 0.5);
@@ -22,7 +23,7 @@ html[data-app-theme="light"] {
2223

2324
--c-btn-solid: var(--c-text);
2425
--c-btn-inverse: var(--p-snow);
25-
--c-btn-secondary: var(--c-btn-inverse);
26+
--c-btn-secondary: var(--c-surface-raised);
2627
--c-btn-secondary-border: var(--c-border);
2728

2829
--c-border: var(--p-c-f0f0f0);
@@ -144,7 +145,8 @@ html[data-app-theme="midnight"] {
144145
--c-surface: var(--p-c-1a1a1d);
145146
--c-surface-raised: var(--p-zinc-650);
146147
--c-surface-sunken: var(--p-zinc-850);
147-
--c-input-bg: var(--p-zinc-650);
148+
--c-input-bg: var(--c-surface);
149+
--c-modal-surface: var(--c-surface);
148150
--c-hover: var(--p-gray-800);
149151
--c-active: var(--p-gray-800);
150152
--c-overlay: rgba(0, 0, 0, 0.6);
@@ -360,7 +362,7 @@ html[data-app-theme="custom"][data-mantine-color-scheme="dark"] {
360362
var(--c-primary) 8%,
361363
var(--p-zinc-900)
362364
);
363-
--c-input-bg: color-mix(in srgb, var(--c-primary) 7%, var(--p-zinc-900));
365+
--c-input-bg: var(--c-surface);
364366
--c-hover: color-mix(in srgb, var(--c-primary) 12%, var(--p-zinc-750));
365367
--c-active: color-mix(in srgb, var(--c-primary) 15%, var(--p-zinc-700));
366368
--c-border: color-mix(in srgb, var(--c-primary) 14%, var(--p-c-28282d));
@@ -424,7 +426,7 @@ html[data-app-theme="custom"][data-accent="default"][data-mantine-color-scheme="
424426
--c-surface: var(--p-c-1a1a1d);
425427
--c-surface-raised: var(--p-zinc-775);
426428
--c-surface-sunken: var(--p-zinc-900);
427-
--c-input-bg: var(--p-zinc-900);
429+
--c-input-bg: var(--c-surface);
428430
--c-hover: var(--p-zinc-750);
429431
--c-active: var(--p-zinc-700);
430432
--c-border: var(--p-c-28282d);
Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,41 @@
11
.sui-collapsible {
2+
display: flex;
3+
flex-direction: column;
24
overflow: hidden;
35
}
46

7+
/* A bare chevron-led toggle: no box, sized to its label, left-aligned. */
58
.sui-collapsible__head {
6-
display: flex;
9+
align-self: flex-start;
10+
display: inline-flex;
711
align-items: center;
8-
gap: 0.5rem;
9-
width: 100%;
10-
padding: 0.75rem 0.875rem;
11-
background: var(--c-surface);
12+
gap: 0.375rem;
13+
padding: 0;
1214
border: none;
15+
background: none;
1316
cursor: pointer;
14-
text-align: left;
15-
transition: background-color 0.15s ease;
17+
font: inherit;
18+
font-size: 0.8125rem;
19+
font-weight: 600;
20+
color: var(--c-text-muted);
1621
}
1722

1823
.sui-collapsible__head:hover {
19-
background: var(--c-hover);
20-
}
21-
22-
.sui-collapsible__head-main {
23-
display: flex;
24-
align-items: center;
25-
gap: 0.5rem;
26-
flex: 1;
27-
min-width: 0;
28-
flex-wrap: wrap;
29-
}
30-
31-
.sui-collapsible__head-end {
32-
display: inline-flex;
33-
align-items: center;
34-
gap: 0.625rem;
35-
margin-left: auto;
36-
flex-shrink: 0;
24+
color: var(--c-text);
3725
}
3826

27+
/* Points right when closed, rotates down when open. */
3928
.sui-collapsible__chevron {
4029
color: var(--c-text-subtle);
30+
transform: rotate(-90deg);
4131
transition: transform 0.2s ease;
4232
}
4333

4434
.sui-collapsible__chevron[data-open="true"] {
45-
transform: rotate(180deg);
35+
transform: rotate(0deg);
4636
}
4737

48-
/* Grid-rows disclosure: 0fr → 1fr, no magic max-height */
38+
/* Grid-rows disclosure: 0fr → 1fr, no magic max-height. */
4939
.sui-collapsible__body {
5040
display: grid;
5141
grid-template-rows: 0fr;
@@ -56,6 +46,8 @@
5646
grid-template-rows: 1fr;
5747
}
5848

49+
/* Gap between the toggle and the revealed content, no side indent. */
5950
.sui-collapsible__body-inner {
6051
overflow: hidden;
52+
padding-top: 0.875rem;
6153
}

frontend/editor/src/core/ui/Collapsible.stories.tsx

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,17 @@ export const Default: Story = {
1919
<Collapsible
2020
open={open}
2121
onToggle={() => setOpen((o) => !o)}
22-
header={<strong>Section title</strong>}
23-
aside={<span style={{ fontSize: "0.75rem" }}>3 items</span>}
22+
header="Advanced"
2423
>
25-
<div
26-
style={{
27-
padding: "0.875rem",
28-
borderTop: "1px solid var(--c-border)",
29-
}}
30-
>
31-
Body content revealed when the section is open.
32-
</div>
24+
Body content revealed when the section is open.
3325
</Collapsible>
3426
</div>
3527
);
3628
},
3729
};
3830

39-
// Stacked instances form an accordion; each section toggles independently.
40-
export const Accordion: Story = {
31+
// Several independent disclosures stacked in a form-like column.
32+
export const Stacked: Story = {
4133
render: () => {
4234
const [open, setOpen] = useState<number | null>(0);
4335
const sections = ["Trial", "Quote", "Agreement"];
@@ -47,24 +39,17 @@ export const Accordion: Story = {
4739
maxWidth: "40rem",
4840
display: "flex",
4941
flexDirection: "column",
50-
gap: "0.75rem",
42+
gap: "0.875rem",
5143
}}
5244
>
5345
{sections.map((label, i) => (
5446
<Collapsible
5547
key={label}
5648
open={open === i}
5749
onToggle={() => setOpen(open === i ? null : i)}
58-
header={<strong>{label}</strong>}
50+
header={label}
5951
>
60-
<div
61-
style={{
62-
padding: "0.875rem",
63-
borderTop: "1px solid var(--c-border)",
64-
}}
65-
>
66-
{label} details.
67-
</div>
52+
{label} details.
6853
</Collapsible>
6954
))}
7055
</div>

frontend/editor/src/core/ui/Collapsible.tsx

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,54 @@
11
import type { ReactNode } from "react";
2-
import "@app/ui/Surface.css";
32
import "@app/ui/Collapsible.css";
43

54
export interface CollapsibleProps {
65
/** Whether the section is expanded. Controlled — pair with `onToggle`. */
76
open: boolean;
87
onToggle: () => void;
9-
/** Header content (left/main side); the chevron is appended automatically. */
8+
/** The toggle's label, shown after the chevron. */
109
header: ReactNode;
11-
/** Right-aligned header content shown before the chevron (a count, a label). */
12-
aside?: ReactNode;
1310
children: ReactNode;
1411
className?: string;
1512
}
1613

1714
/**
18-
* A single bordered disclosure section: an always-visible header that toggles,
19-
* and a body that animates open/closed via a grid-rows transition (no magic
20-
* max-height). Stack several to build an accordion. Header content is fully
21-
* caller-supplied, so it suits both terse and rich (icon + chips + count) rows.
15+
* A lightweight inline disclosure: a chevron-led label that toggles, and a body
16+
* that animates open/closed via a grid-rows transition (no magic max-height).
17+
* No surface or box - it sits inline within a form or panel.
2218
*/
2319
export function Collapsible({
2420
open,
2521
onToggle,
2622
header,
27-
aside,
2823
children,
2924
className,
3025
}: CollapsibleProps) {
3126
return (
3227
<div
33-
className={["sui-surface", "sui-collapsible", className ?? ""]
34-
.filter(Boolean)
35-
.join(" ")}
28+
className={["sui-collapsible", className ?? ""].filter(Boolean).join(" ")}
3629
>
3730
<button
3831
type="button"
3932
className="sui-collapsible__head"
4033
onClick={onToggle}
4134
aria-expanded={open}
4235
>
43-
<span className="sui-collapsible__head-main">{header}</span>
44-
<span className="sui-collapsible__head-end">
45-
{aside}
46-
<svg
47-
className="sui-collapsible__chevron"
48-
data-open={open}
49-
viewBox="0 0 24 24"
50-
width={16}
51-
height={16}
52-
fill="none"
53-
stroke="currentColor"
54-
strokeWidth={2}
55-
strokeLinecap="round"
56-
strokeLinejoin="round"
57-
aria-hidden
58-
>
59-
<polyline points="6 9 12 15 18 9" />
60-
</svg>
61-
</span>
36+
<svg
37+
className="sui-collapsible__chevron"
38+
data-open={open}
39+
viewBox="0 0 24 24"
40+
width={16}
41+
height={16}
42+
fill="none"
43+
stroke="currentColor"
44+
strokeWidth={2}
45+
strokeLinecap="round"
46+
strokeLinejoin="round"
47+
aria-hidden
48+
>
49+
<polyline points="6 9 12 15 18 9" />
50+
</svg>
51+
{header}
6252
</button>
6353
<div className="sui-collapsible__body" data-open={open}>
6454
<div className="sui-collapsible__body-inner">{children}</div>

frontend/editor/src/core/ui/ColorInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { useInputAria } from "@app/ui/ariaForwarding";
1212
import "@app/ui/MantineForms.css";
1313

1414
const SUI_INPUT_VARS = {
15-
"--input-bg": "var(--c-surface)",
15+
"--input-bg": "var(--c-input-bg)",
1616
"--input-bd": "var(--c-border)",
1717
"--input-bd-focus": "var(--c-primary)",
1818
"--input-radius": "var(--radius-md)",

0 commit comments

Comments
 (0)