diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx index d1fdde1c37..89756a43ee 100644 --- a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx +++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx @@ -1,13 +1,101 @@ -import React from 'react'; +import React, { useEffect, useCallback } from 'react'; +import { t } from '@lingui/macro'; import { withI18n } from '@lingui/react'; +import { useLocation } from 'react-router-dom'; import { Card, PageSection } from '@patternfly/react-core'; -function ManagementJobDetails() { +import { SystemJobTemplatesAPI } from '../../../api'; +import { useConfig } from '../../../contexts/Config'; +import { getQSConfig, parseQueryString } from '../../../util/qs'; +import useRequest from '../../../util/useRequest'; +import DatalistToolbar from '../../../components/DataListToolbar'; +import PaginatedDataList from '../../../components/PaginatedDataList'; + +import ManagementJobListItem from './ManagementJobListItem'; + +const QS_CONFIG = getQSConfig('management_jobs', { + page: 1, + page_size: 20, +}); + +const buildSearchKeys = options => { + const actions = options?.data?.actions?.GET || {}; + const searchableKeys = Object.keys(actions).filter( + key => actions[key].filterable + ); + const relatedSearchableKeys = options?.data?.related_search_fields || []; + + return { searchableKeys, relatedSearchableKeys }; +}; + +const loadManagementJobs = async search => { + const params = parseQueryString(QS_CONFIG, search); + const [ + { + data: { results: items, count }, + }, + options, + ] = await Promise.all([ + SystemJobTemplatesAPI.read(params), + SystemJobTemplatesAPI.readOptions(), + ]); + + return { items, count, options }; +}; + +function ManagementJobList({ i18n }) { + const { search } = useLocation(); + const { me } = useConfig(); + + const { + request, + error = false, + isLoading = true, + result: { options = {}, items = [], count = 0 }, + } = useRequest( + useCallback(async () => loadManagementJobs(search), [search]), + {} + ); + + useEffect(() => { + request(); + }, [request]); + + const { searchableKeys, relatedSearchableKeys } = buildSearchKeys(options); + return ( - - Management Job List - + <> + + + ( + + )} + renderItem={({ id, name, description }) => ( + + )} + /> + + + ); } -export default withI18n()(ManagementJobDetails); +export default withI18n()(ManagementJobList); diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx new file mode 100644 index 0000000000..7dd31d4ef0 --- /dev/null +++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { Link } from 'react-router-dom'; +import { + Button, + DataListAction as _DataListAction, + DataListItem, + DataListItemRow, + DataListItemCells, + Tooltip, +} from '@patternfly/react-core'; +import { PencilAltIcon } from '@patternfly/react-icons'; +import styled from 'styled-components'; + +import DataListCell from '../../../components/DataListCell'; + +const DataListAction = styled(_DataListAction)` + align-items: center; + display: grid; + grid-gap: 16px; + grid-template-columns: 40px; +`; + +function ManagementJobListItem({ i18n, isSuperUser, id, name, description }) { + const detailsUrl = `/management_jobs/${id}/details`; + const editUrl = `/management_jobs/${id}/edit`; + const labelId = `mgmt-job-action-${id}`; + + return ( + + + + + {name} + + , + + {i18n._(t`Description:`)} {description} + , + ]} + /> + + {isSuperUser ? ( + + + + ) : null} + + + + ); +} + +export default withI18n()(ManagementJobListItem);