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);