-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2753 from DaoDaoNoCode/jira-rhoaieng-4776
Executions empty state and table
- Loading branch information
Showing
18 changed files
with
603 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
frontend/src/concepts/pipelines/apiHooks/mlmd/useGetExecutionsList.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React from 'react'; | ||
import { useMlmdListContext, usePipelinesAPI } from '~/concepts/pipelines/context'; | ||
import { Execution, GetExecutionsRequest } from '~/third_party/mlmd'; | ||
import { ListOperationOptions } from '~/third_party/mlmd/generated/ml_metadata/proto/metadata_store_pb'; | ||
import useFetchState, { FetchState, FetchStateCallbackPromise } from '~/utilities/useFetchState'; | ||
|
||
export interface ExecutionsListResponse { | ||
executions: Execution[]; | ||
nextPageToken: string; | ||
} | ||
|
||
export const useGetExecutionsList = (): FetchState<ExecutionsListResponse | null> => { | ||
const { metadataStoreServiceClient } = usePipelinesAPI(); | ||
const { pageToken, maxResultSize, filterQuery } = useMlmdListContext(); | ||
|
||
const call = React.useCallback<FetchStateCallbackPromise<ExecutionsListResponse>>(async () => { | ||
const request = new GetExecutionsRequest(); | ||
const listOperationOptions = new ListOperationOptions(); | ||
listOperationOptions.setOrderByField( | ||
new ListOperationOptions.OrderByField().setField(ListOperationOptions.OrderByField.Field.ID), | ||
); | ||
|
||
if (filterQuery) { | ||
listOperationOptions.setFilterQuery(filterQuery); | ||
} | ||
if (pageToken) { | ||
listOperationOptions.setNextPageToken(pageToken); | ||
} | ||
|
||
listOperationOptions.setMaxResultSize(maxResultSize); | ||
request.setOptions(listOperationOptions); | ||
|
||
const response = await metadataStoreServiceClient.getExecutions(request); | ||
const nextPageToken = response.getNextPageToken(); | ||
listOperationOptions.setNextPageToken(nextPageToken); | ||
|
||
return { executions: response.getExecutionsList(), nextPageToken }; | ||
}, [filterQuery, maxResultSize, metadataStoreServiceClient, pageToken]); | ||
|
||
return useFetchState(call, null); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
frontend/src/pages/pipelines/GlobalPipelineExecutionsRoutes.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import * as React from 'react'; | ||
import { Navigate, Route } from 'react-router-dom'; | ||
import ProjectsRoutes from '~/concepts/projects/ProjectsRoutes'; | ||
import GlobalPipelineCoreLoader from '~/pages/pipelines/global/GlobalPipelineCoreLoader'; | ||
import { executionsBaseRoute } from '~/routes'; | ||
import { | ||
executionsPageDescription, | ||
executionsPageTitle, | ||
} from '~/pages/pipelines/global/experiments/executions/const'; | ||
import GlobalExecutions from '~/pages/pipelines/global/experiments/executions/GlobalExecutions'; | ||
|
||
const GlobalPipelineExecutionsRoutes: React.FC = () => ( | ||
<ProjectsRoutes> | ||
<Route | ||
path="/:namespace?/*" | ||
element={ | ||
<GlobalPipelineCoreLoader | ||
title={executionsPageTitle} | ||
description={executionsPageDescription} | ||
getInvalidRedirectPath={executionsBaseRoute} | ||
/> | ||
} | ||
> | ||
<Route index element={<GlobalExecutions />} /> | ||
<Route path="*" element={<Navigate to="." />} /> | ||
</Route> | ||
</ProjectsRoutes> | ||
); | ||
|
||
export default GlobalPipelineExecutionsRoutes; |
68 changes: 68 additions & 0 deletions
68
frontend/src/pages/pipelines/global/experiments/executions/ExecutionsList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import * as React from 'react'; | ||
import { | ||
Bullseye, | ||
EmptyState, | ||
EmptyStateBody, | ||
EmptyStateHeader, | ||
EmptyStateIcon, | ||
Spinner, | ||
} from '@patternfly/react-core'; | ||
import { ExclamationCircleIcon, PlusCircleIcon } from '@patternfly/react-icons'; | ||
import { useGetExecutionsList } from '~/concepts/pipelines/apiHooks/mlmd/useGetExecutionsList'; | ||
import ExecutionsTable from '~/pages/pipelines/global/experiments/executions/ExecutionsTable'; | ||
import { useMlmdListContext } from '~/concepts/pipelines/context'; | ||
|
||
const ExecutionsList: React.FC = () => { | ||
const { filterQuery } = useMlmdListContext(); | ||
const [executionsResponse, isExecutionsLoaded, executionsError] = useGetExecutionsList(); | ||
const { executions, nextPageToken } = executionsResponse || { executions: [] }; | ||
const filterQueryRef = React.useRef(filterQuery); | ||
|
||
if (executionsError) { | ||
return ( | ||
<Bullseye> | ||
<EmptyState> | ||
<EmptyStateHeader | ||
titleText="There was an issue loading executions" | ||
icon={<EmptyStateIcon icon={ExclamationCircleIcon} />} | ||
headingLevel="h2" | ||
/> | ||
<EmptyStateBody>{executionsError.message}</EmptyStateBody> | ||
</EmptyState> | ||
</Bullseye> | ||
); | ||
} | ||
|
||
if (!isExecutionsLoaded) { | ||
return ( | ||
<Bullseye> | ||
<Spinner /> | ||
</Bullseye> | ||
); | ||
} | ||
|
||
if (!executions.length && !filterQuery && filterQueryRef.current === filterQuery) { | ||
return ( | ||
<EmptyState data-testid="global-no-executions"> | ||
<EmptyStateHeader | ||
titleText="No executions" | ||
icon={<EmptyStateIcon icon={PlusCircleIcon} />} | ||
headingLevel="h4" | ||
/> | ||
<EmptyStateBody> | ||
No experiments have been executed within this project. Select a different project, or | ||
execute an experiment from the <b>Experiments and runs</b> page. | ||
</EmptyStateBody> | ||
</EmptyState> | ||
); | ||
} | ||
|
||
return ( | ||
<ExecutionsTable | ||
executions={executions} | ||
nextPageToken={nextPageToken} | ||
isLoaded={isExecutionsLoaded} | ||
/> | ||
); | ||
}; | ||
export default ExecutionsList; |
93 changes: 93 additions & 0 deletions
93
frontend/src/pages/pipelines/global/experiments/executions/ExecutionsTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import * as React from 'react'; | ||
import { TableBase } from '~/components/table'; | ||
import { Execution } from '~/third_party/mlmd'; | ||
import ExecutionsTableRow from '~/pages/pipelines/global/experiments/executions/ExecutionsTableRow'; | ||
import { executionColumns } from '~/pages/pipelines/global/experiments/executions/columns'; | ||
import { useMlmdListContext } from '~/concepts/pipelines/context'; | ||
import { initialFilterData } from '~/pages/pipelines/global/experiments/executions/const'; | ||
import ExecutionsTableToolbar from '~/pages/pipelines/global/experiments/executions/ExecutionsTableToolbar'; | ||
import DashboardEmptyTableView from '~/concepts/dashboard/DashboardEmptyTableView'; | ||
|
||
interface ExecutionsTableProps { | ||
executions: Execution[]; | ||
nextPageToken: string | undefined; | ||
isLoaded: boolean; | ||
} | ||
|
||
const ExecutionsTable: React.FC<ExecutionsTableProps> = ({ | ||
executions, | ||
nextPageToken, | ||
isLoaded, | ||
}) => { | ||
const { | ||
maxResultSize, | ||
setPageToken: setRequestToken, | ||
setMaxResultSize, | ||
} = useMlmdListContext(nextPageToken); | ||
|
||
const [page, setPage] = React.useState(1); | ||
const [filterData, setFilterData] = React.useState(initialFilterData); | ||
const [pageTokens, setPageTokens] = React.useState<Record<number, string>>({}); | ||
|
||
const onClearFilters = React.useCallback(() => setFilterData(initialFilterData), [setFilterData]); | ||
|
||
const onNextPageClick = React.useCallback( | ||
(_: React.SyntheticEvent<HTMLButtonElement>, nextPage: number) => { | ||
if (nextPageToken) { | ||
setPageTokens((prevTokens) => ({ ...prevTokens, [nextPage]: nextPageToken })); | ||
setRequestToken(nextPageToken); | ||
setPage(nextPage); | ||
} | ||
}, | ||
[nextPageToken, setRequestToken], | ||
); | ||
|
||
const onPrevPageClick = React.useCallback( | ||
(_: React.SyntheticEvent<HTMLButtonElement>, prevPage: number) => { | ||
if (pageTokens[prevPage]) { | ||
setRequestToken(pageTokens[prevPage]); | ||
setPage(prevPage); | ||
} else { | ||
setRequestToken(undefined); | ||
} | ||
}, | ||
[pageTokens, setRequestToken], | ||
); | ||
|
||
return ( | ||
<TableBase | ||
variant="compact" | ||
loading={!isLoaded} | ||
enablePagination="compact" | ||
data={executions} | ||
columns={executionColumns} | ||
data-testid="executions-list-table" | ||
rowRenderer={(execution) => <ExecutionsTableRow key={execution.getId()} obj={execution} />} | ||
toggleTemplate={() => <>{maxResultSize} per page </>} | ||
toolbarContent={ | ||
<ExecutionsTableToolbar | ||
filterData={filterData} | ||
setFilterData={setFilterData} | ||
onClearFilters={onClearFilters} | ||
/> | ||
} | ||
page={page} | ||
perPage={maxResultSize} | ||
disableItemCount | ||
onNextClick={onNextPageClick} | ||
onPreviousClick={onPrevPageClick} | ||
onPerPageSelect={(_, newSize) => { | ||
setMaxResultSize(newSize); | ||
}} | ||
onSetPage={(_, newPage) => { | ||
if (newPage < page || !isLoaded) { | ||
setPage(newPage); | ||
} | ||
}} | ||
emptyTableView={<DashboardEmptyTableView onClearFilters={onClearFilters} />} | ||
id="executions-list-table" | ||
/> | ||
); | ||
}; | ||
|
||
export default ExecutionsTable; |
23 changes: 23 additions & 0 deletions
23
frontend/src/pages/pipelines/global/experiments/executions/ExecutionsTableRow.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import * as React from 'react'; | ||
import { Td, Tr } from '@patternfly/react-table'; | ||
import { Execution } from '~/third_party/mlmd'; | ||
import ExecutionsTableRowStatusIcon from '~/pages/pipelines/global/experiments/executions/ExecutionsTableRowStatusIcon'; | ||
|
||
type ExecutionsTableRowProps = { | ||
obj: Execution; | ||
}; | ||
|
||
const ExecutionsTableRow: React.FC<ExecutionsTableRowProps> = ({ obj }) => ( | ||
<Tr> | ||
<Td dataLabel="Executions"> | ||
{obj.getCustomPropertiesMap().get('task_name')?.getStringValue() || '(No name)'} | ||
</Td> | ||
<Td dataLabel="Status"> | ||
<ExecutionsTableRowStatusIcon status={obj.getLastKnownState()} /> | ||
</Td> | ||
<Td dataLabel="ID">{obj.getId()}</Td> | ||
<Td dataLabel="Type">{obj.getType()}</Td> | ||
</Tr> | ||
); | ||
|
||
export default ExecutionsTableRow; |
Oops, something went wrong.