From 8d46d32944f539d4f5364aed626117520873ea7d Mon Sep 17 00:00:00 2001 From: Zita Nemeckova Date: Thu, 16 Feb 2023 12:26:48 +0100 Subject: [PATCH] UI --- awx/ui/src/api/index.js | 3 + awx/ui/src/api/models/HostMetrics.js | 10 +++ awx/ui/src/routeConfig.js | 6 ++ awx/ui/src/screens/HostMetrics/HostMetrics.js | 86 +++++++++++++++++++ .../HostMetrics/HostMetricsListItem.js | 27 ++++++ awx/ui/src/screens/HostMetrics/index.js | 1 + awx/ui/src/types.js | 9 ++ 7 files changed, 142 insertions(+) create mode 100644 awx/ui/src/api/models/HostMetrics.js create mode 100644 awx/ui/src/screens/HostMetrics/HostMetrics.js create mode 100644 awx/ui/src/screens/HostMetrics/HostMetricsListItem.js create mode 100644 awx/ui/src/screens/HostMetrics/index.js diff --git a/awx/ui/src/api/index.js b/awx/ui/src/api/index.js index 5281ad861d..7a03643c05 100644 --- a/awx/ui/src/api/index.js +++ b/awx/ui/src/api/index.js @@ -44,6 +44,7 @@ import WorkflowApprovalTemplates from './models/WorkflowApprovalTemplates'; import WorkflowJobTemplateNodes from './models/WorkflowJobTemplateNodes'; import WorkflowJobTemplates from './models/WorkflowJobTemplates'; import WorkflowJobs from './models/WorkflowJobs'; +import HostMetrics from './models/HostMetrics'; const ActivityStreamAPI = new ActivityStream(); const AdHocCommandsAPI = new AdHocCommands(); @@ -91,6 +92,7 @@ const WorkflowApprovalTemplatesAPI = new WorkflowApprovalTemplates(); const WorkflowJobTemplateNodesAPI = new WorkflowJobTemplateNodes(); const WorkflowJobTemplatesAPI = new WorkflowJobTemplates(); const WorkflowJobsAPI = new WorkflowJobs(); +const HostMetricsAPI = new HostMetrics(); export { ActivityStreamAPI, @@ -139,4 +141,5 @@ export { WorkflowJobTemplateNodesAPI, WorkflowJobTemplatesAPI, WorkflowJobsAPI, + HostMetricsAPI, }; diff --git a/awx/ui/src/api/models/HostMetrics.js b/awx/ui/src/api/models/HostMetrics.js new file mode 100644 index 0000000000..d8ca8f4c8c --- /dev/null +++ b/awx/ui/src/api/models/HostMetrics.js @@ -0,0 +1,10 @@ +import Base from '../Base'; + +class HostMetrics extends Base { + constructor(http) { + super(http); + this.baseUrl = 'api/v2/host_metrics/'; + } +} + +export default HostMetrics; diff --git a/awx/ui/src/routeConfig.js b/awx/ui/src/routeConfig.js index 602e804d2b..c738a352b3 100644 --- a/awx/ui/src/routeConfig.js +++ b/awx/ui/src/routeConfig.js @@ -23,6 +23,7 @@ import TopologyView from 'screens/TopologyView'; import Users from 'screens/User'; import WorkflowApprovals from 'screens/WorkflowApproval'; import { Jobs } from 'screens/Job'; +import HostMetrics from 'screens/HostMetrics'; function getRouteConfig(userProfile = {}) { let routeConfig = [ @@ -55,6 +56,11 @@ function getRouteConfig(userProfile = {}) { path: '/workflow_approvals', screen: WorkflowApprovals, }, + { + title: Host Metrics, + path: '/host_metrics', + screen: HostMetrics, + }, ], }, { diff --git a/awx/ui/src/screens/HostMetrics/HostMetrics.js b/awx/ui/src/screens/HostMetrics/HostMetrics.js new file mode 100644 index 0000000000..0a397dfce3 --- /dev/null +++ b/awx/ui/src/screens/HostMetrics/HostMetrics.js @@ -0,0 +1,86 @@ +import React, {useCallback, useEffect, useState} from 'react'; +import {t} from "@lingui/macro"; +import ScreenHeader from 'components/ScreenHeader/ScreenHeader'; +import { HostMetricsAPI } from 'api'; +import useRequest from 'hooks/useRequest'; +import PaginatedTable, { + HeaderRow, + HeaderCell +} from 'components/PaginatedTable'; +import DataListToolbar from 'components/DataListToolbar'; +import { getQSConfig, parseQueryString } from 'util/qs'; +import {Card, PageSection} from "@patternfly/react-core"; +import { useLocation } from 'react-router-dom'; +import HostMetricsListItem from "./HostMetricsListItem"; + +function HostMetrics() { + + const location = useLocation(); + + const [breadcrumbConfig] = useState({ + '/host_metrics': t`Host Metrics`, + }); + const QS_CONFIG = getQSConfig('host_metrics', { + page: 1, + page_size: 20, + order_by: 'hostname', + }); + const { + result: { count, results }, + isLoading, + error, + request: readHostMetrics, + } = useRequest( + useCallback(async () => { + const params = parseQueryString(QS_CONFIG, location.search); + const list = await HostMetricsAPI.read(params); + return { + count: list.data.count, + results: list.data.results + }; + }, [location.search]), + { results: [], count: 0 } + ); + + useEffect(() => { + readHostMetrics(); + }, [readHostMetrics]); + + return( + <> + + + + ()} + qsConfig={QS_CONFIG} + toolbarSearchColumns={[{name: t`Hostname`, key: 'hostname', isDefault: true}]} + toolbarSearchableKeys={[]} + toolbarRelatedSearchableKeys={[]} + renderToolbar={(props) => } + headerRow={ + + {t`Hostname`} + {t`First automated`} + {t`Last automated`} + {t`Automation`} + {t`Inventories`} + {t`Deleted`} + +} + /> + + + + ); +} + +export default HostMetrics; diff --git a/awx/ui/src/screens/HostMetrics/HostMetricsListItem.js b/awx/ui/src/screens/HostMetrics/HostMetricsListItem.js new file mode 100644 index 0000000000..fe9d06a25c --- /dev/null +++ b/awx/ui/src/screens/HostMetrics/HostMetricsListItem.js @@ -0,0 +1,27 @@ +import 'styled-components/macro'; +import React from 'react'; +import { Tr, Td } from '@patternfly/react-table'; +import { formatDateString } from 'util/dates'; +import { HostMetrics } from 'types'; +import {t} from "@lingui/macro"; + +function HostMetricsListItem({ item }) { + + return ( + + + {item.hostname} + {formatDateString(item.first_automation)} + {formatDateString(item.last_automation)} + {item.automated_counter} + {item.used_in_inventories || 0} + {item.deleted_counter}< + /Tr> + ); +} + +HostMetricsListItem.propTypes = { + item: HostMetrics.isRequired, +}; + +export default HostMetricsListItem; diff --git a/awx/ui/src/screens/HostMetrics/index.js b/awx/ui/src/screens/HostMetrics/index.js new file mode 100644 index 0000000000..bb2945686c --- /dev/null +++ b/awx/ui/src/screens/HostMetrics/index.js @@ -0,0 +1 @@ +export { default } from './HostMetrics'; diff --git a/awx/ui/src/types.js b/awx/ui/src/types.js index 57fd32029d..677f4edae8 100644 --- a/awx/ui/src/types.js +++ b/awx/ui/src/types.js @@ -439,3 +439,12 @@ export const Toast = shape({ hasTimeout: bool, message: string, }); + +export const HostMetrics = shape({ + hostname: string.isRequired, + first_automation: string.isRequired, + last_automation: string.isRequired, + automated_counter: number.isRequired, + used_in_inventories: number, + deleted_counter: number, +});