Skip to content

Commit 2ee8e88

Browse files
committed
Restore experiment object model, fix status filters
Signed-off-by: Nana Nosirova <10577112+nananosirova@users.noreply.github.com>
1 parent fd51c80 commit 2ee8e88

31 files changed

Lines changed: 237 additions & 369 deletions

frontend/src/api/pipelines/custom.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -248,33 +248,21 @@ export const listPipelineArchivedRuns: ListPipelinesRunAPI = (hostPath) => (opts
248248
};
249249

250250
export const listPipelineRecurringRuns: ListPipelineRecurringRunsAPI =
251-
(hostPath) => (opts, params) => {
252-
let predicates = params?.filter?.predicates ?? [];
253-
if (params?.pipelineVersionId) {
254-
predicates = [
255-
...predicates,
256-
{
257-
key: 'pipeline_version_id',
258-
operation: PipelinesFilterOp.EQUALS,
259-
// eslint-disable-next-line camelcase
260-
string_value: params.pipelineVersionId,
261-
},
262-
];
263-
}
264-
265-
return handlePipelineFailures(
251+
(hostPath) => (opts, params) =>
252+
handlePipelineFailures(
266253
proxyGET(
267254
hostPath,
268255
'/apis/v2beta1/recurringruns',
269256
{
270-
...pipelineParamsToQuery({ ...params, filter: { predicates } }),
257+
...pipelineParamsToQuery(params),
271258
// eslint-disable-next-line camelcase
272259
experiment_id: params?.experimentId,
260+
// eslint-disable-next-line camelcase
261+
pipeline_version_id: params?.pipelineVersionId,
273262
},
274263
opts,
275264
),
276265
);
277-
};
278266

279267
export const listPipelineVersions: ListPipelineVersionsAPI =
280268
(hostPath) => (opts, pipelineId, params) =>

frontend/src/concepts/pipelines/apiHooks/usePipelineRecurringRuns.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const usePipelineRecurringRuns = (
1111
): FetchState<PipelineListPaged<PipelineRecurringRunKF>> => {
1212
const { api } = usePipelinesAPI();
1313
const experimentId = options?.experimentId;
14+
const pipelineVersionId = options?.pipelineVersionId;
1415

1516
const fetchLatestVersionId = React.useCallback(
1617
async (pipelineId: string, opts: K8sAPIOptions) => {
@@ -26,9 +27,24 @@ const usePipelineRecurringRuns = (
2627
return usePipelineQuery<PipelineRecurringRunKF>(
2728
React.useCallback(
2829
async (opts, params) => {
30+
const unsupportedKeys = new Set(['experiment_id', 'pipeline_version_id']);
31+
const unsupported = new Map(
32+
params?.filter?.predicates
33+
?.filter((p) => unsupportedKeys.has(p.key))
34+
.map((p) => [p.key, p.string_value]) ?? [],
35+
);
36+
const supportedPredicates = params?.filter?.predicates?.filter(
37+
(p) => !unsupportedKeys.has(p.key),
38+
);
39+
const resolvedExperimentId = experimentId || unsupported.get('experiment_id');
40+
const resolvedPipelineVersionId =
41+
pipelineVersionId || unsupported.get('pipeline_version_id');
42+
2943
const response = await api.listPipelineRecurringRuns(opts, {
3044
...params,
31-
...(experimentId && { experimentId }),
45+
...(resolvedExperimentId && { experimentId: resolvedExperimentId }),
46+
...(resolvedPipelineVersionId && { pipelineVersionId: resolvedPipelineVersionId }),
47+
filter: supportedPredicates ? { predicates: supportedPredicates } : params?.filter,
3248
});
3349

3450
if (!response.recurringRuns) {
@@ -57,7 +73,7 @@ const usePipelineRecurringRuns = (
5773
);
5874
return { ...response, items: completeRecurringRuns };
5975
},
60-
[api, experimentId, fetchLatestVersionId],
76+
[api, experimentId, pipelineVersionId, fetchLatestVersionId],
6177
),
6278
options,
6379
);

frontend/src/concepts/pipelines/content/compareRuns/CompareRunsRunList.tsx

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@ import PipelineRunTableToolbar from '#~/concepts/pipelines/content/tables/pipeli
1919
import { manageCompareRunsRoute } from '#~/routes/pipelines/runs';
2020
import { usePipelinesAPI } from '#~/concepts/pipelines/context';
2121
import { ExperimentContext } from '#~/pages/pipelines/global/experiments/ExperimentContext';
22-
import { PipelineRunExperimentsContext } from '#~/pages/pipelines/global/runs/PipelineRunExperimentsContext';
2322
import useMlflowExperiments from '#~/concepts/mlflow/useMlflowExperiments';
2423
import { ExperimentKF } from '#~/concepts/pipelines/kfTypes';
2524

2625
const CompareRunsRunList: React.FC = () => {
2726
const { namespace } = usePipelinesAPI();
2827
const { experiment } = React.useContext(ExperimentContext);
29-
const { experiments: allExperiments } = React.useContext(PipelineRunExperimentsContext);
3028
const { status: isMlflowAvailable } = useIsAreaAvailable(SupportedArea.MLFLOW_PIPELINES);
3129
const { runs, loaded } = useCompareRuns();
3230
const { data: mlflowExperiments, loaded: mlflowExperimentsLoaded } = useMlflowExperiments({
@@ -47,27 +45,17 @@ const CompareRunsRunList: React.FC = () => {
4745
const startedTime = getDataValue(filterData[FilterOptions.CREATED_AT]);
4846
const startedDate = startedTime && new Date(startedTime);
4947
const state = getDataValue(filterData[FilterOptions.STATUS])?.toLowerCase();
50-
const runGroupFilter = experiment
51-
? undefined
52-
: getDataValue(filterData[FilterOptions.RUN_GROUP])?.toLowerCase();
48+
const runGroupFilter = getDataValue(filterData[FilterOptions.RUN_GROUP]);
5349
const pipelineVersionId = getDataValue(filterData[FilterOptions.PIPELINE_VERSION]);
5450
const mlflowExperimentFilter = isMlflowAvailable
5551
? getDataValue(filterData[FilterOptions.MLFLOW_EXPERIMENT])?.toLowerCase()
5652
: undefined;
5753

58-
const matchingRunGroups = runGroupFilter
59-
? new Set(
60-
allExperiments
61-
.filter((e) => e.display_name.toLowerCase() === runGroupFilter)
62-
.map((e) => e.experiment_id),
63-
)
64-
: undefined;
65-
6654
return runs.filter((run) => {
6755
const nameMatch = !runName || run.display_name.toLowerCase().includes(runName);
6856
const dateTimeMatch = !startedDate || new Date(run.created_at) >= startedDate;
6957
const stateMatch = !state || run.state.toLowerCase() === state;
70-
const runGroupMatch = !matchingRunGroups || matchingRunGroups.has(run.experiment_id);
58+
const runGroupIdMatch = !runGroupFilter || run.experiment_id === runGroupFilter;
7159
const pipelineVersionIdMatch =
7260
!pipelineVersionId ||
7361
run.pipeline_version_reference?.pipeline_version_id === pipelineVersionId;
@@ -80,12 +68,12 @@ const CompareRunsRunList: React.FC = () => {
8068
nameMatch &&
8169
dateTimeMatch &&
8270
stateMatch &&
83-
runGroupMatch &&
71+
runGroupIdMatch &&
8472
pipelineVersionIdMatch &&
8573
mlflowExperimentMatch
8674
);
8775
});
88-
}, [runs, filterData, allExperiments, experiment, isMlflowAvailable]);
76+
}, [runs, filterData, isMlflowAvailable]);
8977

9078
const manageRunsHref = manageCompareRunsRoute(
9179
namespace,
@@ -94,7 +82,10 @@ const CompareRunsRunList: React.FC = () => {
9482
);
9583
const handleRunGroupClick = React.useCallback(
9684
(clickedExperiment: ExperimentKF) => {
97-
filterToolbarProps.onFilterUpdate(FilterOptions.RUN_GROUP, clickedExperiment.display_name);
85+
filterToolbarProps.onFilterUpdate(FilterOptions.RUN_GROUP, {
86+
value: clickedExperiment.experiment_id,
87+
label: clickedExperiment.display_name,
88+
});
9889
},
9990
[filterToolbarProps],
10091
);

frontend/src/concepts/pipelines/content/createRun/RunForm.tsx

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as React from 'react';
2-
import { Form, FormGroup, FormSection, TextArea, TextInput } from '@patternfly/react-core';
3-
import { CharLimitHelperText } from '#~/components/CharLimitHelperText';
4-
import DashboardHelpTooltip from '#~/concepts/dashboard/DashboardHelpTooltip';
2+
import { Form, FormGroup, FormSection, Stack, StackItem } from '@patternfly/react-core';
3+
import NameDescriptionField from '#~/concepts/k8s/NameDescriptionField';
54
import {
65
MlflowFormData,
76
PipelineVersionToUse,
@@ -19,19 +18,20 @@ import {
1918
} from '#~/concepts/pipelines/kfTypes';
2019
import ProjectSection from '#~/concepts/pipelines/content/createRun/contentSections/ProjectSection';
2120
import { getDisplayNameFromK8sResource } from '#~/concepts/k8s/utils';
21+
import { ActiveExperimentSelector } from '#~/concepts/pipelines/content/experiment/ExperimentSelector';
2222
import { useLatestPipelineVersion } from '#~/concepts/pipelines/apiHooks/useLatestPipelineVersion';
2323
import { getNameEqualsFilter } from '#~/concepts/pipelines/utils';
2424
import { DuplicateNameHelperText } from '#~/concepts/pipelines/content/DuplicateNameHelperText';
2525
import { usePipelinesAPI } from '#~/concepts/pipelines/context';
2626
import useDebounceCallback from '#~/utilities/useDebounceCallback';
2727
import { isArgoWorkflow } from '#~/concepts/pipelines/content/tables/utils';
28-
import { ActiveExperimentSelector } from '#~/concepts/pipelines/content/experiment/ExperimentSelector';
2928
import {
3029
NAME_CHARACTER_LIMIT,
3130
DESCRIPTION_CHARACTER_LIMIT,
3231
} from '#~/concepts/pipelines/content/const';
3332
import { SupportedArea, useIsAreaAvailable } from '#~/concepts/areas';
3433
import { runGroupCreateModalPopoverText } from '#~/pages/pipelines/global/runs/const';
34+
import DashboardHelpTooltip from '#~/concepts/dashboard/DashboardHelpTooltip';
3535
import MlflowIntegrationSection from './contentSections/MlflowIntegrationSection';
3636
import PipelineSection from './contentSections/PipelineSection';
3737
import { RunTypeSection } from './contentSections/RunTypeSection';
@@ -128,57 +128,34 @@ const RunForm: React.FC<RunFormProps> = ({ data, onValueChange, isDuplicated })
128128
]
129129
}
130130
>
131-
<FormGroup label="Name" isRequired fieldId="run-name">
132-
<TextInput
133-
isRequired
134-
id="run-name"
135-
data-testid="run-name"
136-
name="run-name"
137-
value={data.nameDesc.name}
138-
onChange={(_e, value) => {
139-
onValueChange('nameDesc', { ...data.nameDesc, name: value });
140-
setHasDuplicateName(false);
141-
checkForDuplicateName(value);
142-
}}
143-
maxLength={NAME_CHARACTER_LIMIT}
144-
/>
145-
{hasDuplicateName ? <DuplicateNameHelperText name={name} /> : undefined}
146-
<CharLimitHelperText
147-
limit={NAME_CHARACTER_LIMIT}
148-
currentLength={data.nameDesc.name.length}
149-
/>
150-
</FormGroup>
131+
<NameDescriptionField
132+
nameFieldId="run-name"
133+
descriptionFieldId="run-description"
134+
data={data.nameDesc}
135+
setData={(nameDesc) => onValueChange('nameDesc', nameDesc)}
136+
maxLengthName={NAME_CHARACTER_LIMIT}
137+
maxLengthDesc={DESCRIPTION_CHARACTER_LIMIT}
138+
onNameChange={(value) => {
139+
setHasDuplicateName(false);
140+
checkForDuplicateName(value);
141+
}}
142+
nameHelperText={hasDuplicateName ? <DuplicateNameHelperText name={name} /> : undefined}
143+
/>
151144

152145
<FormGroup
153146
label="Run group"
154-
fieldId="run-group"
147+
aria-label="Run group"
155148
isRequired
156149
labelHelp={<DashboardHelpTooltip content={runGroupCreateModalPopoverText} />}
157150
>
158-
<ActiveExperimentSelector
159-
dataTestId="run-group-selector"
160-
selection={data.runGroup}
161-
onSelect={(experiment) => onValueChange('runGroup', experiment.display_name)}
162-
/>
163-
<CharLimitHelperText limit={NAME_CHARACTER_LIMIT} currentLength={data.runGroup.length} />
164-
</FormGroup>
165-
166-
<FormGroup label="Description" fieldId="run-description">
167-
<TextArea
168-
resizeOrientation="vertical"
169-
id="run-description"
170-
data-testid="run-description"
171-
name="run-description"
172-
value={data.nameDesc.description}
173-
onChange={(_e, description) =>
174-
onValueChange('nameDesc', { ...data.nameDesc, description })
175-
}
176-
maxLength={DESCRIPTION_CHARACTER_LIMIT}
177-
/>
178-
<CharLimitHelperText
179-
limit={DESCRIPTION_CHARACTER_LIMIT}
180-
currentLength={data.nameDesc.description.length}
181-
/>
151+
<Stack hasGutter>
152+
<StackItem>
153+
<ActiveExperimentSelector
154+
selection={data.experiment?.display_name}
155+
onSelect={(runGroup) => onValueChange('experiment', runGroup)}
156+
/>
157+
</StackItem>
158+
</Stack>
182159
</FormGroup>
183160

184161
{isSchedule && data.runType.type === RunTypeOption.SCHEDULED && (

frontend/src/concepts/pipelines/content/createRun/RunPage.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { ValueOf } from '#~/typeHelpers';
2323
import { useGetSearchParamValues } from '#~/utilities/useGetSearchParamValues';
2424
import { PipelineRunSearchParam } from '#~/concepts/pipelines/content/types';
2525
import { asEnumMember } from '#~/utilities/utils';
26+
import useDefaultExperiment from '#~/pages/pipelines/global/experiments/useDefaultExperiment';
2627

2728
type RunPageProps = {
2829
duplicateRun?: PipelineRunKF | PipelineRecurringRunKF | null;
@@ -48,7 +49,7 @@ const RunPage: React.FC<RunPageProps> = ({
4849
nameDesc: locationNameDesc,
4950
pipeline: locationPipeline,
5051
version: locationVersion,
51-
runGroup: locationRunGroup,
52+
experiment: locationRunGroup,
5253
mlflow: locationMlflow,
5354
} = location.state?.locationData || {};
5455
const { triggerType: triggerTypeString } = useGetSearchParamValues([
@@ -57,6 +58,7 @@ const RunPage: React.FC<RunPageProps> = ({
5758
const triggerType = asEnumMember(triggerTypeString, ScheduledType);
5859
const isSchedule = runType === RunTypeOption.SCHEDULED;
5960
const { status: isMlflowAvailable } = useIsAreaAvailable(SupportedArea.MLFLOW_PIPELINES);
61+
const [defaultExperiment] = useDefaultExperiment();
6062
const jumpToSections = Object.values(CreateRunPageSections).filter(
6163
(section) =>
6264
!(
@@ -99,7 +101,7 @@ const RunPage: React.FC<RunPageProps> = ({
99101
pipeline: locationPipeline || contextPipeline,
100102
version: locationVersion || contextPipelineVersion,
101103
versionToUse: versionToUseData,
102-
runGroup: locationRunGroup || contextExperiment?.display_name || '',
104+
experiment: locationRunGroup || contextExperiment || defaultExperiment,
103105
...(locationMlflow ? { mlflow: locationMlflow } : {}),
104106
});
105107

frontend/src/concepts/pipelines/content/createRun/const.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ export const DEFAULT_PERIODIC_DATA: RunTypeScheduledData = {
1616
export const DATE_FORMAT = 'YYYY-MM-DD';
1717
export const DEFAULT_TIME = '12:00 AM';
1818
export const RUN_OPTION_LABEL_SIZE = 100;
19-
export const DEFAULT_RUN_GROUP = 'Default';
2019

2120
export enum CreateRunPageSections {
2221
RUN_TYPE = 'run-section-run-type',

0 commit comments

Comments
 (0)