Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bfc0f69
refactor(data-handling): rename statistic-analysis-panel to DataHandl…
KFilippopolitis Oct 23, 2026
6d60d7e
refactor(data-handling): move shared types and pure helpers out of th…
KFilippopolitis Oct 23, 2026
42f7a7a
refactor(data-handling): extract the "How to use" strip into HowToStr…
KFilippopolitis Oct 23, 2026
63dedca
refactor(data-handling): extract the pipeline terminal into PipelineT…
KFilippopolitis Oct 23, 2026
6ac7665
refactor(data-handling): extract the summary workspace into SummaryWo…
KFilippopolitis Oct 23, 2026
701ed12
refactor(data-handling): type and extract the describe-summary pivot
KFilippopolitis Oct 23, 2026
2bf8e1d
refactor(data-handling): share the pending-change check between prepr…
KFilippopolitis Oct 23, 2026
32a7275
docs(data-handling): record the section-component split
KFilippopolitis Oct 23, 2026
c621b04
refactor(data-handling): share panel/table/search styles through CSS …
KFilippopolitis Oct 23, 2026
bf61766
refactor(data-handling): find category rule builders by rule, not by …
KFilippopolitis Oct 23, 2026
ba82906
refactor(data-handling): register goToSection scroll targets instead …
KFilippopolitis Oct 23, 2026
4d55294
refactor(data-handling): extract the Raw data step into SourceDataSta…
KFilippopolitis Oct 23, 2026
b7ab0c2
refactor(data-handling): extract cohort filtering into CohortFilterSt…
KFilippopolitis Oct 23, 2026
100a5b3
refactor(data-handling): extract preprocessing into PreprocessingStat…
KFilippopolitis Oct 23, 2026
3fea030
refactor(data-handling): one PrepVariableRailComponent for the three …
KFilippopolitis Oct 23, 2026
8af5a27
refactor(data-handling): split the preprocessing sub-steps into their…
KFilippopolitis Oct 23, 2026
4d87336
refactor(data-handling): extract transformations into TransformationS…
KFilippopolitis Oct 23, 2026
d4d409c
refactor(data-handling): TransformationDraftsService owns the nominal…
KFilippopolitis Oct 23, 2026
d331df8
refactor(data-handling): PreprocessingStateService owns the preproces…
KFilippopolitis Oct 23, 2026
0868906
refactor(data-handling): StatisticSummaryService owns the summary sur…
KFilippopolitis Oct 23, 2026
fa3df7b
docs: Data Handling split - stations, sub-steps, feature services and…
KFilippopolitis Oct 23, 2026
b5eaba2
Merge origin/master into refactor/data-handling-split
KFilippopolitis Oct 30, 2026
9ebc752
refactor(data-handling): drop dead members and never-matching documen…
KFilippopolitis Oct 30, 2026
b7629df
refactor(data-handling): move category counts into TransformationStat…
KFilippopolitis Oct 30, 2026
d0d0a27
refactor(data-handling): move histogram preview parsing into a tested…
KFilippopolitis Oct 30, 2026
d425a39
refactor(data-handling): move the outlier strip's bounds math into a …
KFilippopolitis Oct 30, 2026
f8162da
refactor(data-handling): move summary coverage reads into a tested util
claude Oct 30, 2026
018b492
refactor(data-handling): move the histogram request/cache loop into S…
claude Oct 30, 2026
61728ef
refactor(data-handling): move the summary PDF/CSV export into Summary…
claude Oct 30, 2026
cd794d5
refactor(data-handling): move scroll requests into SectionAnchors and…
claude Oct 30, 2026
c58e3f6
test(data-handling): build the export spec's chart containers without…
claude Oct 30, 2026
f7d842f
docs(decision-log): say which extractions the screenshot harness covered
claude Oct 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This repository contains `fl-platform`, the Angular 22 standalone frontend for t
- `src/app/services/`: auth/session, experiment orchestration, dashboard data access, algorithm rules, labeling, runtime env, theme, errors, and PDF/CSV exports.
- `src/app/models/`: frontend and backend DTOs/interfaces for users, algorithms, experiments, filters, and data models.
- `src/app/core/`: algorithm mapping, result enum mapping, constants, and result utility logic.
- `src/app/pages/experiment-studio/`: step views switched via a sticky horizontal stepper — `experiment-studio.component` shows one step view at a time (Datasets & Variables · Data review & preprocessing · Algorithm); all views stay mounted (hidden via CSS) so state is preserved. On the Data review step the stepper expands a sub-step row (Filtering, Raw Summary, Preprocessing, Processed Summary, Transformation) that drives the `statistic-analysis-panel` sections (`goToSection`). In-panel section targets use `scroll-margin-top` so `scrollIntoView` clears sticky chrome. Also contains variable/filter selection, QueryBuilder filter UI, algorithm configuration with variable role assignment (outcome y / covariates x on the algorithm panel), run/edit flows, statistics, visualizations, and result rendering.
- `src/app/pages/experiment-studio/`: step views switched via a sticky horizontal stepper — `experiment-studio.component` shows one step view at a time (Datasets & Variables · Data review & preprocessing · Algorithm); all views stay mounted (hidden via CSS) so state is preserved. On the Data review step the stepper expands a sub-step row (Filtering, Raw Summary, Preprocessing, Processed Summary, Transformation) that drives the `data-handling` (`DataHandlingComponent`) sections (`goToSection`). In-panel section targets use `scroll-margin-top` so `scrollIntoView` clears sticky chrome. Also contains variable/filter selection, QueryBuilder filter UI, algorithm configuration with variable role assignment (outcome y / covariates x on the algorithm panel), run/edit flows, statistics, visualizations, and result rendering.
- `src/app/pages/experiments-dashboard/`: experiment list/search/pagination, detail view, compare mode, sharing, delete/edit/name updates, and result export.
- `src/app/pages/terms-page/`: NDA/TOS display and acceptance flow.
- `src/app/pages/account-page/`: account/profile view and logout entry.
Expand Down
2 changes: 1 addition & 1 deletion docs/context/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
### UI and Styling
- Use component CSS for feature-specific styles.
- Use `src/styles.css` for app-wide styles and QueryBuilder theming.
- A component may list several stylesheets in `styleUrls`; Angular concatenates them **in array order**, so that order is the cascade. Splitting a file must preserve the original order and must not move a rule across another rule that shares its selector — `statistic-analysis-panel` is split this way (`.component.css` shell + pipeline canvas, then `.preprocessing.css`, then `.results.css`).
- A component may list several stylesheets in `styleUrls`; Angular concatenates them **in array order**, so that order is the cascade. Splitting a file must preserve the original order and must not move a rule across another rule that shares its selector — `data-handling` (`DataHandlingComponent`) is split this way (`.component.css` shell + pipeline canvas, then `.preprocessing.css`, then `.results.css`). Its section components attach to the element they replace (attribute selectors such as `div[app-pipeline-terminal]`) and `@import` the shared partials in `data-handling/styles/*.shared.css` at the top of their stylesheet (an `@import` must come first, so a rule only moves into a partial after checking it does not cross an equal-specificity rule for the same element); see the decision log entry on Data Handling sections.
- Consult `DESIGN.md` before visual changes.
- Existing branding assets live under `src/assets`.

Expand Down
23 changes: 23 additions & 0 deletions docs/context/decision-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,26 @@ Consequences: Breaking: this UI needs a backend with PR #34 and does not work ag
Files affected: `src/app/services/experiment-studio.service.ts`, `src/app/services/experiment-studio.service.spec.ts`, `e2e/experiment-studio-api.ts`, `e2e/experiment-studio.flows.spec.ts`, `README.md`, `docs/context/*.md`, `docs/llm-wiki/indexes/backend-endpoints.md`.

Date: 2026-10-15.

### Decision: Data Handling sections are attribute-hosted components over the pipeline's state

Status: Accepted

Context: `statistic-analysis-panel` grew to one ~4.5k-line component with a ~1.8k-line template. It was renamed `data-handling` (`DataHandlingComponent`, `app-data-handling`) and is being split into section components. Behaviour, visuals, `data-guide` anchors, e2e selectors, payloads and sessionStorage keys must not change, and the studio's global reveal rule (`.experiment-studio-page .workflow-section-body.open > *`) animates the direct children of a section body.

Decision:
- A section component attaches to the element it replaces (`section[app-cohort-filter-station]`, `section[app-missing-values-step]`, `aside[app-prep-variable-rail]`, `div.transformation-create[app-categorical-column-card]`, `div.workflow-section-body[app-summary-workspace]`, ...) instead of adding a wrapper, so the DOM, the reveal animation and every selector stay as they were. `display: contents` wrappers were tried and rejected: they break the reveal animation. The host keeps the parent's `_ngcontent` attribute, so host-state rules are written `:host(.x) ...` in the child and ancestor rules `:host-context(.x) ...`.
- Each pipeline step is a station component (`source-data-station`, `cohort-filter-station`, `preprocessing-station`, `transformation-station`); the preprocessing station splits further into one component per sub-step plus one shared variable rail (`prep-variable-rail`, whose per-step row markup is given as `<ng-template prepRailSlot="lead|trail|action">`), and each nominal transformation card's editor is `categorical-column-card`.
- Pipeline state and orchestration (requests, apply, persistence) stay on `DataHandlingComponent`, whose public API (`goToSection`, `progressStateChange`) and fields the studio and specs use. State that forms a feature lives in component-scoped services provided by the panel: `StatisticSummaryService` (the three summary surfaces, their cache keys, describe-response assembly), `PreprocessingStateService` (pending/applied rules of the three sub-steps and their comparisons), `TransformationDraftsService` (the nominal-column drafts, their status and payload), `SummaryExportService` (a surface's PDF report and CSV; the panel's template keeps the off-screen chart containers the PDF reads) and `SummaryHistogramService` (the Histogram tab's per-variable, per-split requests and cache; it reads the panel's blocks, pending preprocessing and Cohort Filtering preview through `ports`, and a settled request, with data or an error, is not repeated until its surface is rebuilt). The panel keeps its member names as getter/setter facades onto them, so templates and the studio are unchanged.
- Narrow sections take `input()`/`output()` (how-to strip, terminal, rail, card). Sections that read much of the pipeline inject `DATA_HANDLING` (`data-handling.context.ts`, provided by the panel with `useExisting`) and use `ChangeDetectionStrategy.Eager`, so they refresh exactly when the inline template did.
- `@ViewChild`/`@ViewChildren` lookups into extracted markup were replaced by registries the panel provides: `SectionAnchors` + `[dhSectionAnchor]` for scroll targets (it also runs the scroll request: `requestScroll` waits for the render that follows an open/close, and a newer request replaces one that has not run), `RuleBuilderRegistry` + `app-filter-config-modal[ruleBuilderFor]` for each category's rule builder (keyed by the rule object, not by position).
- Styles move with the elements that only a section renders. Rules several components render are `@import`ed partials in `data-handling/styles/` (`pipeline-node`, `statistics-panel`, `search-and-empty-states`, `tables`, `preprocessing-step`, `transformation-rules`), imported at the top of each user's sheet; keyframes travel with the rules that use them because emulated encapsulation scopes them per stylesheet. The panel's icon nudge (`.stats-panel-shell i`) is repeated as `:host-context(.stats-panel-shell) i`.
- Pure logic moves to `data-handling/utils/*` with specs (formatting, summary pivot and view helpers, preprocessing state, documentation HTML, transformation drafts, histogram preview parsing, outlier bounds, summary coverage/distribution/category reads over a pivot block, the section layout `goToSection` applies, export helpers); shared types live in `data-handling.models.ts`.

Consequences: Each extraction up to the master merge was checked against master with a local DOM + computed-style + screenshot comparison of the pipeline in eight scenarios. The later shell-slimming commits (coverage reads, histogram loop, export, section layout and scroll request) are covered by their own specs, the panel's existing specs and the CI Playwright run, but were not rerun through that harness. Every component stylesheet is under the 20 kB budget. The panel is still the orchestrator (~3.2k lines of TS, from ~4.1k): the three describe requests, apply/persist and hydrating the stored preprocessing, the editors' validation and request-config builders, the pipeline-terminal and rail sub-node views, and the stage add/remove side effects remain there. The histogram loop, the exports, the coverage reads and the section layout/scroll request moved out. What is left needs a redesign rather than ports: the describe requests and apply/persist share the `*DescribeSeq` supersession counters, the preprocessing rule maps and `emitProgressState`, so extracting them means moving the pending/applied rule state's writers together (`PreprocessingStateService` owns the maps, but about a dozen panel methods, 43 assignment sites, still write them directly).

After merging master (ordered transformation steps, PCA columns): the transformation station renders one card per store step (`app-categorical-column-card`, `app-kmeans-cluster-source`, `app-pca-column-source`), and `TransformationDraftsService` owns what master kept on the panel: the nominal drafts keyed by store step id, card open state, titles and chips per creator, name clashes (`columnNameError`, `writeProblem`), removal rules and the chooser (`choose`). The panel keeps the side effects (store writes, change detection). `TransformationStatisticsService` owns the category counts (placeholder shapes, the single describe over all derived columns, K-means column views, invalidation); the panel hands it its pending preprocessing and labels through `ports`, and the stage's views read its signals.

Files affected: `src/app/pages/experiment-studio/data-handling/**`, `src/app/pages/experiment-studio/experiment-studio.component.*`, `AGENTS.md`, `docs/context/module-index.md`, `docs/context/conventions.md`, `docs/context/risk-register.md`, `docs/context/decision-log.md`.

Date: 2026-10-23.
2 changes: 1 addition & 1 deletion docs/context/module-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Notes: Stored historical experiment payloads may depend on legacy algorithm keys

## `src/app/pages/experiment-studio`
Purpose: Experiment composition workflow.
Key files: `experiment-studio.component.*`, `variables-panel/*`, `statistic-analysis-panel/*` (including `pca-column-source` / `kmeans-cluster-source`), `algorithm-panel/*`, `execution-panel/*` (result view + docked setup summary), `stepper/*`, `shared/*`, `guide/*`.
Key files: `experiment-studio.component.*`, `variables-panel/*`, `data-handling/*` (panel shell + one component per pipeline step: `source-data-station/`, `cohort-filter-station/`, `preprocessing-station/` (with `prep-variable-rail/`, `missing-values-step/`, `outlier-step/`, `longitudinal-step/`, `preprocessing-state.service.ts`), `transformation-station/` (with `categorical-column-card/`, `kmeans-cluster-source/`, `pca-column-source/`, `transformation-drafts.service.ts`, `transformation-statistics.service.ts`); shared `summary-workspace/`, `pipeline-terminal/`, `how-to-strip/`; `statistic-summary.service.ts`, `summary-histogram.service.ts`, `summary-export.service.ts`; seams `data-handling.context.ts`, `section-anchors.ts`, `transformation/rule-builder-registry.ts`; shared CSS partials in `styles/`; `data-handling.models.ts`; pure `utils/`), `algorithm-panel/*`, `execution-panel/*` (result view + docked setup summary), `stepper/*`, `shared/*`, `guide/*`.
Used by: `/experiment-studio` route and dashboard edit flows.
Rules: Keep page-specific UI here; use `ExperimentStudioService` for shared selection/run state. Transformation cards append to `appliedTransformations` in creation order; each creator step names outputs with `new_column_names`. Do not reintroduce `pca_with_transformation`.
Tests: Component specs live near components; e2e covers PCA then K-means then logistic regression payload order in `e2e/experiment-studio.flows.spec.ts`.
Expand Down
4 changes: 2 additions & 2 deletions docs/context/risk-register.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
| Docker image publishing | Release workflow uses registry credentials and pushes images. | `.github/workflows/publish_images.yml`. | Never print secrets; review registry/tag changes carefully. | Yes |
| EBRAINS mirroring | Workflow pushes code/tags to an external GitLab mirror. | `.github/workflows/ebrains.yml`. | Avoid changing mirror refs or credentials handling without owner review. | Yes |
| Dependencies | Updates can affect Angular build, bundle output, and chart/export libraries. | `package.json`, `package-lock.json`. | Explain need, review lockfile, run build/tests. | Yes |
| Cohort / category-rule filters (edit mode) | Stored filter trees can be re-sent in a shape the engine rejects, or silently rewritten, so an experiment that runs from the API fails from Studio. | `core/filter-logic.utils.ts`, `filter-config-modal.component.ts` (`backendToGroup`/`normalizeCondition`), `statistic-analysis-panel.component.ts` (`commitTransformationRuleFilters`). | Treat backend filter trees as untrusted input: hydrate every shape, never default an unknown operator to `equal`, never overwrite a loaded rule with an empty builder. Verify edit-mode runs against an experiment whose filters use `in`/`is_not_null`. | Yes |
| Derived-column stage (ungated) | Preview and Apply run on whatever the cards can express, so an unfinished card contributes nothing to the describe and to the payload, and a duplicate column name persists its first occurrence only. | `statistic-analysis-panel.component.ts` (`commitTransformationRuleFilters`, `buildTransformationConfigForDraft`, `transformationDraftStatus`). | Do not reintroduce a Preview/Apply gate over loaded data: it strands experiments whose category rules were authored outside this UI. Keep the commit's rule-safety check — never overwrite a rule its builder could not read — and let that rule's own note (`.transformation-saved-filter-note`, driven by `unloadedInput()`) plus the `Pending`/`Duplicate name` chips stay the only warning. `transformationCanApply` may dim Apply while no card forms a config, which must stay a statement about an empty payload and never a verdict on loaded rules; and Apply must keep the stage open while `transformationHasPendingChange` is true, or the chip that reports unfinished work folds away with it. Manual QA must cover Apply with a duplicate column name, and Apply on an experiment whose stored category rules this UI cannot author. | Yes |
| Cohort / category-rule filters (edit mode) | Stored filter trees can be re-sent in a shape the engine rejects, or silently rewritten, so an experiment that runs from the API fails from Studio. | `core/filter-logic.utils.ts`, `filter-config-modal.component.ts` (`backendToGroup`/`normalizeCondition`), `data-handling.component.ts` (`commitTransformationRuleFilters`). | Treat backend filter trees as untrusted input: hydrate every shape, never default an unknown operator to `equal`, never overwrite a loaded rule with an empty builder. Verify edit-mode runs against an experiment whose filters use `in`/`is_not_null`. | Yes |
| Derived-column stage (ungated) | Preview and Apply run on whatever the cards can express, so an unfinished card contributes nothing to the describe and to the payload, and a duplicate column name persists its first occurrence only. | `data-handling.component.ts` (`commitTransformationRuleFilters`), `transformation-station/transformation-drafts.service.ts` (`status`, `writeProblem`), `utils/transformation-draft.utils.ts` (`transformationConfigFor`). | Do not reintroduce a Preview/Apply gate over loaded data: it strands experiments whose category rules were authored outside this UI. Keep the commit's rule-safety check — never overwrite a rule its builder could not read — and let that rule's own note (`.transformation-saved-filter-note`, driven by `unloadedInput()`) plus the `Pending`/`Duplicate name` chips stay the only warning. `transformationCanApply` may dim Apply while no card forms a config, which must stay a statement about an empty payload and never a verdict on loaded rules; and Apply must keep the stage open while `transformationHasPendingChange` is true, or the chip that reports unfinished work folds away with it. Manual QA must cover Apply with a duplicate column name, and Apply on an experiment whose stored category rules this UI cannot author. | Yes |
| Ordered transformations / PCA columns | Reordering or keying creators by name can break "later step may only read earlier outputs"; sending `code` or `pca_with_transformation` fails at Exaflow. | `ExperimentStudioService.appliedTransformations`, `pca_column_creator` / `kmeans_cluster_creator` / `categorical_column_creator`, e2e PCA→K-means→logistic flow. | Keep creators in the ordered list with `new_column_names`; emit after singletons; never revive `pca_with_transformation`. Manual QA: two PCA cards, K-means on PCA outputs, logistic on outputs, edit/rerun. | Yes |
| Dashboard history cap | A filter the backend cannot express is answered from one ownership-scoped snapshot of the history, capped at `fullHistoryCap` runs; a search past it silently misses older runs. | `experiments-dashboard.service.ts` (`loadAllExperiments`, `historyTruncated`). | The cap is stated in the list summary now, not hidden; removing the signal without a backend substring/date filter brings the silent miss back. | Yes |
| Design and branding | UI changes can violate MIP brand guidelines. | `DESIGN.md`, logos/assets. | Follow approved colors, logo rules, and UI hierarchy. | For visible brand changes |
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@import '../styles/pipeline-node.shared.css';

/* The panel nudges every icon 1px down (`.stats-panel-shell i`); the rule is
scoped to the panel's own template, so it is repeated here for this one. */
:host-context(.stats-panel-shell) i {
transform: translateY(1px);
}

/* The panel's `.pipeline-node .workflow-section-body`, for this step's bodies. */
:host(.pipeline-node) .workflow-section-body {
padding-inline: 16px;
}

/* Live match chip under the cohort builder, filled by Preview. */
.filter-match-row {
display: flex;
justify-content: flex-end;
padding: 14px 14px 10px;
}

.filter-match-chip {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 4px 12px;
border-radius: 999px;
font-size: 0.78rem;
font-weight: 600;
color: #065f46;
background: color-mix(in srgb, var(--success) 12%, white);
}
Loading
Loading