Skip to content
Open
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 `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; `algorithm-panel` is a shell over `algorithm-selection/` and `experiment-result/` sections that share panel-provided services), 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
1 change: 1 addition & 0 deletions docs/context/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- 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 split into section components keeps its DOM by attaching each section to the element it renders into (attribute selectors such as `section[app-algorithm-parameters]`). Each rule moves to the stylesheet of the template its element is declared in; a rule that reaches into a section from its host element is rewritten as `:host(.class)` (same specificity as `.class` under emulated encapsulation). Rules several sections share go into `styles/*.shared.css` partials, `@import`ed at the top of each stylesheet, so a rule only moves into a partial when it does not cross an equal-specificity rule for the same element (`algorithm-panel/` keeps its `.ng-touched` validation rules inline for that reason).
- Consult `DESIGN.md` before visual changes.
- Existing branding assets live under `src/assets`.

Expand Down
14 changes: 14 additions & 0 deletions docs/context/decision-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,17 @@ 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: Algorithm panel split into selection and result sections

Status: Accepted

Context: `algorithm-panel.component.ts` had grown to 1,703 lines with 28 `any`, loose mutable fields (`lastUsedAlgorithm`, the outlier_report rule maps, `formKey`, the built-form signature, the category-collapse bookkeeping) and one 22.1 kB stylesheet over the 20 kB component budget. Data Handling had been split the same way (PR 56).

Decision: `AlgorithmPanelComponent` (`app-algorithm-panel`) stays the studio's entry point with the same API (`canRun`, `runDisabledReason`, `onClickRunExp`, `setStudioSubstep`, `studioSubstepChange`, `onExportResult`, `onExportResultZip`) and provides four component-scoped services: `AlgorithmCatalogService` (search, Runnable/All, group collapse as a `linkedSignal`, availability text), `AlgorithmConfigFormService` (enriched schema, reactive form, cross-validation, positive_class, outlier_report rules as signals), `AlgorithmRunService` (run needs, `canRun`, the run, its error, PDF/ZIP export) and `AlgorithmStudioSubstepService`. Its template is a shell over `section[app-algorithm-selection]` (role assignment host, `aside[app-algorithm-catalog]`, details, `section[app-algorithm-parameters]` with `div[app-algorithm-config-field]`, `section[app-outlier-report-editor]`), the projected `div[app-experiment-result]` readiness bar with `ul[app-algorithm-run-requirements]`. Attribute selectors keep the DOM, the `data-guide` anchors, `#algo-search`, sessionStorage keys and request payloads unchanged; pure helpers live in `algorithm-panel/utils/` with specs and shared types in `algorithm-panel.models.ts`.

Consequences: Every stylesheet is under budget (the panel's is 3.3 kB). The outlier_report editor is still separate from Data Handling's outlier step; sharing one editor is a follow-up once PR 56 lands. The catalog's availability tooltip (`showTooltip` had no caller) was removed with its position helper and `formatInputCountRange`. `algorithm-result/` is shared with the Execution step and the dashboard and is unchanged.

Files affected: `src/app/pages/experiment-studio/algorithm-panel/**`, `docs/context/conventions.md`, `docs/context/module-index.md`, `docs/llm-wiki/03-feature-index.md`, `AGENTS.md`.

Date: 2026-10-29.
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/*`, `statistic-analysis-panel/*` (including `pca-column-source` / `kmeans-cluster-source`), `algorithm-panel/*` (thin shell; `algorithm-selection/` catalog, details, parameter form and outlier_report editor; `experiment-result/` run needs, readiness bar, run and exports; feature services `AlgorithmCatalogService`, `AlgorithmConfigFormService`, `AlgorithmRunService`, `AlgorithmStudioSubstepService` provided by the panel; `algorithm-result/` is shared and stays put), `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: 3 additions & 1 deletion docs/llm-wiki/03-feature-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ Start with:
- `ExperimentStudioComponent` (step shell) and `StudioStepperComponent` (step rail)
- `ExperimentStudioService` (selection, algorithm roles, run state)
- `execution-panel/` for run status/results and
`algorithm-panel/algorithm-role-assignment/` for the y/x slots
`algorithm-panel/algorithm-role-assignment/` for the y/x slots; the rest of
`algorithm-panel/` is a shell over `algorithm-selection/` (catalog, parameters)
and `experiment-result/` (run needs, readiness bar, run and exports)
- `shared/station-card`, `shared/station-action-bar`, `shared/station-list-row` for
the cards and footers every Data review step reuses
- relevant model under `src/app/models/`
Expand Down
4 changes: 0 additions & 4 deletions src/app/core/algorithm-input-counts.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
applyFallbackInputCounts,
formatInputCountRange,
readInputCount,
resolveInputMaxCount,
resolveInputMinCount,
Expand Down Expand Up @@ -29,8 +28,5 @@ describe('algorithm input counts', () => {

expect(resolveInputMaxCount(y, 'y', 'glmm_binary')).toBe(1);
expect(resolveInputMinCount(x, 'x', 'glmm_binary')).toBe(2);
expect(formatInputCountRange(1, 1)).toBe('exactly 1');
expect(formatInputCountRange(2, null)).toBe('2+');
expect(formatInputCountRange(2, 2)).toBe('exactly 2');
});
});
10 changes: 0 additions & 10 deletions src/app/core/algorithm-input-counts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,6 @@ export function resolveInputMaxCount(
}


export function formatInputCountRange(minCount: number, maxCount: number | null): string {
if (minCount === 1 && maxCount === 1) return 'exactly 1';
if (minCount === 0 && maxCount === 1) return '0-1';
if (minCount > 0 && maxCount !== null && minCount === maxCount) return `exactly ${minCount}`;
if (minCount > 0 && maxCount !== null) return `${minCount}-${maxCount}`;
if (minCount > 0) return `${minCount}+`;
if (maxCount !== null) return `0-${maxCount}`;
return 'optional';
}

export function applyFallbackInputCounts(inputdata: unknown, algorithmName: string): Record<string, unknown> {
if (!inputdata || typeof inputdata !== 'object') return {};
const next: Record<string, unknown> = { ...(inputdata as Record<string, unknown>) };
Expand Down
Loading
Loading