-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
…aram selector
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import React from 'react'; | ||
|
||
import { Artifact } from '~/third_party/mlmd'; | ||
import { GetArtifactsByContextRequest } from '~/third_party/mlmd/generated/ml_metadata/proto/metadata_store_service_pb'; | ||
import useFetchState, { FetchState, FetchStateCallbackPromise } from '~/utilities/useFetchState'; | ||
import { usePipelinesAPI } from '~/concepts/pipelines/context'; | ||
import { PipelineRunKFv2 } from '~/concepts/pipelines/kfTypes'; | ||
import { MlmdContextTypes } from './types'; | ||
import { getMlmdContext } from './useMlmdContext'; | ||
|
||
export const useGetArtifactsByRuns = ( | ||
runs: PipelineRunKFv2[], | ||
): FetchState<Record<string, Artifact[]>[]> => { | ||
const { metadataStoreServiceClient } = usePipelinesAPI(); | ||
|
||
const call = React.useCallback<FetchStateCallbackPromise<Record<string, Artifact[]>[]>>( | ||
() => | ||
Promise.all( | ||
runs.map((run) => | ||
getMlmdContext(metadataStoreServiceClient, run.run_id, MlmdContextTypes.RUN).then( | ||
async (context) => { | ||
if (!context) { | ||
throw new Error(`No context for run: ${run.run_id}`); | ||
} | ||
|
||
const request = new GetArtifactsByContextRequest(); | ||
request.setContextId(context.getId()); | ||
|
||
const response = await metadataStoreServiceClient.getArtifactsByContext(request); | ||
const artifacts = response.getArtifactsList(); | ||
|
||
return { | ||
[run.run_id]: artifacts, | ||
}; | ||
}, | ||
), | ||
), | ||
), | ||
[metadataStoreServiceClient, runs], | ||
); | ||
|
||
return useFetchState(call, []); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Artifact } from '~/third_party/mlmd'; | ||
|
||
export interface ScalarMetrics { | ||
name: string; | ||
value: string; | ||
} | ||
|
||
export const getScalarMetrics = (artifact: Artifact): ScalarMetrics[] => | ||
artifact | ||
.toObject() | ||
.customPropertiesMap.reduce( | ||
( | ||
acc: { name: string; value: string }[], | ||
[customPropKey, { stringValue, intValue, doubleValue, boolValue }], | ||
) => { | ||
if (customPropKey !== 'display_name') { | ||
acc.push({ | ||
Check warning on line 17 in frontend/src/concepts/pipelines/content/pipelinesDetails/pipelineRun/artifacts/utils.ts Codecov / codecov/patchfrontend/src/concepts/pipelines/content/pipelinesDetails/pipelineRun/artifacts/utils.ts#L14-L17
|
||
name: customPropKey, | ||
value: stringValue || (intValue || doubleValue || boolValue).toString(), | ||
Check warning on line 19 in frontend/src/concepts/pipelines/content/pipelinesDetails/pipelineRun/artifacts/utils.ts Codecov / codecov/patchfrontend/src/concepts/pipelines/content/pipelinesDetails/pipelineRun/artifacts/utils.ts#L19
|
||
}); | ||
} | ||
|
||
return acc; | ||
Check warning on line 23 in frontend/src/concepts/pipelines/content/pipelinesDetails/pipelineRun/artifacts/utils.ts Codecov / codecov/patchfrontend/src/concepts/pipelines/content/pipelinesDetails/pipelineRun/artifacts/utils.ts#L23
|
||
}, | ||
[], | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import React from 'react'; | ||
import { | ||
Button, | ||
Checkbox, | ||
DataListDragButton, | ||
DragDrop, | ||
Draggable, | ||
DraggableItemPosition, | ||
Droppable, | ||
Flex, | ||
FlexItem, | ||
Label, | ||
Modal, | ||
ModalBoxBody, | ||
ModalVariant, | ||
Stack, | ||
StackItem, | ||
Tooltip, | ||
} from '@patternfly/react-core'; | ||
import { getMetricsColumnsLocalStorageKey } from './utils'; | ||
|
||
interface MetricsColumn { | ||
id: string; | ||
checked: boolean; | ||
} | ||
|
||
interface CustomMetricsColumnsModalProps { | ||
columns: MetricsColumn[]; | ||
experimentId: string | undefined; | ||
onClose: () => void; | ||
} | ||
|
||
export const CustomMetricsColumnsModal: React.FC<CustomMetricsColumnsModalProps> = ({ | ||
onClose, | ||
experimentId, | ||
...props | ||
}) => { | ||
const [columns, setColumns] = React.useState(props.columns); | ||
const [dragDropText, setDragDropText] = React.useState(''); | ||
const metricsColumnsLocalStorageKey = getMetricsColumnsLocalStorageKey(experimentId ?? ''); | ||
const selectedColumns = Object.values(columns).reduce((acc: string[], column) => { | ||
if (column.checked) { | ||
acc.push(column.id); | ||
Check warning on line 43 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L34-L43
|
||
} | ||
return acc; | ||
Check warning on line 45 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L45
|
||
}, []); | ||
|
||
const onDrag = React.useCallback( | ||
(source: DraggableItemPosition) => { | ||
setDragDropText(`Started dragging ${columns[source.index].id}`); | ||
Check warning on line 50 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L48-L50
|
||
|
||
return true; | ||
Check warning on line 52 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L52
|
||
}, | ||
[columns], | ||
); | ||
|
||
const onDragMove = React.useCallback( | ||
(source: DraggableItemPosition, dest?: DraggableItemPosition | undefined) => { | ||
const newDragDropText = dest | ||
? `Move ${columns[source.index].id} to ${columns[dest.index].id}` | ||
: 'Invalid drop zone'; | ||
Check warning on line 61 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L57-L61
|
||
|
||
if (newDragDropText !== dragDropText) { | ||
setDragDropText(newDragDropText); | ||
Check warning on line 64 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L63-L64
|
||
} | ||
}, | ||
[columns, dragDropText], | ||
); | ||
|
||
const onDrop = React.useCallback( | ||
(source: DraggableItemPosition, dest?: DraggableItemPosition | undefined) => { | ||
if (dest) { | ||
const reorderedColumns = columns; | ||
const [removedColumns] = reorderedColumns.splice(source.index, 1); | ||
reorderedColumns.splice(dest.index, 0, removedColumns); | ||
Check warning on line 75 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L70-L75
|
||
|
||
setColumns(reorderedColumns); | ||
setDragDropText('Dragging finished.'); | ||
Check warning on line 78 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L77-L78
|
||
|
||
return true; | ||
Check warning on line 80 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L80
|
||
} | ||
|
||
return false; | ||
Check warning on line 83 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L83
|
||
}, | ||
[columns], | ||
); | ||
|
||
const onUpdate = React.useCallback(() => { | ||
localStorage.removeItem(metricsColumnsLocalStorageKey); | ||
localStorage.setItem(metricsColumnsLocalStorageKey, JSON.stringify(selectedColumns)); | ||
Check warning on line 90 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L88-L90
|
||
|
||
onClose(); | ||
Check warning on line 92 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L92
|
||
}, [metricsColumnsLocalStorageKey, onClose, selectedColumns]); | ||
|
||
return ( | ||
Check warning on line 95 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L95
|
||
<Modal | ||
bodyAriaLabel="Metrics column names" | ||
tabIndex={0} | ||
hasNoBodyWrapper | ||
aria-label="Custom metrics columns modal" | ||
variant={ModalVariant.small} | ||
height="fit-content" | ||
title="Customize metrics columns" | ||
description={ | ||
<Stack hasGutter className="pf-v5-u-pb-md"> | ||
<StackItem className="pf-v5-u-mt-sm"> | ||
Select up to 10 metrics that will display as columns in the table. Drag and drop column | ||
names to reorder them. | ||
</StackItem> | ||
<StackItem> | ||
<Label> | ||
{selectedColumns.length} / total {columns.length} selected | ||
</Label> | ||
</StackItem> | ||
</Stack> | ||
} | ||
isOpen | ||
onClose={onClose} | ||
actions={[ | ||
<Button key="update" variant="primary" onClick={onUpdate}> | ||
Update | ||
</Button>, | ||
<Button key="cancel" variant="link" onClick={onClose}> | ||
Cancel | ||
</Button>, | ||
]} | ||
> | ||
<ModalBoxBody className="pf-v5-u-pt-0"> | ||
<DragDrop onDrag={onDrag} onDragMove={onDragMove} onDrop={onDrop}> | ||
<Droppable className="pf-v5-u-pt-sm pf-v5-u-pb-sm"> | ||
{columns.map(({ id, checked }) => { | ||
Check warning on line 131 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L131
|
||
const columnCheckbox = ( | ||
<Checkbox | ||
Check warning on line 133 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L133
|
||
id={id} | ||
isChecked={checked} | ||
isDisabled={selectedColumns.length === 10 && !checked} | ||
onChange={(_, isChecked) => | ||
setColumns((prevColumns) => | ||
prevColumns.map((prevColumn) => { | ||
if (prevColumn.id === id) { | ||
return { id, checked: isChecked }; | ||
Check warning on line 141 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L136-L141
|
||
} | ||
|
||
return prevColumn; | ||
Check warning on line 144 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L144
|
||
}), | ||
) | ||
} | ||
/> | ||
); | ||
|
||
return ( | ||
Check warning on line 151 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L151
|
||
<Draggable key={id} className="pf-v5-u-p-sm"> | ||
<Flex | ||
alignItems={{ default: 'alignItemsCenter' }} | ||
flexWrap={{ default: 'nowrap' }} | ||
> | ||
<DataListDragButton | ||
aria-label="Reorder" | ||
aria-labelledby={`draggable-${id}`} | ||
aria-describedby={`description-${id}`} | ||
aria-pressed="false" | ||
/> | ||
<FlexItem spacer={{ default: 'spacerSm' }}> | ||
{selectedColumns.length === 10 && !checked ? ( | ||
<Tooltip content="Maximum metrics selected. To view values of all metrics, go to the Compare runs page."> | ||
Check warning on line 165 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L164-L165
|
||
{columnCheckbox} | ||
</Tooltip> | ||
) : ( | ||
columnCheckbox | ||
Check warning on line 169 in frontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx Codecov / codecov/patchfrontend/src/concepts/pipelines/content/tables/pipelineRun/CustomMetricsColumnsModal.tsx#L169
|
||
)} | ||
</FlexItem> | ||
<FlexItem>{id}</FlexItem> | ||
</Flex> | ||
</Draggable> | ||
); | ||
})} | ||
</Droppable> | ||
</DragDrop> | ||
</ModalBoxBody> | ||
</Modal> | ||
); | ||
}; |