From 29eab7715362537c00cc1348a6386b36cc96ade8 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Mon, 4 Oct 2021 12:10:43 +0200 Subject: [PATCH 01/71] Accidentally cleaned up the scss file --- src/App.scss | 61 ------------------------ src/Containers/Clusters/ModulesList.js | 1 + src/Containers/Clusters/TemplatesList.js | 1 + 3 files changed, 2 insertions(+), 61 deletions(-) diff --git a/src/App.scss b/src/App.scss index f02c1569d..d0789feca 100644 --- a/src/App.scss +++ b/src/App.scss @@ -7,60 +7,11 @@ * CONSIDER when styling using the styled components instead of this file. * At this project we prefer to use the styled components. * ***********************************************************************/ - -.pf-c-data-list__cell { - --pf-c-data-list__cell--PaddingBottom: 10px; -} - -.dataCard { - .pf-c-data-list { - flex: 1; - margin-right: 0; - } - - ul + ul { - margin-left: 20px; - } -} - -.pf-c-modal-box.templateModal { - --pf-c-modal-box--Width: 1000px; - - .pf-c-table { - --pf-c-table-td--PaddingBottom: 20px; - --pf-c-table-td--PaddingTop: 20px; - th:first-child, - td:first-child { - padding-left: 0; - } - - th:last-child, - td:last-child { - padding-right: 20px; - text-align: right; - } - } -} - -@media only screen and (max-width: 600px) { - .dataCard { - flex-direction: column; - - .pf-c-data-list { - margin: 20px 0 0 0; - } - } -} - #d3-donut-1-chart-root, #d3-donut-2-chart-root { min-height: 300px; min-width: 60%; } -h2 { - color: #393f44; -} - #d3-grouped-bar-chart-root, #d3-line-chart-root, #d3-bar-chart-root, #d3-pie-1-chart-root, #d3-roi-chart-root { min-height: 450px; min-width: 75%; @@ -70,18 +21,6 @@ h2 { overflow-x: auto; } -#fail-icon { - position: absolute; - left: 21px; - top: 20px; - color: white; - font-size: 14px; -} - -section#refTab1Section, section#refTab2Section { - outline: none; -} - #d3-bar-chart-root rect:hover { cursor: pointer; } diff --git a/src/Containers/Clusters/ModulesList.js b/src/Containers/Clusters/ModulesList.js index b07ffe8d7..d4811772b 100644 --- a/src/Containers/Clusters/ModulesList.js +++ b/src/Containers/Clusters/ModulesList.js @@ -13,6 +13,7 @@ import { const DataListCell = styled(PFDataListCell)` --pf-c-data-list__cell-cell--MarginRight: 0; + --pf-c-data-list__cell--PaddingBottom: 10px; `; const DataListItem = styled(PFDataListItem)` diff --git a/src/Containers/Clusters/TemplatesList.js b/src/Containers/Clusters/TemplatesList.js index fb4617d27..ee79ce228 100644 --- a/src/Containers/Clusters/TemplatesList.js +++ b/src/Containers/Clusters/TemplatesList.js @@ -14,6 +14,7 @@ import ModalContents from './ModalContents'; const DataListCell = styled(PFDataListCell)` --pf-c-data-list__cell-cell--MarginRight: 0; + --pf-c-data-list__cell--PaddingBottom: 10px; `; const DataListItem = styled(PFDataListItem)` From 3de262c53b284b215902142067ce10a38e30b382 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Wed, 6 Oct 2021 09:50:48 -0400 Subject: [PATCH 02/71] Fixed default sort by field in report --- src/Containers/Reports/Shared/schemas/templates_explorer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Containers/Reports/Shared/schemas/templates_explorer.ts b/src/Containers/Reports/Shared/schemas/templates_explorer.ts index ff0090724..2085d1636 100644 --- a/src/Containers/Reports/Shared/schemas/templates_explorer.ts +++ b/src/Containers/Reports/Shared/schemas/templates_explorer.ts @@ -65,7 +65,7 @@ const defaultParams: Params = { group_by_time: false, granularity: 'monthly', quick_date_range: 'last_6_months', - sort_options: 'host_count', + sort_options: 'total_count', sort_order: 'desc', cluster_id: [], inventory_id: [], From 9ee920799fb4ac48bf6cabcb4cf6e397213eb2fb Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 6 Oct 2021 12:18:23 +0200 Subject: [PATCH 03/71] Correct types for API and useRequest --- src/Api/types.ts | 7 ++++++- src/Containers/Notifications/Notifications.tsx | 8 ++------ src/Utilities/useRequest.ts | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Api/types.ts b/src/Api/types.ts index bf1abde29..3029adc99 100644 --- a/src/Api/types.ts +++ b/src/Api/types.ts @@ -2,7 +2,12 @@ export type Params = Record< string, string | number | string[] | number[] | boolean >; -export type ApiJson = Record; + +export type OptionsReturnType = Record< + string, + { key: string; value: string }[] +>; +export type ApiJson = Record | OptionsReturnType; export interface ParamsWithPagination { limit?: string | number; diff --git a/src/Containers/Notifications/Notifications.tsx b/src/Containers/Notifications/Notifications.tsx index 706aac5ca..b9c5f88a5 100644 --- a/src/Containers/Notifications/Notifications.tsx +++ b/src/Containers/Notifications/Notifications.tsx @@ -149,15 +149,11 @@ const Notifications: FC> = () => { useEffect(() => { // TODO: Update the useRequest hook to return function and not a promise!! @brum - fetchClusters() - .then(() => ({})) - .catch(() => ({})); + fetchClusters(); }, []); useEffect(() => { - fetchNotifications() - .then(() => ({})) - .catch(() => ({})); + fetchNotifications(); }, [queryParams]); return ( diff --git a/src/Utilities/useRequest.ts b/src/Utilities/useRequest.ts index 537bbb971..15d6a2b82 100644 --- a/src/Utilities/useRequest.ts +++ b/src/Utilities/useRequest.ts @@ -24,7 +24,7 @@ interface UseRequestVariables { } interface UseRequestReturn extends UseRequestVariables { - request: () => Promise; + request: () => void; setValue: (value: T) => void; } @@ -118,7 +118,7 @@ export const useDismissableError = ( */ interface UseDeleteItemsReturn { isLoading: boolean; - deleteItems: () => Promise; + deleteItems: () => void; deletionError: ErrorType; clearDeletionError: () => void; } From 7eef28b1b8ce102786bc29d4a0592ce9dc45b447 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 6 Oct 2021 13:26:52 +0200 Subject: [PATCH 04/71] Reports page refactor for future devel with TS in mind --- .../Reports/Details/Components/Chart.tsx | 35 +++ .../{Report.tsx => Components/ReportCard.tsx} | 120 +++++------ .../Table}/TableExpandedRow.tsx | 200 +++++++++--------- .../Details/Components/Table/TableRow.tsx | 88 ++++++++ .../Details/Components/Table/index.tsx | 59 ++++++ .../Reports/Details/Components/index.ts | 3 + .../Reports/Details/Components/types.ts | 12 ++ src/Containers/Reports/Details/Details.tsx | 25 ++- .../Details/ReportTable/ReportTable.tsx | 85 -------- .../Reports/Details/ReportTable/TableRow.tsx | 105 --------- .../Reports/Details/ReportTable/index.tsx | 3 - .../Reports/Shared/schemas/index.ts | 1 + .../Shared/schemas/templates_explorer.ts | 4 +- 13 files changed, 373 insertions(+), 367 deletions(-) create mode 100644 src/Containers/Reports/Details/Components/Chart.tsx rename src/Containers/Reports/Details/{Report.tsx => Components/ReportCard.tsx} (62%) rename src/Containers/Reports/Details/{ReportTable => Components/Table}/TableExpandedRow.tsx (51%) create mode 100644 src/Containers/Reports/Details/Components/Table/TableRow.tsx create mode 100644 src/Containers/Reports/Details/Components/Table/index.tsx create mode 100644 src/Containers/Reports/Details/Components/index.ts create mode 100644 src/Containers/Reports/Details/Components/types.ts delete mode 100644 src/Containers/Reports/Details/ReportTable/ReportTable.tsx delete mode 100644 src/Containers/Reports/Details/ReportTable/TableRow.tsx delete mode 100644 src/Containers/Reports/Details/ReportTable/index.tsx diff --git a/src/Containers/Reports/Details/Components/Chart.tsx b/src/Containers/Reports/Details/Components/Chart.tsx new file mode 100644 index 000000000..dbd2175af --- /dev/null +++ b/src/Containers/Reports/Details/Components/Chart.tsx @@ -0,0 +1,35 @@ +import React, { FunctionComponent } from 'react'; +import ChartBuilder, { + ApiReturnType, + ChartSchemaElement, + functions, +} from 'react-json-chart-builder'; + +const customFunctions = (data: ApiReturnType) => ({ + ...functions, + axisFormat: { + ...functions.axisFormat, + formatAsYear: (tick: string | number) => + Intl.DateTimeFormat('en', { year: 'numeric' }).format(new Date(tick)), + formatAsMonth: (tick: string | number) => + Intl.DateTimeFormat('en', { month: 'long' }).format(new Date(tick)), + }, + fetchFnc: () => + new Promise((resolve) => { + resolve(data); + }), +}); + +interface Props { + schema: ChartSchemaElement[]; + data: ApiReturnType; +} + +const Chart: FunctionComponent = ({ schema, data }) => ( + +); + +export default Chart; diff --git a/src/Containers/Reports/Details/Report.tsx b/src/Containers/Reports/Details/Components/ReportCard.tsx similarity index 62% rename from src/Containers/Reports/Details/Report.tsx rename to src/Containers/Reports/Details/Components/ReportCard.tsx index f4473d7ab..25fa0c5f6 100644 --- a/src/Containers/Reports/Details/Report.tsx +++ b/src/Containers/Reports/Details/Components/ReportCard.tsx @@ -1,8 +1,5 @@ -/* eslint-disable @typescript-eslint/no-floating-promises */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import React, { @@ -20,19 +17,20 @@ import { PaginationVariant, } from '@patternfly/react-core'; -import Pagination from '../../../Components/Pagination'; +import Pagination from '../../../../Components/Pagination'; -import { useQueryParams } from '../../../QueryParams/'; +import { useQueryParams } from '../../../../QueryParams'; -import useRequest from '../../../Utilities/useRequest'; +import useRequest from '../../../../Utilities/useRequest'; -import ApiStatusWrapper from '../../../Components/ApiStatus/ApiStatusWrapper'; -import FilterableToolbar from '../../../Components/Toolbar/Toolbar'; +import ApiStatusWrapper from '../../../../Components/ApiStatus/ApiStatusWrapper'; +import FilterableToolbar from '../../../../Components/Toolbar/Toolbar'; -import { AttributesType, ReportGeneratorParams } from '../Shared/types'; -import ReportTable from './ReportTable'; -import DownloadPdfButton from '../../../Components/Toolbar/DownloadPdfButton'; -import { useFeatureFlag, ValidFeatureFlags } from '../../../FeatureFlags'; +import { AttributesType, ReportGeneratorParams } from '../../Shared/types'; +import { Chart, Table } from './'; +import DownloadPdfButton from '../../../../Components/Toolbar/DownloadPdfButton'; +import { useFeatureFlag, ValidFeatureFlags } from '../../../../FeatureFlags'; +import { OptionsReturnType } from '../../../../Api'; const CardBody = styled(PFCardBody)` & .pf-c-toolbar, @@ -52,9 +50,10 @@ const getDateFormatByGranularity = (granularity: string): string => { if (granularity === 'yearly') return 'formatAsYear'; if (granularity === 'monthly') return 'formatAsMonth'; if (granularity === 'daily') return 'formatDateAsDayMonth'; + return ''; }; -const Report: FunctionComponent = ({ +const ReportCard: FunctionComponent = ({ slug, defaultParams, extraAttributes, @@ -73,15 +72,17 @@ const Report: FunctionComponent = ({ const { request: setData, ...dataApi } = useRequest( useCallback(() => readData(queryParams), [queryParams]), - {} + { meta: { count: 0, legend: [] } } ); - const { result: options, request: setOptions } = useRequest( - useCallback(() => readOptions(queryParams), [queryParams]), - {} - ); + const { result: options, request: setOptions } = + useRequest( + () => readOptions(queryParams) as Promise, + {} + ); const [attrPairs, setAttrPairs] = useState([]); + useEffect(() => { if (listAttributes && options.sort_options) { const attrsList = options.sort_options.filter(({ key }) => @@ -101,27 +102,21 @@ const Report: FunctionComponent = ({ xTickFormat: getDateFormatByGranularity(queryParams.granularity), }; - const chartSchema = schemaFnc( - chartParams.label, - chartParams.y, - chartParams.xTickFormat - ); - useEffect(() => { setData(); setOptions(); }, [queryParams]); - const onSort = ( - _event: unknown, - index: number, - direction: 'asc' | 'desc' - ) => { - setFromToolbar('sort_order', direction); - setFromToolbar('sort_options', attrPairs[index]?.key); - }; - const getSortParams = (currKey: string) => { + const onSort = ( + _event: unknown, + index: number, + direction: 'asc' | 'desc' + ) => { + setFromToolbar('sort_order', direction); + setFromToolbar('sort_options', attrPairs[index]?.key); + }; + const whitelistKeys = options?.sort_options?.map( ({ key }: { key: string }) => key ); @@ -142,6 +137,19 @@ const Report: FunctionComponent = ({ }; }; + const additionalControls = pdfDownloadEnabled + ? [ + , + ] + : []; + return ( @@ -151,50 +159,44 @@ const Report: FunctionComponent = ({ setFilters={setFromToolbar} pagination={ } - additionalControls={ - pdfDownloadEnabled - ? [ - , - ] - : [] - } + additionalControls={additionalControls} /> {attrPairs && ( - + )} = ({ ); }; -export default Report; +export default ReportCard; diff --git a/src/Containers/Reports/Details/ReportTable/TableExpandedRow.tsx b/src/Containers/Reports/Details/Components/Table/TableExpandedRow.tsx similarity index 51% rename from src/Containers/Reports/Details/ReportTable/TableExpandedRow.tsx rename to src/Containers/Reports/Details/Components/Table/TableExpandedRow.tsx index 68f884372..af4f9c296 100644 --- a/src/Containers/Reports/Details/ReportTable/TableExpandedRow.tsx +++ b/src/Containers/Reports/Details/Components/Table/TableExpandedRow.tsx @@ -1,3 +1,10 @@ +/** + * TODO: This file is super specific to the data set, it is not reusable at all. + * TODO: The types could be specified if I would be more confortable with the + * data set this is developed for. The Brekadown component is not TS, which + * is preventing the typescript compiler from compiling this component. + */ + /* eslint-disable @typescript-eslint/no-floating-promises */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ @@ -20,9 +27,9 @@ import { } from '@patternfly/react-core'; import { ExpandableRowContent, Td, Tr as PFTr } from '@patternfly/react-table'; -import { ReportGeneratorParams } from '../../Shared/types'; -import Breakdown from '../../../../Charts/Breakdown'; -import { categoryColor } from '../../../../Utilities/constants'; +import Breakdown from '../../../../../Charts/Breakdown'; +import { categoryColor } from '../../../../../Utilities/constants'; +import { LegendEntry } from '../types'; const Tr = styled(PFTr)` & td:first-child { @@ -30,40 +37,42 @@ const Tr = styled(PFTr)` } `; -const renderExpandedRow = (expanded, item) => { - const totalCount = (item) => - item - ? { - ok: item?.successful_count ?? 0, - skipped: item?.skipped_count ?? 0, - failed: item?.failed_count ?? 0, - error: item?.error_count ?? 0, - } - : null; +interface Props { + isExpanded: boolean; + item: LegendEntry; +} + +const TableExpandedRow: FunctionComponent = ({ isExpanded, item }) => { + const totalCount = item + ? { + ok: item?.successful_count ?? 0, + skipped: item?.skipped_count ?? 0, + failed: item?.failed_count ?? 0, + error: item?.error_count ?? 0, + } + : null; - const totalTaskCount = (item) => - item - ? { - ok: item?.average_host_task_ok_count_per_host ?? 0, - skipped: item?.average_host_task_skipped_count_per_host ?? 0, - changed: item?.average_host_task_changed_count_per_host ?? 0, - failed: item?.average_host_task_failed_count_per_host ?? 0, - unreachable: item?.average_host_task_unreachable_count_per_host ?? 0, - } - : null; + const totalTaskCount = item + ? { + ok: item?.average_host_task_ok_count_per_host ?? 0, + skipped: item?.average_host_task_skipped_count_per_host ?? 0, + changed: item?.average_host_task_changed_count_per_host ?? 0, + failed: item?.average_host_task_failed_count_per_host ?? 0, + unreachable: item?.average_host_task_unreachable_count_per_host ?? 0, + } + : null; - const totalHostCount = (item) => - item - ? { - ok: item?.ok_host_count ?? 0, - skipped: item?.skipped_host_count ?? 0, - changed: item?.changed_host_count ?? 0, - failed: item?.failed_host_count ?? 0, - unreachable: item?.unreachable_host_count ?? 0, - } - : null; + const totalHostCount = item + ? { + ok: item?.ok_host_count ?? 0, + skipped: item?.skipped_host_count ?? 0, + changed: item?.changed_host_count ?? 0, + failed: item?.failed_host_count ?? 0, + unreachable: item?.unreachable_host_count ?? 0, + } + : null; - const taskInfo = (task) => { + const taskInfo = (task: any) => { return [ { label: 'Task name', @@ -76,7 +85,7 @@ const renderExpandedRow = (expanded, item) => { ]; }; - const total_host_status_count = (task) => { + const totalHostStatusCount = (task: any) => { return ( parseInt(task.passed_host_count) + parseInt(task.failed_host_count) + @@ -84,7 +93,7 @@ const renderExpandedRow = (expanded, item) => { ); }; - const total_task_status_count = (task) => { + const totalTaskStatusCount = (task: any) => { return ( parseInt(task.successful_count) + parseInt(task.failed_count) + @@ -92,7 +101,7 @@ const renderExpandedRow = (expanded, item) => { ); }; - const renderFailedTaskBar = (item) => { + const renderFailedTaskBar = (item: any) => { const failed_tasks = item.most_failed_tasks; if (failed_tasks != null) { return ( @@ -104,7 +113,7 @@ const renderExpandedRow = (expanded, item) => { {failed_tasks .slice(0, failed_tasks.length) - .map((task, idx: number) => { + .map((task: any, idx: number) => { const hostCount = { passed: task?.passed_host_count ?? 0, failed: task?.failed_host_count ?? 0, @@ -116,56 +125,54 @@ const renderExpandedRow = (expanded, item) => { unfinished: task?.unfinished_count ?? 0, }; return ( - <> - - - - {taskInfo(task).map(({ label, value }) => ( - - {label} - - {value} - - - ))} - - - - - - Host status - - - Hosts - {' '} - {total_host_status_count(task)} - - - Task status - - - Tasks - {' '} - {total_task_status_count(task)} - - - - - - - - - - - + + + + {taskInfo(task).map(({ label, value }) => ( + + {label} + + {value} + + + ))} + + + + + + Host status + + + Hosts + {' '} + {totalHostStatusCount(task)} + + + Task status + + + Tasks + {' '} + {totalTaskStatusCount(task)} + + + + + + + + + + ); })} @@ -174,7 +181,7 @@ const renderExpandedRow = (expanded, item) => { } }; - const expandedInfo = (item) => { + const expandedInfo = (item: any) => { return [ { label: 'Clusters', @@ -188,7 +195,7 @@ const renderExpandedRow = (expanded, item) => { }; return ( - s.id === item.id)}> + + {headers.map(({ key }, index) => ( + <> + {expandRows && index === 0 && ( + + + ))} + + {expandRows && ( + + )} + + ); +}; + +export default TableRow; diff --git a/src/Containers/Reports/Details/Components/Table/index.tsx b/src/Containers/Reports/Details/Components/Table/index.tsx new file mode 100644 index 000000000..3a1d72e0a --- /dev/null +++ b/src/Containers/Reports/Details/Components/Table/index.tsx @@ -0,0 +1,59 @@ +import React, { FunctionComponent } from 'react'; +import styled from 'styled-components'; + +import { + TableComposable, + TableVariant, + Tbody, + Th, + Thead, + Tr as PFTr, +} from '@patternfly/react-table'; + +import TableRow from './TableRow'; +import { LegendEntry, TableHeaders, TableSortParams } from '../types'; + +const Tr = styled(PFTr)` + & td:first-child { + width: 50px; + } +`; + +interface Props { + headers: TableHeaders; + legend: LegendEntry[]; + expandRows: boolean; + getSortParams: (currKey: string) => TableSortParams; +} + +const ReportTable: FunctionComponent = ({ + legend, + headers, + getSortParams, + expandRows, +}) => ( + + + + {expandRows && } + {headers.map(({ key, value }) => ( + + ))} + + + + {legend.map((entry) => ( + + ))} + + +); + +export default ReportTable; diff --git a/src/Containers/Reports/Details/Components/index.ts b/src/Containers/Reports/Details/Components/index.ts new file mode 100644 index 000000000..e764bbc73 --- /dev/null +++ b/src/Containers/Reports/Details/Components/index.ts @@ -0,0 +1,3 @@ +export { default as Table } from './Table'; +export { default as Chart } from './Chart'; +export { default as ReportCard } from './ReportCard'; diff --git a/src/Containers/Reports/Details/Components/types.ts b/src/Containers/Reports/Details/Components/types.ts new file mode 100644 index 000000000..24c09403c --- /dev/null +++ b/src/Containers/Reports/Details/Components/types.ts @@ -0,0 +1,12 @@ +export type LegendEntry = Record; +export type TableHeaders = { key: string; value: string }[]; +export type TableSortParams = { + sort?: { + sortBy: { + index: number; + direction: 'asc' | 'desc'; + }; + onSort: (_event: unknown, index: number, direction: 'asc' | 'desc') => void; + columnIndex: number; + }; +}; diff --git a/src/Containers/Reports/Details/Details.tsx b/src/Containers/Reports/Details/Details.tsx index 5126ea8f4..ad59028fa 100644 --- a/src/Containers/Reports/Details/Details.tsx +++ b/src/Containers/Reports/Details/Details.tsx @@ -1,7 +1,6 @@ import React, { FunctionComponent } from 'react'; import { useParams } from 'react-router-dom'; import styled from 'styled-components'; -import { Card } from '@patternfly/react-core'; import Main from '@redhat-cloud-services/frontend-components/Main'; import Error404 from '../../../Components/Error404'; @@ -12,7 +11,7 @@ import { import Breadcrumbs from '../../../Components/Breadcrumbs'; -import Report from './Report'; +import { ReportCard } from './Components/'; import { getReport } from '../Shared/schemas'; import paths from '../paths'; @@ -28,16 +27,7 @@ const Details: FunctionComponent> = () => { const breadcrumbsItems = [{ title: 'Reports', navigate: paths.get }]; const render = () => { - if (!name) - return ( - - ); - else + if (report) return ( <> @@ -46,10 +36,19 @@ const Details: FunctionComponent> = () => { {description}
- {report && } +
); + else + return ( + + ); }; return render(); diff --git a/src/Containers/Reports/Details/ReportTable/ReportTable.tsx b/src/Containers/Reports/Details/ReportTable/ReportTable.tsx deleted file mode 100644 index c4840c597..000000000 --- a/src/Containers/Reports/Details/ReportTable/ReportTable.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* eslint-disable @typescript-eslint/no-floating-promises */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -import React, { FunctionComponent } from 'react'; -import styled from 'styled-components'; - -import ChartBuilder, { - ApiReturnType, - functions, -} from 'react-json-chart-builder'; - -import { - TableComposable, - TableVariant, - Th, - Thead, - Tr as PFTr, -} from '@patternfly/react-table'; - -import EmptyList from '../../../../Components/EmptyList'; -import TableRow from './TableRow'; - -const Tr = styled(PFTr)` - & td:first-child { - width: 50px; - } -`; - -const customFunctions = (data: ApiReturnType) => ({ - ...functions, - axisFormat: { - ...functions.axisFormat, - formatAsYear: (tick: string) => - Intl.DateTimeFormat('en', { year: 'numeric' }).format(new Date(tick)), - formatAsMonth: (tick: string) => - Intl.DateTimeFormat('en', { month: 'long' }).format(new Date(tick)), - }, - fetchFnc: () => - new Promise((resolve) => { - resolve(data); - }), -}); - -const ReportTable: FunctionComponent = ({ - dataApi, - chartSchema, - attrPairs, - getSortParams, - expandRows, -}) => { - if (dataApi.isSuccess && dataApi.result.meta?.count === 0) - return ; - - return ( - <> - - -
- - {expandRows && } - {attrPairs.map(({ key, value }) => ( - - ))} - - - - - - ); -}; - -export default ReportTable; diff --git a/src/Containers/Reports/Details/ReportTable/TableRow.tsx b/src/Containers/Reports/Details/ReportTable/TableRow.tsx deleted file mode 100644 index 0f1e692ac..000000000 --- a/src/Containers/Reports/Details/ReportTable/TableRow.tsx +++ /dev/null @@ -1,105 +0,0 @@ -/* eslint-disable @typescript-eslint/no-floating-promises */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -import React, { FunctionComponent, useState } from 'react'; -import styled from 'styled-components'; -import { global_disabled_color_300 } from '@patternfly/react-tokens'; - -import { Tbody, Td, Tr as PFTr } from '@patternfly/react-table'; -import { formatTotalTime } from '../../../../Utilities/helpers'; - -import currencyFormatter from '../../../../Utilities/currencyFormatter'; - -import { ReportGeneratorParams } from '../Shared/types'; -import TableExpandedRow from './TableExpandedRow'; - -const Tr = styled(PFTr)` - & td:first-child { - width: 50px; - } -`; - -const timeFields: string[] = ['elapsed']; -const costFields: string[] = []; - -const isOther = (item: Record, key: string) => - key === 'id' && item[key] === -1; - -const isNoName = (item: Record, key: string) => - key === 'id' && item[key] === -2; - -const getText = ( - item: Record, - key: string -): string => { - if (isNoName(item, key)) return '-'; - if (isOther(item, key)) return '-'; - if (timeFields.includes(key)) return formatTotalTime(item[key]); - if (costFields.includes(key)) return currencyFormatter(+item[key]); - // TODO: Remove no name when api does not return empty values - // https://issues.redhat.com/browse/AA-691 - return `${item[key]}` || 'No name'; -}; - -const getOthersStyle = (item: Record, key: string) => { - if (isOther(item, key)) { - return { - backgroundColor: global_disabled_color_300.value, - }; - } - return {}; -}; - -const renderRow = (dataApi, attrPairs, expandRows) => { - const [expanded, setExpanded] = useState([]); - const handleExpansion = (row) => { - if (expanded.some((s) => s.id === row.id)) { - setExpanded((prevState) => [...prevState.filter((i) => i.id !== row.id)]); - } else { - setExpanded((prevState) => [...prevState, row]); - } - }; - - return ( - - {dataApi.result.meta?.legend.map( - (item: Record) => ( - <> - - {attrPairs.map(({ key, value }, index) => ( - <> - {expandRows && index === 0 && ( - - - ))} - - {expandRows && } - - ) - )} - - ); -}; - -const TableRow: FunctionComponent = ({ - dataApi, - attrPairs, - expandRows, -}) => { - return renderRow(dataApi, attrPairs, expandRows); -}; - -export default TableRow; diff --git a/src/Containers/Reports/Details/ReportTable/index.tsx b/src/Containers/Reports/Details/ReportTable/index.tsx deleted file mode 100644 index e1ba9f29b..000000000 --- a/src/Containers/Reports/Details/ReportTable/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import ReportTable from './ReportTable'; - -export default ReportTable; diff --git a/src/Containers/Reports/Shared/schemas/index.ts b/src/Containers/Reports/Shared/schemas/index.ts index d65dbfd36..8e3bbe725 100644 --- a/src/Containers/Reports/Shared/schemas/index.ts +++ b/src/Containers/Reports/Shared/schemas/index.ts @@ -13,6 +13,7 @@ const defaultReport: ReportPageParams = { name: '', description: '', categories: [] as string[], + report: undefined, }; const flaggedReports = [ diff --git a/src/Containers/Reports/Shared/schemas/templates_explorer.ts b/src/Containers/Reports/Shared/schemas/templates_explorer.ts index 2085d1636..6b8e64e97 100644 --- a/src/Containers/Reports/Shared/schemas/templates_explorer.ts +++ b/src/Containers/Reports/Shared/schemas/templates_explorer.ts @@ -154,8 +154,8 @@ const reportParams: ReportPageParams = { slug, defaultParams, extraAttributes, - expandRows: expandRows, - listAttributes: listAttributes, + expandRows, + listAttributes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, From 260a3477f228af0b858dcca135780e97805ccfd0 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 6 Oct 2021 15:46:55 +0200 Subject: [PATCH 05/71] Removed the custom styling on the first row It caused inconsistencies with the tables that had expand options --- .../Components/Table/TableExpandedRow.tsx | 9 +-------- .../Details/Components/Table/TableRow.tsx | 9 +-------- .../Reports/Details/Components/Table/index.tsx | 17 +++++------------ 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/src/Containers/Reports/Details/Components/Table/TableExpandedRow.tsx b/src/Containers/Reports/Details/Components/Table/TableExpandedRow.tsx index af4f9c296..3b9cdd90c 100644 --- a/src/Containers/Reports/Details/Components/Table/TableExpandedRow.tsx +++ b/src/Containers/Reports/Details/Components/Table/TableExpandedRow.tsx @@ -13,7 +13,6 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import React, { FunctionComponent } from 'react'; -import styled from 'styled-components'; import { DescriptionList, DescriptionListDescription, @@ -25,18 +24,12 @@ import { Grid, GridItem, } from '@patternfly/react-core'; -import { ExpandableRowContent, Td, Tr as PFTr } from '@patternfly/react-table'; +import { ExpandableRowContent, Td, Tr } from '@patternfly/react-table'; import Breakdown from '../../../../../Charts/Breakdown'; import { categoryColor } from '../../../../../Utilities/constants'; import { LegendEntry } from '../types'; -const Tr = styled(PFTr)` - & td:first-child { - width: 50px; - } -`; - interface Props { isExpanded: boolean; item: LegendEntry; diff --git a/src/Containers/Reports/Details/Components/Table/TableRow.tsx b/src/Containers/Reports/Details/Components/Table/TableRow.tsx index 5650dca0c..2d9be0dce 100644 --- a/src/Containers/Reports/Details/Components/Table/TableRow.tsx +++ b/src/Containers/Reports/Details/Components/Table/TableRow.tsx @@ -1,8 +1,7 @@ import React, { FunctionComponent, useState } from 'react'; -import styled from 'styled-components'; import { global_disabled_color_300 } from '@patternfly/react-tokens'; -import { Td, Tr as PFTr } from '@patternfly/react-table'; +import { Td, Tr } from '@patternfly/react-table'; import { formatTotalTime } from '../../../../../Utilities/helpers'; import currencyFormatter from '../../../../../Utilities/currencyFormatter'; @@ -10,12 +9,6 @@ import currencyFormatter from '../../../../../Utilities/currencyFormatter'; import TableExpandedRow from './TableExpandedRow'; import { LegendEntry, TableHeaders } from '../types'; -const Tr = styled(PFTr)` - & td:first-child { - width: 50px; - } -`; - const timeFields: string[] = ['elapsed']; const costFields: string[] = []; diff --git a/src/Containers/Reports/Details/Components/Table/index.tsx b/src/Containers/Reports/Details/Components/Table/index.tsx index 3a1d72e0a..c2b5ef495 100644 --- a/src/Containers/Reports/Details/Components/Table/index.tsx +++ b/src/Containers/Reports/Details/Components/Table/index.tsx @@ -1,5 +1,4 @@ import React, { FunctionComponent } from 'react'; -import styled from 'styled-components'; import { TableComposable, @@ -7,30 +6,24 @@ import { Tbody, Th, Thead, - Tr as PFTr, + Tr, } from '@patternfly/react-table'; import TableRow from './TableRow'; import { LegendEntry, TableHeaders, TableSortParams } from '../types'; -const Tr = styled(PFTr)` - & td:first-child { - width: 50px; - } -`; - interface Props { headers: TableHeaders; legend: LegendEntry[]; - expandRows: boolean; - getSortParams: (currKey: string) => TableSortParams; + expandRows?: boolean; + getSortParams?: (currKey: string) => TableSortParams; } const ReportTable: FunctionComponent = ({ legend, headers, - getSortParams, - expandRows, + getSortParams = () => ({}), + expandRows = false, }) => ( From b23002a8b183d50e7e8bec35cfce6f3dfd9a5144 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Thu, 7 Oct 2021 12:11:29 +0200 Subject: [PATCH 06/71] Updated the naming for reability --- .../Reports/Details/Components/ReportCard.tsx | 55 ++++++++----------- .../Shared/schemas/affectedHostsByPlaybook.ts | 23 +++++--- .../Reports/Shared/schemas/changesMade.ts | 30 ++++++---- .../Shared/schemas/hostsByOrganizations.ts | 23 +++++--- .../Reports/Shared/schemas/index.ts | 4 +- .../Shared/schemas/jobsTasksByOrganization.ts | 20 ++++--- .../Reports/Shared/schemas/playbookRunRate.ts | 20 ++++--- ...lates_explorer.ts => templatesExplorer.ts} | 20 +++---- src/Containers/Reports/Shared/types.ts | 6 +- 9 files changed, 112 insertions(+), 89 deletions(-) rename src/Containers/Reports/Shared/schemas/{templates_explorer.ts => templatesExplorer.ts} (93%) diff --git a/src/Containers/Reports/Details/Components/ReportCard.tsx b/src/Containers/Reports/Details/Components/ReportCard.tsx index 25fa0c5f6..0286dbc0f 100644 --- a/src/Containers/Reports/Details/Components/ReportCard.tsx +++ b/src/Containers/Reports/Details/Components/ReportCard.tsx @@ -2,12 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck -import React, { - FunctionComponent, - useCallback, - useEffect, - useState, -} from 'react'; +import React, { FunctionComponent, useCallback, useEffect } from 'react'; import styled from 'styled-components'; import { @@ -26,7 +21,7 @@ import useRequest from '../../../../Utilities/useRequest'; import ApiStatusWrapper from '../../../../Components/ApiStatus/ApiStatusWrapper'; import FilterableToolbar from '../../../../Components/Toolbar/Toolbar'; -import { AttributesType, ReportGeneratorParams } from '../../Shared/types'; +import { ReportGeneratorParams } from '../../Shared/types'; import { Chart, Table } from './'; import DownloadPdfButton from '../../../../Components/Toolbar/DownloadPdfButton'; import { useFeatureFlag, ValidFeatureFlags } from '../../../../FeatureFlags'; @@ -56,12 +51,12 @@ const getDateFormatByGranularity = (granularity: string): string => { const ReportCard: FunctionComponent = ({ slug, defaultParams, - extraAttributes, + defaultTableHeaders, + tableAttributes, + expandedAttributes, readData, readOptions, schemaFnc, - expandRows, - listAttributes, }) => { const pdfDownloadEnabled = useFeatureFlag( ValidFeatureFlags.pdfDownloadButton @@ -78,21 +73,20 @@ const ReportCard: FunctionComponent = ({ const { result: options, request: setOptions } = useRequest( () => readOptions(queryParams) as Promise, - {} + { sort_options: [] } ); - const [attrPairs, setAttrPairs] = useState([]); - useEffect(() => { - if (listAttributes && options.sort_options) { - const attrsList = options.sort_options.filter(({ key }) => - listAttributes.includes(key) - ); - setAttrPairs([...extraAttributes, ...attrsList]); - } else if (options.sort_options) { - setAttrPairs([...extraAttributes, ...options.sort_options]); - } - }, [options, extraAttributes]); + setData(); + setOptions(); + }, [queryParams]); + + const tableHeaders = [ + ...defaultTableHeaders, + ...(tableAttributes + ? options.sort_options.filter(({ key }) => tableAttributes.includes(key)) + : options.sort_options), + ]; const chartParams = { y: queryParams.sort_options as string, @@ -102,11 +96,6 @@ const ReportCard: FunctionComponent = ({ xTickFormat: getDateFormatByGranularity(queryParams.granularity), }; - useEffect(() => { - setData(); - setOptions(); - }, [queryParams]); - const getSortParams = (currKey: string) => { const onSort = ( _event: unknown, @@ -114,7 +103,7 @@ const ReportCard: FunctionComponent = ({ direction: 'asc' | 'desc' ) => { setFromToolbar('sort_order', direction); - setFromToolbar('sort_options', attrPairs[index]?.key); + setFromToolbar('sort_options', tableHeaders[index]?.key); }; const whitelistKeys = options?.sort_options?.map( @@ -126,13 +115,13 @@ const ReportCard: FunctionComponent = ({ sort: { sortBy: { index: - attrPairs.findIndex( + tableHeaders.findIndex( ({ key }) => key === queryParams.sort_options ) || 0, direction: queryParams.sort_order || 'none', }, onSort, - columnIndex: attrPairs.findIndex(({ key }) => key === currKey), + columnIndex: tableHeaders.findIndex(({ key }) => key === currKey), }, }; }; @@ -171,7 +160,7 @@ const ReportCard: FunctionComponent = ({ } additionalControls={additionalControls} /> - {attrPairs && ( + {tableHeaders && ( = ({ />
@@ -202,7 +209,7 @@ const renderExpandedRow = (expanded, item) => { @@ -218,7 +225,7 @@ const renderExpandedRow = (expanded, item) => { @@ -234,7 +241,7 @@ const renderExpandedRow = (expanded, item) => { @@ -260,11 +267,4 @@ const renderExpandedRow = (expanded, item) => { ); }; -const TableExpandedRow: FunctionComponent = ({ - expanded, - item, -}) => { - return renderExpandedRow(expanded, item); -}; - export default TableExpandedRow; diff --git a/src/Containers/Reports/Details/Components/Table/TableRow.tsx b/src/Containers/Reports/Details/Components/Table/TableRow.tsx new file mode 100644 index 000000000..5650dca0c --- /dev/null +++ b/src/Containers/Reports/Details/Components/Table/TableRow.tsx @@ -0,0 +1,88 @@ +import React, { FunctionComponent, useState } from 'react'; +import styled from 'styled-components'; +import { global_disabled_color_300 } from '@patternfly/react-tokens'; + +import { Td, Tr as PFTr } from '@patternfly/react-table'; +import { formatTotalTime } from '../../../../../Utilities/helpers'; + +import currencyFormatter from '../../../../../Utilities/currencyFormatter'; + +import TableExpandedRow from './TableExpandedRow'; +import { LegendEntry, TableHeaders } from '../types'; + +const Tr = styled(PFTr)` + & td:first-child { + width: 50px; + } +`; + +const timeFields: string[] = ['elapsed']; +const costFields: string[] = []; + +const isOther = (item: Record, key: string) => + key === 'id' && item[key] === -1; + +const isNoName = (item: Record, key: string) => + key === 'id' && item[key] === -2; + +const getText = ( + item: Record, + key: string +): string => { + if (isNoName(item, key)) return '-'; + if (isOther(item, key)) return '-'; + if (timeFields.includes(key)) return formatTotalTime(+item[key]); + if (costFields.includes(key)) return currencyFormatter(+item[key]); + return `${item[key]}`; +}; + +const getOthersStyle = (item: Record, key: string) => { + if (isOther(item, key)) { + return { + backgroundColor: global_disabled_color_300.value, + }; + } + return {}; +}; + +interface Params { + legendEntry: LegendEntry; + headers: TableHeaders; + expandRows: boolean; +} + +const TableRow: FunctionComponent = ({ + legendEntry, + headers, + expandRows, +}) => { + const [isExpanded, setIsExpanded] = useState(false); + + return ( + <> +
setIsExpanded(!isExpanded), + }} + /> + )} + + {getText(legendEntry, key)} +
+ {value} +
- {value} -
s.id === item.id), - onToggle: () => handleExpansion(item), - }} - /> - )} - {/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */} - {getText(item, key)}
0} /> )} diff --git a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts index 6fbc299e5..27900a3a9 100644 --- a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts +++ b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts @@ -20,10 +20,22 @@ const description = const categories = [CATEGORIES.executive]; +const defaultTableHeaders: AttributesType = [ + { key: 'id', value: 'ID' }, + { key: 'name', value: 'Template name' }, +]; + +const tableAttributes = [ + 'total_unique_host_count', + 'total_unique_host_changed_count', +]; + +const expandedAttributes = [] as string[]; + const defaultParams = { limit: 6, offset: 0, - attributes: ['total_unique_host_count', 'total_unique_host_changed_count'], + attributes: [...tableAttributes, ...expandedAttributes], group_by: 'template', group_by_time: true, granularity: 'monthly', @@ -38,11 +50,6 @@ const defaultParams = { template_id: [], }; -const extraAttributes: AttributesType = [ - { key: 'id', value: 'ID' }, - { key: 'name', value: 'Template name' }, -]; - const schemaFnc = ( label: string, y: string, @@ -120,7 +127,9 @@ const reportParams: ReportPageParams = { report: { slug, defaultParams, - extraAttributes, + defaultTableHeaders, + tableAttributes, + expandedAttributes, readData: readHostExplorer, readOptions: readHostExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/changesMade.ts b/src/Containers/Reports/Shared/schemas/changesMade.ts index db4b102cb..703d99a5f 100644 --- a/src/Containers/Reports/Shared/schemas/changesMade.ts +++ b/src/Containers/Reports/Shared/schemas/changesMade.ts @@ -20,15 +20,24 @@ const description = const categories = [CATEGORIES.executive]; +const defaultTableHeaders: AttributesType = [ + { key: 'id', value: 'ID' }, + { key: 'name', value: 'Template name' }, +]; + +const tableAttributes = [ + 'host_count', + 'changed_host_count', + 'host_task_count', + 'host_task_changed_count', +]; + +const expandedAttributes = [] as string[]; + const defaultParams = { limit: 6, offset: 0, - attributes: [ - 'host_count', - 'changed_host_count', - 'host_task_count', - 'host_task_changed_count', - ], + attributes: [...tableAttributes, ...expandedAttributes], group_by: 'template', group_by_time: true, granularity: 'monthly', @@ -43,11 +52,6 @@ const defaultParams = { template_id: [], }; -const extraAttributes: AttributesType = [ - { key: 'id', value: 'ID' }, - { key: 'name', value: 'Template name' }, -]; - const schemaFnc = ( label: string, y: string, @@ -125,7 +129,9 @@ const reportParams: ReportPageParams = { report: { slug, defaultParams, - extraAttributes, + defaultTableHeaders, + tableAttributes, + expandedAttributes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts index f4b1cb47e..21a3345d5 100644 --- a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts +++ b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts @@ -20,6 +20,18 @@ const description = const categories = [CATEGORIES.executive]; +const defaultTableHeaders: AttributesType = [ + { key: 'id', value: 'ID' }, + { key: 'name', value: 'Organization name' }, +]; + +const tableAttributes = [ + 'total_unique_host_count', + 'total_unique_host_changed_count', +]; + +const expandedAttributes = [] as string[]; + const defaultParams = { limit: 6, offset: 0, @@ -31,18 +43,13 @@ const defaultParams = { cluster_id: [], template_id: [], inventory_id: [], - attributes: ['total_unique_host_count', 'total_unique_host_changed_count'], + attributes: [...tableAttributes, ...expandedAttributes], group_by: 'org', group_by_time: true, sort_options: 'total_unique_host_count', sort_order: 'desc', }; -const extraAttributes: AttributesType = [ - { key: 'id', value: 'ID' }, - { key: 'name', value: 'Organization name' }, -]; - const schemaFnc = ( label: string, y: string, @@ -120,7 +127,9 @@ const reportParams: ReportPageParams = { report: { slug, defaultParams, - extraAttributes, + defaultTableHeaders, + tableAttributes, + expandedAttributes, readData: readHostExplorer, readOptions: readHostExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/index.ts b/src/Containers/Reports/Shared/schemas/index.ts index 8e3bbe725..82fed8d41 100644 --- a/src/Containers/Reports/Shared/schemas/index.ts +++ b/src/Containers/Reports/Shared/schemas/index.ts @@ -6,7 +6,7 @@ import changesMade from './changesMade'; import playbookRunRate from './playbookRunRate'; import hostsByOrganization from './hostsByOrganizations'; import jobsTasksByOrganization from './jobsTasksByOrganization'; -import templates_explorer from './templates_explorer'; +import templatesExplorer from './templatesExplorer'; const defaultReport: ReportPageParams = { slug: '', @@ -19,7 +19,7 @@ const defaultReport: ReportPageParams = { const flaggedReports = [ hostsByOrganization, jobsTasksByOrganization, - templates_explorer, + templatesExplorer, ]; const prodReports = [affectedHostsByPlaybook, changesMade, playbookRunRate]; diff --git a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts index 3403da7e9..46b76f51b 100644 --- a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts +++ b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts @@ -20,6 +20,15 @@ const description = const categories = [CATEGORIES.executive]; +const defaultTableHeaders: AttributesType = [ + { key: 'id', value: 'ID' }, + { key: 'name', value: 'Organization name' }, +]; + +const tableAttributes = ['total_count', 'host_task_count']; + +const expandedAttributes = [] as string[]; + const defaultParams = { limit: 6, offset: 0, @@ -31,18 +40,13 @@ const defaultParams = { cluster_id: [], template_id: [], inventory_id: [], - attributes: ['total_count', 'host_task_count'], + attributes: [...tableAttributes, ...expandedAttributes], group_by: 'org', group_by_time: true, sort_options: 'total_count', sort_order: 'desc', }; -const extraAttributes: AttributesType = [ - { key: 'id', value: 'ID' }, - { key: 'name', value: 'Organization name' }, -]; - const schemaFnc = ( label: string, y: string, @@ -120,7 +124,9 @@ const reportParams: ReportPageParams = { report: { slug, defaultParams, - extraAttributes, + defaultTableHeaders, + tableAttributes, + expandedAttributes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts index 997783551..71d0ecc62 100644 --- a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts +++ b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts @@ -24,10 +24,19 @@ const description = const categories = [CATEGORIES.executive]; +const defaultTableHeaders: AttributesType = [ + { key: 'id', value: 'ID' }, + { key: 'name', value: 'Template name' }, +]; + +const tableAttributes = ['failed_count', 'successful_count', 'total_count']; + +const expandedAttributes = [] as string[]; + const defaultParams: Params = { limit: 6, offset: 0, - attributes: ['failed_count', 'successful_count', 'total_count'], + attributes: [...tableAttributes, ...expandedAttributes], group_by: 'template', group_by_time: true, granularity: 'monthly', @@ -42,11 +51,6 @@ const defaultParams: Params = { template_id: [], }; -const extraAttributes: AttributesType = [ - { key: 'id', value: 'ID' }, - { key: 'name', value: 'Template name' }, -]; - const schemaFnc = ( label: string, y: string, @@ -124,7 +128,9 @@ const reportParams: ReportPageParams = { report: { slug, defaultParams, - extraAttributes, + defaultTableHeaders, + tableAttributes, + expandedAttributes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/templates_explorer.ts b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts similarity index 93% rename from src/Containers/Reports/Shared/schemas/templates_explorer.ts rename to src/Containers/Reports/Shared/schemas/templatesExplorer.ts index 6b8e64e97..ef2d0a9e6 100644 --- a/src/Containers/Reports/Shared/schemas/templates_explorer.ts +++ b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts @@ -22,9 +22,12 @@ const description = const categories = [CATEGORIES.executive]; -const listAttributes = ['failed_count', 'successful_count', 'total_count']; +const defaultTableHeaders: AttributesType = [ + { key: 'id', value: 'ID' }, + { key: 'name', value: 'Template name' }, +]; -const expandRows = true; +const tableAttributes = ['failed_count', 'successful_count', 'total_count']; const expandedAttributes = [ 'average_host_task_count_per_host', @@ -60,7 +63,7 @@ const expandedAttributes = [ const defaultParams: Params = { limit: 6, offset: 0, - attributes: [...listAttributes, ...expandedAttributes], + attributes: [...tableAttributes, ...expandedAttributes], group_by: 'template', group_by_time: false, granularity: 'monthly', @@ -75,11 +78,6 @@ const defaultParams: Params = { template_id: [], }; -const extraAttributes: AttributesType = [ - { key: 'id', value: 'ID' }, - { key: 'name', value: 'Template name' }, -]; - const schemaFnc = ( label: string, y: string, @@ -153,9 +151,9 @@ const reportParams: ReportPageParams = { report: { slug, defaultParams, - extraAttributes, - expandRows, - listAttributes, + defaultTableHeaders, + tableAttributes, + expandedAttributes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/types.ts b/src/Containers/Reports/Shared/types.ts index 95b2b9424..5c8a318b1 100644 --- a/src/Containers/Reports/Shared/types.ts +++ b/src/Containers/Reports/Shared/types.ts @@ -11,9 +11,9 @@ export type SchemaFnc = ( export interface ReportGeneratorParams { slug: string; defaultParams: Params; - expandRows?: boolean; - extraAttributes: AttributesType; - listAttributes?: string[]; + defaultTableHeaders: AttributesType; + tableAttributes: string[]; + expandedAttributes: string[]; readData: (options: ParamsWithPagination) => Promise; readOptions: (options: Params) => Promise; schemaFnc: SchemaFnc; From b96ff0b5675314356e883e67cab6e2087e55eb80 Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Tue, 5 Oct 2021 13:15:44 -0400 Subject: [PATCH 07/71] Create chart type toggle --- src/Components/Toolbar/Toolbar.tsx | 24 +++++++++++++++++++ .../Shared/schemas/affectedHostsByPlaybook.ts | 5 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Components/Toolbar/Toolbar.tsx b/src/Components/Toolbar/Toolbar.tsx index 7301c338c..b9f202d82 100644 --- a/src/Components/Toolbar/Toolbar.tsx +++ b/src/Components/Toolbar/Toolbar.tsx @@ -4,6 +4,8 @@ import { ToolbarContent, ToolbarGroup, Button, + ToggleGroup, + ToggleGroupItem, ToolbarItem, ToolbarItemVariant, ButtonVariant, @@ -27,6 +29,7 @@ interface Props { setFilters: SetValues; pagination: FunctionComponent; hasSettings: boolean; + chartToggle: FunctionComponent; additionalControls: FunctionComponent[]; } @@ -36,6 +39,7 @@ const FilterableToolbar: FunctionComponent = ({ setFilters: setQueryParams, pagination = null, hasSettings = false, + chartToggle = null, additionalControls = [], }) => { const [settingsExpanded, setSettingsExpanded] = useState(false); @@ -57,6 +61,8 @@ const FilterableToolbar: FunctionComponent = ({ setQueryParams(key, value); }; + const [isLine, setIsLine] = useState(true); + return ( = ({ )} + {chartToggle && ( + + + setIsLine(true)} + /> + setIsLine(false)} + /> + + + )} {additionalControls.length > 0 && ( {additionalControls.map((control, idx) => ( diff --git a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts index 27900a3a9..a786b1aca 100644 --- a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts +++ b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts @@ -53,7 +53,8 @@ const defaultParams = { const schemaFnc = ( label: string, y: string, - xTickFormat: string + xTickFormat: string, + chartToggle?: boolean ): ChartSchemaElement[] => [ { id: 1, @@ -109,7 +110,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: ChartType.line, + type: chartToggle ? ChartType.line : ChartType.bar, parent: 0, props: { x: 'created_date', From 233c1c1bd9b38e136bf99489ba5ea95bf1b5f454 Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Wed, 6 Oct 2021 16:13:08 -0400 Subject: [PATCH 08/71] chart type display fixes --- src/Components/Toolbar/Toolbar.tsx | 24 ------------------- .../Shared/schemas/affectedHostsByPlaybook.ts | 5 ++-- .../Reports/Shared/schemas/changesMade.ts | 6 +++-- .../Shared/schemas/hostsByOrganizations.ts | 6 +++-- .../Shared/schemas/jobsTasksByOrganization.ts | 6 +++-- .../Reports/Shared/schemas/playbookRunRate.ts | 6 +++-- .../Shared/schemas/templatesExplorer.ts | 1 + src/Containers/Reports/Shared/types.ts | 4 +++- 8 files changed, 23 insertions(+), 35 deletions(-) diff --git a/src/Components/Toolbar/Toolbar.tsx b/src/Components/Toolbar/Toolbar.tsx index b9f202d82..7301c338c 100644 --- a/src/Components/Toolbar/Toolbar.tsx +++ b/src/Components/Toolbar/Toolbar.tsx @@ -4,8 +4,6 @@ import { ToolbarContent, ToolbarGroup, Button, - ToggleGroup, - ToggleGroupItem, ToolbarItem, ToolbarItemVariant, ButtonVariant, @@ -29,7 +27,6 @@ interface Props { setFilters: SetValues; pagination: FunctionComponent; hasSettings: boolean; - chartToggle: FunctionComponent; additionalControls: FunctionComponent[]; } @@ -39,7 +36,6 @@ const FilterableToolbar: FunctionComponent = ({ setFilters: setQueryParams, pagination = null, hasSettings = false, - chartToggle = null, additionalControls = [], }) => { const [settingsExpanded, setSettingsExpanded] = useState(false); @@ -61,8 +57,6 @@ const FilterableToolbar: FunctionComponent = ({ setQueryParams(key, value); }; - const [isLine, setIsLine] = useState(true); - return ( = ({ )} - {chartToggle && ( - - - setIsLine(true)} - /> - setIsLine(false)} - /> - - - )} {additionalControls.length > 0 && ( {additionalControls.map((control, idx) => ( diff --git a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts index a786b1aca..86fe49fcf 100644 --- a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts +++ b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts @@ -54,7 +54,7 @@ const schemaFnc = ( label: string, y: string, xTickFormat: string, - chartToggle?: boolean + isLine?: boolean ): ChartSchemaElement[] => [ { id: 1, @@ -69,6 +69,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, + x: !isLine ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -110,7 +111,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartToggle ? ChartType.line : ChartType.bar, + type: isLine ? ChartType.line : ChartType.bar, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/changesMade.ts b/src/Containers/Reports/Shared/schemas/changesMade.ts index 703d99a5f..c31c781f6 100644 --- a/src/Containers/Reports/Shared/schemas/changesMade.ts +++ b/src/Containers/Reports/Shared/schemas/changesMade.ts @@ -55,7 +55,8 @@ const defaultParams = { const schemaFnc = ( label: string, y: string, - xTickFormat: string + xTickFormat: string, + isLine?: boolean ): ChartSchemaElement[] => [ { id: 1, @@ -70,6 +71,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, + x: !isLine ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -111,7 +113,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: ChartType.line, + type: isLine ? ChartType.line : ChartType.bar, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts index 21a3345d5..8745799c5 100644 --- a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts +++ b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts @@ -53,7 +53,8 @@ const defaultParams = { const schemaFnc = ( label: string, y: string, - xTickFormat: string + xTickFormat: string, + isLine?: boolean ): ChartSchemaElement[] => [ { id: 1, @@ -68,6 +69,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, + x: !isLine ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -109,7 +111,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: ChartType.line, + type: isLine ? ChartType.line : ChartType.bar, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts index 46b76f51b..40e6b9631 100644 --- a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts +++ b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts @@ -50,7 +50,8 @@ const defaultParams = { const schemaFnc = ( label: string, y: string, - xTickFormat: string + xTickFormat: string, + isLine?: boolean ): ChartSchemaElement[] => [ { id: 1, @@ -65,6 +66,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, + x: !isLine ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -106,7 +108,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: ChartType.line, + type: isLine ? ChartType.line : ChartType.bar, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts index 71d0ecc62..6bab48e15 100644 --- a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts +++ b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts @@ -54,7 +54,8 @@ const defaultParams: Params = { const schemaFnc = ( label: string, y: string, - xTickFormat: string + xTickFormat: string, + isLine?: boolean ): ChartSchemaElement[] => [ { id: 1, @@ -69,6 +70,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, + x: !isLine ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -110,7 +112,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: ChartType.line, + type: isLine ? ChartType.line : ChartType.bar, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts index ef2d0a9e6..2bdeab8e9 100644 --- a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts +++ b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts @@ -76,6 +76,7 @@ const defaultParams: Params = { org_id: [], status: [], template_id: [], + showChartToggle: false, }; const schemaFnc = ( diff --git a/src/Containers/Reports/Shared/types.ts b/src/Containers/Reports/Shared/types.ts index 5c8a318b1..eceed897c 100644 --- a/src/Containers/Reports/Shared/types.ts +++ b/src/Containers/Reports/Shared/types.ts @@ -5,7 +5,8 @@ export type AttributesType = { key: string; value: string }[]; export type SchemaFnc = ( label: string, y: string, - xTickFormat: string + xTickFormat: string, + isLine?: boolean ) => ChartSchemaElement[]; export interface ReportGeneratorParams { @@ -24,5 +25,6 @@ export interface ReportPageParams { name: string; description: string; categories: string[]; + showChartToggle?: boolean; report?: ReportGeneratorParams; } From 8a1c1d23515e33e51be1ae3a2b914e568ab1b267 Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Wed, 6 Oct 2021 17:14:21 -0400 Subject: [PATCH 09/71] Turned off toggle on templates explorer page --- src/Containers/Reports/Shared/schemas/templatesExplorer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts index 2bdeab8e9..ef2d0a9e6 100644 --- a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts +++ b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts @@ -76,7 +76,6 @@ const defaultParams: Params = { org_id: [], status: [], template_id: [], - showChartToggle: false, }; const schemaFnc = ( From 99a59e457614d33115459d0e457b86b51e9a1428 Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Fri, 8 Oct 2021 13:02:31 -0400 Subject: [PATCH 10/71] Future proofing chart toggle --- .../Reports/Details/Components/ReportCard.tsx | 50 +++++++++++++------ .../Shared/schemas/affectedHostsByPlaybook.ts | 9 ++-- .../Reports/Shared/schemas/changesMade.ts | 9 ++-- .../Shared/schemas/hostsByOrganizations.ts | 9 ++-- .../Shared/schemas/jobsTasksByOrganization.ts | 9 ++-- .../Reports/Shared/schemas/playbookRunRate.ts | 9 ++-- .../Shared/schemas/templatesExplorer.ts | 3 ++ src/Containers/Reports/Shared/types.ts | 6 +-- src/FeatureFlags/useFeatureFlag.ts | 3 +- 9 files changed, 74 insertions(+), 33 deletions(-) diff --git a/src/Containers/Reports/Details/Components/ReportCard.tsx b/src/Containers/Reports/Details/Components/ReportCard.tsx index 0286dbc0f..b911051b8 100644 --- a/src/Containers/Reports/Details/Components/ReportCard.tsx +++ b/src/Containers/Reports/Details/Components/ReportCard.tsx @@ -2,7 +2,12 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck -import React, { FunctionComponent, useCallback, useEffect } from 'react'; +import React, { + FunctionComponent, + useCallback, + useEffect, + useState, +} from 'react'; import styled from 'styled-components'; import { @@ -10,6 +15,8 @@ import { CardBody as PFCardBody, CardFooter, PaginationVariant, + ToggleGroup, + ToggleGroupItem, } from '@patternfly/react-core'; import Pagination from '../../../../Components/Pagination'; @@ -54,6 +61,7 @@ const ReportCard: FunctionComponent = ({ defaultTableHeaders, tableAttributes, expandedAttributes, + availableChartTypes, readData, readOptions, schemaFnc, @@ -81,6 +89,8 @@ const ReportCard: FunctionComponent = ({ setOptions(); }, [queryParams]); + const [activeChartType, setActiveChartType] = useState('line'); + const tableHeaders = [ ...defaultTableHeaders, ...(tableAttributes @@ -126,19 +136,31 @@ const ReportCard: FunctionComponent = ({ }; }; - const additionalControls = pdfDownloadEnabled - ? [ - , - ] - : []; - + const additionalControls = [ + availableChartTypes.length > 1 && ( + + {availableChartTypes.map((chartType) => ( + setActiveChartType(chartType)} + /> + ))} + + ), + pdfDownloadEnabled && ( + + ), + ]; return ( diff --git a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts index 86fe49fcf..03b8fb329 100644 --- a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts +++ b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts @@ -50,11 +50,13 @@ const defaultParams = { template_id: [], }; +const availableChartTypes = [ChartType.bar, ChartType.line]; + const schemaFnc = ( label: string, y: string, xTickFormat: string, - isLine?: boolean + chartType: string ): ChartSchemaElement[] => [ { id: 1, @@ -69,7 +71,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, - x: !isLine ? 85 : 0, + x: chartType == ChartType.bar ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -111,7 +113,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: isLine ? ChartType.line : ChartType.bar, + type: chartType === 'bar' ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', @@ -132,6 +134,7 @@ const reportParams: ReportPageParams = { defaultTableHeaders, tableAttributes, expandedAttributes, + availableChartTypes, readData: readHostExplorer, readOptions: readHostExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/changesMade.ts b/src/Containers/Reports/Shared/schemas/changesMade.ts index c31c781f6..2941cb430 100644 --- a/src/Containers/Reports/Shared/schemas/changesMade.ts +++ b/src/Containers/Reports/Shared/schemas/changesMade.ts @@ -52,11 +52,13 @@ const defaultParams = { template_id: [], }; +const availableChartTypes = [ChartType.bar, ChartType.line]; + const schemaFnc = ( label: string, y: string, xTickFormat: string, - isLine?: boolean + chartType: string ): ChartSchemaElement[] => [ { id: 1, @@ -71,7 +73,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, - x: !isLine ? 85 : 0, + x: chartType == ChartType.bar ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -113,7 +115,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: isLine ? ChartType.line : ChartType.bar, + type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', @@ -134,6 +136,7 @@ const reportParams: ReportPageParams = { defaultTableHeaders, tableAttributes, expandedAttributes, + availableChartTypes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts index 8745799c5..6b1b62909 100644 --- a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts +++ b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts @@ -50,11 +50,13 @@ const defaultParams = { sort_order: 'desc', }; +const availableChartTypes = [ChartType.bar, ChartType.line]; + const schemaFnc = ( label: string, y: string, xTickFormat: string, - isLine?: boolean + chartType: string ): ChartSchemaElement[] => [ { id: 1, @@ -69,7 +71,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, - x: !isLine ? 85 : 0, + x: chartType == ChartType.bar ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -111,7 +113,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: isLine ? ChartType.line : ChartType.bar, + type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', @@ -132,6 +134,7 @@ const reportParams: ReportPageParams = { defaultTableHeaders, tableAttributes, expandedAttributes, + availableChartTypes, readData: readHostExplorer, readOptions: readHostExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts index 40e6b9631..599f5b8ca 100644 --- a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts +++ b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts @@ -47,11 +47,13 @@ const defaultParams = { sort_order: 'desc', }; +const availableChartTypes = [ChartType.bar, ChartType.line]; + const schemaFnc = ( label: string, y: string, xTickFormat: string, - isLine?: boolean + chartType: string ): ChartSchemaElement[] => [ { id: 1, @@ -66,7 +68,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, - x: !isLine ? 85 : 0, + x: chartType == ChartType.bar ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -108,7 +110,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: isLine ? ChartType.line : ChartType.bar, + type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', @@ -129,6 +131,7 @@ const reportParams: ReportPageParams = { defaultTableHeaders, tableAttributes, expandedAttributes, + availableChartTypes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts index 6bab48e15..b8e46665e 100644 --- a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts +++ b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts @@ -51,11 +51,13 @@ const defaultParams: Params = { template_id: [], }; +const availableChartTypes = [ChartType.bar, ChartType.line]; + const schemaFnc = ( label: string, y: string, xTickFormat: string, - isLine?: boolean + chartType: string ): ChartSchemaElement[] => [ { id: 1, @@ -70,7 +72,7 @@ const schemaFnc = ( }, domainPadding: { y: 25, - x: !isLine ? 85 : 0, + x: chartType == ChartType.bar ? 85 : 0, }, themeColor: ChartThemeColor.multiOrdered, }, @@ -112,7 +114,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: isLine ? ChartType.line : ChartType.bar, + type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', @@ -133,6 +135,7 @@ const reportParams: ReportPageParams = { defaultTableHeaders, tableAttributes, expandedAttributes, + availableChartTypes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts index ef2d0a9e6..20a2b0f65 100644 --- a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts +++ b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts @@ -78,6 +78,8 @@ const defaultParams: Params = { template_id: [], }; +const availableChartTypes = [ChartType.bar]; + const schemaFnc = ( label: string, y: string, @@ -154,6 +156,7 @@ const reportParams: ReportPageParams = { defaultTableHeaders, tableAttributes, expandedAttributes, + availableChartTypes, readData: readJobExplorer, readOptions: readJobExplorerOptions, schemaFnc, diff --git a/src/Containers/Reports/Shared/types.ts b/src/Containers/Reports/Shared/types.ts index eceed897c..90c592daa 100644 --- a/src/Containers/Reports/Shared/types.ts +++ b/src/Containers/Reports/Shared/types.ts @@ -1,4 +1,4 @@ -import { ChartSchemaElement } from 'react-json-chart-builder'; +import { ChartSchemaElement, ChartType } from 'react-json-chart-builder'; import { ApiJson, Params, ParamsWithPagination } from '../../../Api'; export type AttributesType = { key: string; value: string }[]; @@ -6,7 +6,7 @@ export type SchemaFnc = ( label: string, y: string, xTickFormat: string, - isLine?: boolean + chartType: ChartType.line ) => ChartSchemaElement[]; export interface ReportGeneratorParams { @@ -15,6 +15,7 @@ export interface ReportGeneratorParams { defaultTableHeaders: AttributesType; tableAttributes: string[]; expandedAttributes: string[]; + availableChartTypes: string[]; readData: (options: ParamsWithPagination) => Promise; readOptions: (options: Params) => Promise; schemaFnc: SchemaFnc; @@ -25,6 +26,5 @@ export interface ReportPageParams { name: string; description: string; categories: string[]; - showChartToggle?: boolean; report?: ReportGeneratorParams; } diff --git a/src/FeatureFlags/useFeatureFlag.ts b/src/FeatureFlags/useFeatureFlag.ts index c38ea9564..3f9b3e0a1 100644 --- a/src/FeatureFlags/useFeatureFlag.ts +++ b/src/FeatureFlags/useFeatureFlag.ts @@ -14,7 +14,8 @@ const useFeatureFlag = (flag: ValidFeatureFlags): boolean => { ({ name }) => name === (isBeta() ? betaFlag : flag) ); - return !!feature && feature.enabled; + // return !!feature && feature.enabled; + return true; }; export default useFeatureFlag; From 66bb1bddbd91340723697bd560a32bd0ccff12eb Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Fri, 8 Oct 2021 14:01:42 -0400 Subject: [PATCH 11/71] Toggle fixes --- src/Containers/Reports/Details/Components/ReportCard.tsx | 4 +++- src/Containers/Reports/Shared/schemas/changesMade.ts | 2 +- src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts | 2 +- .../Reports/Shared/schemas/jobsTasksByOrganization.ts | 2 +- src/Containers/Reports/Shared/schemas/playbookRunRate.ts | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Containers/Reports/Details/Components/ReportCard.tsx b/src/Containers/Reports/Details/Components/ReportCard.tsx index b911051b8..7cf6d418f 100644 --- a/src/Containers/Reports/Details/Components/ReportCard.tsx +++ b/src/Containers/Reports/Details/Components/ReportCard.tsx @@ -104,6 +104,7 @@ const ReportCard: FunctionComponent = ({ options.sort_options?.find(({ key }) => key === queryParams.sort_options) ?.value || 'Label Y', xTickFormat: getDateFormatByGranularity(queryParams.granularity), + chartType: activeChartType, }; const getSortParams = (currKey: string) => { @@ -188,7 +189,8 @@ const ReportCard: FunctionComponent = ({ schema={schemaFnc( chartParams.label, chartParams.y, - chartParams.xTickFormat + chartParams.xTickFormat, + chartParams.chartType )} data={dataApi.result} /> diff --git a/src/Containers/Reports/Shared/schemas/changesMade.ts b/src/Containers/Reports/Shared/schemas/changesMade.ts index 2941cb430..273e10ef0 100644 --- a/src/Containers/Reports/Shared/schemas/changesMade.ts +++ b/src/Containers/Reports/Shared/schemas/changesMade.ts @@ -115,7 +115,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, + type: chartType == 'bar' ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts index 6b1b62909..abc508432 100644 --- a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts +++ b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts @@ -113,7 +113,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, + type: chartType == 'bar' ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts index 599f5b8ca..6211895ef 100644 --- a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts +++ b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts @@ -110,7 +110,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, + type: chartType == 'bar' ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts index b8e46665e..ebbdfa0f0 100644 --- a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts +++ b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts @@ -114,7 +114,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == ChartType.bar ? ChartType.bar : ChartType.line, + type: chartType == 'bar' ? ChartType.bar : ChartType.line, parent: 0, props: { x: 'created_date', From 74e7d1d4aba54a86ec9cb248ab41e16ff5b9bac5 Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Fri, 8 Oct 2021 14:03:13 -0400 Subject: [PATCH 12/71] feature flag --- src/FeatureFlags/useFeatureFlag.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/FeatureFlags/useFeatureFlag.ts b/src/FeatureFlags/useFeatureFlag.ts index 3f9b3e0a1..c38ea9564 100644 --- a/src/FeatureFlags/useFeatureFlag.ts +++ b/src/FeatureFlags/useFeatureFlag.ts @@ -14,8 +14,7 @@ const useFeatureFlag = (flag: ValidFeatureFlags): boolean => { ({ name }) => name === (isBeta() ? betaFlag : flag) ); - // return !!feature && feature.enabled; - return true; + return !!feature && feature.enabled; }; export default useFeatureFlag; From 75a304113d690d875b4341b59af683b476f762f6 Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Fri, 8 Oct 2021 14:59:29 -0400 Subject: [PATCH 13/71] files clean up --- src/Containers/Reports/Details/Components/ReportCard.tsx | 7 +++++-- .../Reports/Shared/schemas/affectedHostsByPlaybook.ts | 6 +++--- src/Containers/Reports/Shared/schemas/changesMade.ts | 6 +++--- .../Reports/Shared/schemas/hostsByOrganizations.ts | 6 +++--- .../Reports/Shared/schemas/jobsTasksByOrganization.ts | 6 +++--- src/Containers/Reports/Shared/schemas/playbookRunRate.ts | 6 +++--- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/Containers/Reports/Details/Components/ReportCard.tsx b/src/Containers/Reports/Details/Components/ReportCard.tsx index 7cf6d418f..421c2a648 100644 --- a/src/Containers/Reports/Details/Components/ReportCard.tsx +++ b/src/Containers/Reports/Details/Components/ReportCard.tsx @@ -33,6 +33,7 @@ import { Chart, Table } from './'; import DownloadPdfButton from '../../../../Components/Toolbar/DownloadPdfButton'; import { useFeatureFlag, ValidFeatureFlags } from '../../../../FeatureFlags'; import { OptionsReturnType } from '../../../../Api'; +import { capitalize } from '../../../../Utilities/helpers'; const CardBody = styled(PFCardBody)` & .pf-c-toolbar, @@ -89,7 +90,9 @@ const ReportCard: FunctionComponent = ({ setOptions(); }, [queryParams]); - const [activeChartType, setActiveChartType] = useState('line'); + const [activeChartType, setActiveChartType] = useState( + availableChartTypes[0] + ); const tableHeaders = [ ...defaultTableHeaders, @@ -143,7 +146,7 @@ const ReportCard: FunctionComponent = ({ {availableChartTypes.map((chartType) => ( setActiveChartType(chartType)} diff --git a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts index 03b8fb329..c85469837 100644 --- a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts +++ b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts @@ -50,13 +50,13 @@ const defaultParams = { template_id: [], }; -const availableChartTypes = [ChartType.bar, ChartType.line]; +const availableChartTypes = [ChartType.line, ChartType.bar]; const schemaFnc = ( label: string, y: string, xTickFormat: string, - chartType: string + chartType: ChartType ): ChartSchemaElement[] => [ { id: 1, @@ -113,7 +113,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType === 'bar' ? ChartType.bar : ChartType.line, + type: chartType, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/changesMade.ts b/src/Containers/Reports/Shared/schemas/changesMade.ts index 273e10ef0..6ca23db07 100644 --- a/src/Containers/Reports/Shared/schemas/changesMade.ts +++ b/src/Containers/Reports/Shared/schemas/changesMade.ts @@ -52,13 +52,13 @@ const defaultParams = { template_id: [], }; -const availableChartTypes = [ChartType.bar, ChartType.line]; +const availableChartTypes = [ChartType.line, ChartType.bar]; const schemaFnc = ( label: string, y: string, xTickFormat: string, - chartType: string + chartType: ChartType ): ChartSchemaElement[] => [ { id: 1, @@ -115,7 +115,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == 'bar' ? ChartType.bar : ChartType.line, + type: chartType, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts index abc508432..451478db5 100644 --- a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts +++ b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts @@ -50,13 +50,13 @@ const defaultParams = { sort_order: 'desc', }; -const availableChartTypes = [ChartType.bar, ChartType.line]; +const availableChartTypes = [ChartType.line, ChartType.bar]; const schemaFnc = ( label: string, y: string, xTickFormat: string, - chartType: string + chartType: ChartType ): ChartSchemaElement[] => [ { id: 1, @@ -113,7 +113,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == 'bar' ? ChartType.bar : ChartType.line, + type: chartType, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts index 6211895ef..21dc2cceb 100644 --- a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts +++ b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts @@ -47,13 +47,13 @@ const defaultParams = { sort_order: 'desc', }; -const availableChartTypes = [ChartType.bar, ChartType.line]; +const availableChartTypes = [ChartType.line, ChartType.bar]; const schemaFnc = ( label: string, y: string, xTickFormat: string, - chartType: string + chartType: ChartType ): ChartSchemaElement[] => [ { id: 1, @@ -110,7 +110,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == 'bar' ? ChartType.bar : ChartType.line, + type: chartType, parent: 0, props: { x: 'created_date', diff --git a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts index ebbdfa0f0..a876deea1 100644 --- a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts +++ b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts @@ -51,13 +51,13 @@ const defaultParams: Params = { template_id: [], }; -const availableChartTypes = [ChartType.bar, ChartType.line]; +const availableChartTypes = [ChartType.line, ChartType.bar]; const schemaFnc = ( label: string, y: string, xTickFormat: string, - chartType: string + chartType: ChartType ): ChartSchemaElement[] => [ { id: 1, @@ -114,7 +114,7 @@ const schemaFnc = ( template: { id: 0, kind: ChartKind.simple, - type: chartType == 'bar' ? ChartType.bar : ChartType.line, + type: chartType, parent: 0, props: { x: 'created_date', From 3fc6ac1fe6fef04d59ed1ee85ce512609b88d1e7 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Mon, 11 Oct 2021 11:53:34 +0200 Subject: [PATCH 14/71] Created action queue to wait for the URL update with dispatch --- src/QueryParams/useQueryParams.js | 8 ++++++- src/Utilities/useAsyncActionQueue.js | 33 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/Utilities/useAsyncActionQueue.js diff --git a/src/QueryParams/useQueryParams.js b/src/QueryParams/useQueryParams.js index 6c82fcb48..ca46af13c 100644 --- a/src/QueryParams/useQueryParams.js +++ b/src/QueryParams/useQueryParams.js @@ -1,6 +1,7 @@ import { useContext } from 'react'; import moment from 'moment'; import { QueryParamsContext } from './Context'; +import useAsyncActionQueue from '../Utilities/useAsyncActionQueue'; import { formatDate } from '../Utilities/helpers'; import { DEFAULT_NAMESPACE } from './helpers'; @@ -119,7 +120,7 @@ const useQueryParams = (initial, namespace = DEFAULT_NAMESPACE) => { const { queryParams, update } = useContext(QueryParamsContext); const params = queryParams[namespace] || initial; - const dispatch = (action) => { + const executeAction = (action) => { if (action.type === 'RESET_FILTER') { update({ newQueryParams: initial, namespace }); } else { @@ -128,6 +129,11 @@ const useQueryParams = (initial, namespace = DEFAULT_NAMESPACE) => { } }; + const { push: dispatch } = useAsyncActionQueue({ + executeAction, + waitFor: params, + }); + return { queryParams: params, dispatch, diff --git a/src/Utilities/useAsyncActionQueue.js b/src/Utilities/useAsyncActionQueue.js new file mode 100644 index 000000000..e89f0da1b --- /dev/null +++ b/src/Utilities/useAsyncActionQueue.js @@ -0,0 +1,33 @@ +import { useState, useEffect } from 'react'; + +const useAsyncActionQueue = ({ executeAction, waitFor }) => { + const [actionQueue, setActionQueue] = useState([]); + const [isProcessing, setIsProcessing] = useState(false); + + const processNext = () => { + const action = actionQueue[0]; + if (action) { + setIsProcessing(true); + executeAction(action); + setActionQueue((prev) => prev.slice(1)); + } + }; + + useEffect(() => { + if (!isProcessing) { + processNext(); + } + }, [actionQueue, isProcessing]); + + useEffect(() => { + setIsProcessing(false); + }, [waitFor]); + + return { + push: (action) => { + setActionQueue((prev) => [...prev, action]); + }, + }; +}; + +export default useAsyncActionQueue; From 87cf4e52b78b01560031ad4ff114639769a567a4 Mon Sep 17 00:00:00 2001 From: Mat Wilson Date: Mon, 11 Oct 2021 10:36:11 -0700 Subject: [PATCH 15/71] Fix Login Flow, remove irrelevant automationcalculator test --- cypress/integration/AutomationCalculator.spec.js | 6 ------ cypress/support/commands.js | 5 +++-- package.json | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/cypress/integration/AutomationCalculator.spec.js b/cypress/integration/AutomationCalculator.spec.js index 2071987e2..e10959462 100644 --- a/cypress/integration/AutomationCalculator.spec.js +++ b/cypress/integration/AutomationCalculator.spec.js @@ -31,12 +31,6 @@ describe('Automation Caluclator page smoketests', () => { } }); - xit('can click on the template name', () => { - cy.get('.top-templates').find('a').eq(0).click(); - cy.location().should((location) => { - expect(location.pathname).to.include(jobExplorerUrl); - }); - }); it('Query parameters are stored in the URL to enable refresh', () => { // Add more once fixtures are implemented - other filters are content-dependent. cy.get('[data-cy="quick_date_range"]').click(); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 1e2f98e16..007a6b3a7 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -48,10 +48,11 @@ Cypress.Commands.add('clearFeatureDialogs', () => { Cypress.Commands.add('loginFlow', () => { cy.visit('/'); - cy.getUsername().then((uname) => cy.get('#username').type(`${uname}`)); + cy.getUsername().then((uname) => cy.get('#username-verification').type(`${uname}`)); + cy.get('#login-show-step2').click(); cy.getPassword().then((password) => cy.get('#password').type(`${password}{enter}`, { log: false }) ); - cy.url().should('eq', Cypress.config().baseUrl + '/clusters'); + cy.url().should('eq', Cypress.config().baseUrl + '/'); }); diff --git a/package.json b/package.json index 1410a6c0d..951ac8fe2 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "babel-jest": "^26.6.3", "babel-plugin-lodash": "^3.3.4", "css-loader": "^6.3.0", - "cypress": "^8.4.1", + "cypress": "^8.5.0", "enzyme": "^3.11.0", "enzyme-to-json": "^3.6.2", "eslint": "7.32.0", From 2018effbcaab5e5b0e88b28d82e9234bb800fd28 Mon Sep 17 00:00:00 2001 From: Mat Wilson Date: Mon, 11 Oct 2021 14:14:22 -0700 Subject: [PATCH 16/71] enable tests with the assumption of stage, fix smoke test on cluster page --- cypress/integration/Dashboard.spec.js | 48 +++++++++++---------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/cypress/integration/Dashboard.spec.js b/cypress/integration/Dashboard.spec.js index c1e9619c3..fae7e1f84 100644 --- a/cypress/integration/Dashboard.spec.js +++ b/cypress/integration/Dashboard.spec.js @@ -26,30 +26,32 @@ async function fuzzClustersPage() { cy.get(appid) .find('a') .eq(i) - .click({ waitForAnimations: true }) + .click() .then(() => { cy.screenshot('top-template-modal-' + i + '.png', { capture: 'fullPage', }); }); + cy.get('[aria-label="Close"]').click(); + } - // navigate to the job explorer page for each bar in the chart ... - for (let i = 0; i <= 4; i++) { - // pick a random bar to click on ... - const barid = parseInt(Math.floor(Math.random() * 10)); + // navigate to the job explorer page for each bar in the chart ... + for (let i = 0; i <= 4; i++) { + // pick a random bar to click on ... + const barid = parseInt(Math.floor(Math.random() * 10)); - // click it and wait for the jobexplorer page to load ... - cy.get(appid) - .find('#d3-bar-chart-root', { timeout: 1000 }) - .should('be.visible'); - cy.get(appid).find('rect').eq(barid).click({ waitForAnimations: true }); - cy.screenshot('clusters-bar-' + barid + '-jobexplorer-details.png', { - capture: 'fullPage', - }); + // click it and wait for the jobexplorer page to load ... + cy.get(appid) + .find('#d3-bar-chart-root', { timeout: 1000 }) + .should('be.visible'); + cy.get(appid).find('rect').eq(barid).click({ force: true }); + cy.url().should('include', 'job-explorer'); + cy.screenshot('clusters-bar-' + barid + '-jobexplorer-details.png', { + capture: 'fullPage', + }); - // go back to the clusters page ... - cy.visit(dashboardUrl); - } + // go back to the clusters page ... + cy.visit(dashboardUrl); } } @@ -63,17 +65,6 @@ describe('Dashboard page smoketests', () => { fuzzClustersPage(); }); - xit('Page contains chart, and 3 card elements', () => { - cy.get('#d3-bar-chart-root').should((chartElem) => { - expect(chartElem).to.have.length(1); - }); - - // fails due to bug: https://issues.redhat.com/browse/AA-470 - it.skip('can interact with the clusters page without breaking the UI', () => { - fuzzClustersPage(); - }); - }); - it('Page contains chart, and 3 card elements', () => { cy.get('#d3-bar-chart-root').should((chartElem) => { expect(chartElem).to.have.length(1); @@ -83,7 +74,8 @@ describe('Dashboard page smoketests', () => { }); }); - it('There is a filter toolbar on the Clusters page', () => { + // Fails due to lack of selectors + xit('There is a filter toolbar on the Clusters page', () => { cy.get('div[id="filterable-toolbar-with-chip-groups"]').should( (toolbar) => { expect(toolbar).to.have.length(1); From 86d3dc211bc014909a38944d79c2468644a858eb Mon Sep 17 00:00:00 2001 From: Mat Wilson Date: Mon, 11 Oct 2021 15:42:21 -0700 Subject: [PATCH 17/71] fix dashboard tests and global spec --- .../integration/AutomationCalculator.spec.js | 3 +-- cypress/integration/Dashboard.spec.js | 19 ++++++++-------- cypress/integration/Global.spec.js | 22 +++++++++++++------ 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/cypress/integration/AutomationCalculator.spec.js b/cypress/integration/AutomationCalculator.spec.js index e10959462..9cedda5dd 100644 --- a/cypress/integration/AutomationCalculator.spec.js +++ b/cypress/integration/AutomationCalculator.spec.js @@ -1,5 +1,5 @@ /* global cy */ -import { appid, calculatorUrl, jobExplorerUrl } from '../support/constants'; +import { appid, calculatorUrl } from '../support/constants'; describe('Automation Caluclator page smoketests', () => { beforeEach(() => { @@ -32,7 +32,6 @@ describe('Automation Caluclator page smoketests', () => { }); it('Query parameters are stored in the URL to enable refresh', () => { - // Add more once fixtures are implemented - other filters are content-dependent. cy.get('[data-cy="quick_date_range"]').click(); cy.contains('Past 2 years').click(); cy.url().should('include', 'quick_date_range=roi_last_2_years'); diff --git a/cypress/integration/Dashboard.spec.js b/cypress/integration/Dashboard.spec.js index fae7e1f84..954d510f0 100644 --- a/cypress/integration/Dashboard.spec.js +++ b/cypress/integration/Dashboard.spec.js @@ -84,13 +84,14 @@ describe('Dashboard page smoketests', () => { }); }); +// skipped due to lack of selectors describe('Dashboard page filter tests', () => { beforeEach(() => { cy.loginFlow(); cy.visit(dashboardUrl); }); - it('Can filter by organization', () => { + xit('Can filter by organization', () => { cy.get('button[class="pf-c-select__toggle"]').eq(0).click(); cy.get('button[class*="pf-c-select__menu-item"]') .contains('Organization') @@ -117,7 +118,7 @@ describe('Dashboard page filter tests', () => { cy.screenshot(screenshotFilename); }); - it('Can filter by a preset date range', () => { + xit('Can filter by a preset date range', () => { const todayminusone = moment(new Date().toISOString()) .subtract(1, 'day') .format('M/DD'); @@ -147,7 +148,7 @@ describe('Dashboard page filter tests', () => { cy.screenshot(screenshotFilename); }); - it('Can filter by a custom date range', () => { + xit('Can filter by a custom date range', () => { const today = moment(new Date().toISOString()).format('YYYY-MM-DD'); const oneWeekAgo = moment(new Date().toISOString()) .subtract(1, 'week') @@ -183,7 +184,7 @@ describe('Dashboard page filter tests', () => { cy.screenshot(screenshotFilename); }); - it('Can filter by cluster', () => { + xit('Can filter by cluster', () => { cy.get('button[class="pf-c-select__toggle"]').eq(0).click(); cy.get('button[class*="pf-c-select__menu-item"]') .contains('Cluster') @@ -207,7 +208,7 @@ describe('Dashboard page filter tests', () => { cy.screenshot(screenshotFilename); }); - it('Can filter by job type', () => { + xit('Can filter by job type', () => { cy.get('button[class="pf-c-select__toggle"]').eq(0).click(); cy.get('button[class*="pf-c-select__menu-item"]').contains('Job').click(); cy.get('button[id^="pf-select-toggle-id-"]') @@ -232,7 +233,7 @@ describe('Dashboard page filter tests', () => { cy.screenshot(screenshotFilename); }); - it('Can filter by template', () => { + xit('Can filter by template', () => { cy.get('button[class="pf-c-select__toggle"]').eq(0).click(); cy.get('button[class*="pf-c-select__menu-item"]') .contains('Template') @@ -253,7 +254,7 @@ describe('Dashboard page filter tests', () => { cy.screenshot(screenshotFilename); }); - it('Can filter by entering text in typeAhead', () => { + xit('Can filter by entering text in typeAhead', () => { cy.get('button[class="pf-c-select__toggle"]').eq(0).click(); cy.get('button[class*="pf-c-select__menu-item"]') .contains('Organization') @@ -288,7 +289,7 @@ describe('Dashboard page filter tests', () => { cy.screenshot(screenshotFilename); }); - it('Can clear filters', () => { + xit('Can clear filters', () => { cy.get('button[class="pf-c-select__toggle"]').eq(0).click(); cy.get('button[class*="pf-c-select__menu-item"]') .contains('Organization') @@ -328,7 +329,7 @@ describe('Dashboard page drilldown tests', () => { cy.visit(dashboardUrl); }); - it('Can navigate to job explorer from bar chart', () => { + it.skip('Can navigate to job explorer from bar chart', () => { const todayminusone = moment(new Date().toISOString()) .subtract(1, 'day') .format('YYYY-MM-DD'); diff --git a/cypress/integration/Global.spec.js b/cypress/integration/Global.spec.js index 093daf43b..ccb4857ee 100644 --- a/cypress/integration/Global.spec.js +++ b/cypress/integration/Global.spec.js @@ -12,15 +12,23 @@ describe('Insights smoketests', () => { cy.loginFlow(); }); - xit('has all the AA navigation items', () => { - cy.visit('/ansible/automation-analytics'); - const navbar = cy.get('li[ouiaid="automation-analytics"]'); - const navlis = navbar.find('li'); - navlis.should('have.length', 5); + it('has all the AA navigation items', () => { + cy.visit(dashboardUrl); + cy.get('[aria-labelledby="Operations Insights"]') + .find('.pf-c-nav__toggle-icon') + .click({ multiple: true }); + cy.get('[aria-labelledby="Operations Insights"]') + .find('li') + .should('have.length', 11); + cy.get('[aria-labelledby="Security Insights"]') + .find('li') + .should('have.length', 1); + cy.get('[aria-labelledby="Business Insights"]') + .find('li') + .should('have.length', 6); }); - + // requires expansion it('can open each page without breaking the UI', () => { - cy.visit('/ansible/automation-analytics'); cy.visit(calculatorUrl); cy.visit(jobExplorerUrl); cy.visit(dashboardUrl); From 46366226c9ea4c4b49985476fc9074972262439e Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 13 Oct 2021 11:38:42 +0200 Subject: [PATCH 18/71] Table rows optimized a little --- .../Details/Components/Table/TableRow.tsx | 26 ++++++++----------- .../Details/Components/Table/index.tsx | 2 +- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/Containers/Reports/Details/Components/Table/TableRow.tsx b/src/Containers/Reports/Details/Components/Table/TableRow.tsx index 2d9be0dce..149ba8e88 100644 --- a/src/Containers/Reports/Details/Components/Table/TableRow.tsx +++ b/src/Containers/Reports/Details/Components/Table/TableRow.tsx @@ -54,21 +54,17 @@ const TableRow: FunctionComponent = ({ return ( <> - {headers.map(({ key }, index) => ( - <> - {expandRows && index === 0 && ( - - + {expandRows && ( + ))} {expandRows && ( diff --git a/src/Containers/Reports/Details/Components/Table/index.tsx b/src/Containers/Reports/Details/Components/Table/index.tsx index c2b5ef495..534a73731 100644 --- a/src/Containers/Reports/Details/Components/Table/index.tsx +++ b/src/Containers/Reports/Details/Components/Table/index.tsx @@ -28,7 +28,7 @@ const ReportTable: FunctionComponent = ({ - {expandRows && } + {expandRows && {expandRows && ))} diff --git a/src/Containers/Reports/List/List.js b/src/Containers/Reports/List/List.js index e5d229362..ec1c40392 100644 --- a/src/Containers/Reports/List/List.js +++ b/src/Containers/Reports/List/List.js @@ -28,6 +28,7 @@ const List = () => { ( - + From 4be737425eac419d3e18ecfc443cf8edab4e820e Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Tue, 19 Oct 2021 13:45:52 -0400 Subject: [PATCH 35/71] changed data-cy to data-testid --- src/Components/Toolbar/Groups/CategoryDropdown.tsx | 2 +- src/Containers/Reports/Details/Components/Table/index.tsx | 2 +- src/Containers/Reports/List/List.js | 2 +- src/Containers/Reports/List/ListItem/index.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Toolbar/Groups/CategoryDropdown.tsx b/src/Components/Toolbar/Groups/CategoryDropdown.tsx index 07007b9a3..d2ea36aa7 100644 --- a/src/Components/Toolbar/Groups/CategoryDropdown.tsx +++ b/src/Components/Toolbar/Groups/CategoryDropdown.tsx @@ -24,7 +24,7 @@ const CategoryDropdown: FunctionComponent = ({ }) => { const [isExpanded, setIsExpanded] = useState(false); return ( - + {expandRows && ))} diff --git a/src/Containers/Reports/List/List.js b/src/Containers/Reports/List/List.js index ec1c40392..fad730b3e 100644 --- a/src/Containers/Reports/List/List.js +++ b/src/Containers/Reports/List/List.js @@ -28,7 +28,7 @@ const List = () => { ( - + From 3fde137333e4515fcb163672e744bbe51304335e Mon Sep 17 00:00:00 2001 From: Mat Wilson Date: Tue, 19 Oct 2021 11:12:22 -0700 Subject: [PATCH 36/71] reenable remaining dash tests --- cypress/integration/Dashboard.spec.js | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/cypress/integration/Dashboard.spec.js b/cypress/integration/Dashboard.spec.js index bd44c1dc1..9c04521f1 100644 --- a/cypress/integration/Dashboard.spec.js +++ b/cypress/integration/Dashboard.spec.js @@ -144,8 +144,8 @@ describe('Dashboard page filter tests', () => { const screenshotFilename = 'clusters_filter_by_quickDateRange.png'; cy.screenshot(screenshotFilename); }); -//FIXME - it.skip('Can filter by a custom date range', () => { + + it('Can filter by a custom date range', () => { const today = moment(new Date().toISOString()).format('YYYY-MM-DD'); const oneWeekAgo = moment(new Date().toISOString()) .subtract(1, 'week') @@ -367,8 +367,7 @@ describe('Dashboard page drilldown tests', () => { cy.screenshot(screenshotFilename); }); - // FIX - it.skip('Can navigate to job explorer from top templates modal', () => { + it('Can navigate to job explorer from top templates modal', () => { const todayminusone = moment(new Date().toISOString()) .subtract(1, 'day') .format('M/D'); @@ -420,21 +419,8 @@ describe('Dashboard page drilldown tests', () => { cy.get('#pf-modal-part-0').find('a').contains('View all jobs').click(); // Verify the redirect to Job explorer cy.get(appid).find('.pf-c-title').contains('Job Explorer'); - // Verify the organization and date range filter is carried correctly to Job Explorer page - cy.get(toolBarChipGroup) - .find('span') - .contains('Organization') - .siblings() - .find('span') - .contains('No organization'); cy.get('div[data-cy="quick_date_range"]').contains('Past 62 days'); cy.get(toolBarChipGroup).find('span').contains('Template'); - cy.get(toolBarChipGroup) - .find('span') - .contains('Job') - .siblings() - .find('span') - .should('not.contain', 'Playbook run'); const screenshotFilename = 'clusters_drilldown_top_templates.png'; cy.screenshot(screenshotFilename); }); From 13bbf849da4470d3e2b29abe96a3b93ce01e12ee Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Tue, 19 Oct 2021 15:08:00 -0400 Subject: [PATCH 37/71] do not load toolbars if options endpoint does not return data - Added async/await when fetching options from plan_options endpoint - changed `renderOptionsBasedValue` function to return/display raw value in the Plan Card instead of getting nice display value if `options` were not set for some reason. --- src/Containers/SavingsPlanner/List/List.js | 12 +++++++----- src/Containers/SavingsPlanner/List/ListItem/index.js | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Containers/SavingsPlanner/List/List.js b/src/Containers/SavingsPlanner/List/List.js index 3bd8a43ee..8c02ea40b 100644 --- a/src/Containers/SavingsPlanner/List/List.js +++ b/src/Containers/SavingsPlanner/List/List.js @@ -49,11 +49,13 @@ const List = () => { const { result: options, - error, isSuccess, request: fetchOptions, } = useRequest( - useCallback(() => readPlanOptions(), [queryParams]), + useCallback(async () => { + const response = await readPlanOptions(); + return response || {}; + }, [queryParams]), {} ); @@ -61,6 +63,7 @@ const List = () => { result: { data, rbac, count }, isLoading: itemsIsLoading, isSuccess: itemsIsSuccess, + error: itemsError, request: fetchEndpoints, } = useRequest( useCallback(async () => { @@ -108,7 +111,7 @@ const List = () => { }; const renderContent = () => { - if (error) return ; + if (itemsError) return ; if (itemsIsLoading || deleteLoading) return ; if ( itemsIsSuccess && @@ -141,8 +144,7 @@ const List = () => { '2xl': '307px', }} > - {isSuccess && - itemsIsSuccess && + {itemsIsSuccess && data.map((datum) => ( { - return options[key].find(({ key: apiValue }) => apiValue === val).value; + return options[key] + ? options[key].find(({ key: apiValue }) => apiValue === val).value + : val; }; const kebabDropDownItems = [ From 261df147f0aa4509438b6d5b425863f64e01636d Mon Sep 17 00:00:00 2001 From: Mat Wilson Date: Tue, 19 Oct 2021 17:28:13 -0700 Subject: [PATCH 38/71] add reports landing page test --- cypress/integration/Reports.spec.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cypress/integration/Reports.spec.js b/cypress/integration/Reports.spec.js index 56dde142e..0c529115d 100644 --- a/cypress/integration/Reports.spec.js +++ b/cypress/integration/Reports.spec.js @@ -9,13 +9,19 @@ const hbo = 'hosts_by_organization'; const jtbo = 'jobs_and_tasks_by_organization'; const texp = 'templates_explorer'; +const allReports = [hcbjt, cmbjt, jtrr, hbo, jtbo, texp]; + describe('Reports page smoketests', () => { beforeEach(() => { cy.loginFlow(); cy.visit(reportsUrl); }); - it.skip('All report cards are displayed on main reports page', () => {}); + it('All report cards are displayed on main reports page', () => { + allReports.forEach(function (item) { + cy.get(`[data-testid="${item}"]`).should('exist'); + }); + }); }); describe('Report: Hosts Changed By Job Template Smoketests', () => { @@ -33,7 +39,7 @@ describe('Report: Hosts Changed By Job Template Smoketests', () => { it('Can change lookback', () => { cy.get('[data-cy="quick_date_range"]').click(); - cy.get('.pf-c-select__menu-item').contains('Past year').click() + cy.get('.pf-c-select__menu-item').contains('Past year').click(); }); }); @@ -52,7 +58,7 @@ describe('Report: Changes Made By Job Template Smoketests', () => { it('Can change lookback', () => { cy.get('[data-cy="quick_date_range"]').click(); - cy.get('.pf-c-select__menu-item').contains('Past year').click() + cy.get('.pf-c-select__menu-item').contains('Past year').click(); }); }); @@ -70,7 +76,7 @@ describe('Report: Job Template Run Rate Smoketests', () => { }); it('Can change lookback', () => { cy.get('[data-cy="quick_date_range"]').click(); - cy.get('.pf-c-select__menu-item').contains('Past year').click() + cy.get('.pf-c-select__menu-item').contains('Past year').click(); }); }); @@ -88,7 +94,7 @@ describe('Report: Hosts By Organization Smoketests', () => { }); it('Can change lookback', () => { cy.get('[data-cy="quick_date_range"]').click(); - cy.get('.pf-c-select__menu-item').contains('Past 62 days').click() + cy.get('.pf-c-select__menu-item').contains('Past 62 days').click(); }); }); @@ -106,7 +112,7 @@ describe('Report: Jobs and Tasks By Organization Smoketests', () => { }); it('Can change lookback', () => { cy.get('[data-cy="quick_date_range"]').click(); - cy.get('.pf-c-select__menu-item').contains('Past 62 days').click() + cy.get('.pf-c-select__menu-item').contains('Past 62 days').click(); }); }); @@ -118,6 +124,6 @@ describe('Report: Templates Explorer Smoketests', () => { it('Can change lookback', () => { cy.get('[data-cy="quick_date_range"]').click(); - cy.get('.pf-c-select__menu-item').contains('Past year').click() + cy.get('.pf-c-select__menu-item').contains('Past year').click(); }); }); From eac6fdcdd26aed0f5947bb0c06b3b0cde6c4d2f3 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 20 Oct 2021 10:12:35 +0200 Subject: [PATCH 39/71] All feature flags are enabled when the url hostname is localhost --- src/FeatureFlags/useFeatureFlag.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/FeatureFlags/useFeatureFlag.ts b/src/FeatureFlags/useFeatureFlag.ts index c38ea9564..6bbd1113b 100644 --- a/src/FeatureFlags/useFeatureFlag.ts +++ b/src/FeatureFlags/useFeatureFlag.ts @@ -3,6 +3,7 @@ import Context from './Context'; import { ValidFeatureFlags } from './types'; const isBeta = () => window.location.pathname.split('/')[1] === 'beta'; +const isLocalhost = () => window.location.hostname === 'localhost'; const useFeatureFlag = (flag: ValidFeatureFlags): boolean => { const features = useContext(Context); @@ -14,6 +15,7 @@ const useFeatureFlag = (flag: ValidFeatureFlags): boolean => { ({ name }) => name === (isBeta() ? betaFlag : flag) ); + if (isLocalhost()) return true; return !!feature && feature.enabled; }; From 28e89ba0e69c671410ef5db072ddf36995f592fc Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 20 Oct 2021 11:08:04 +0200 Subject: [PATCH 40/71] Got the content size for downloadinf PDF to show progress --- src/Api/methods.ts | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/Api/methods.ts b/src/Api/methods.ts index 7068e50f7..7d8afcd85 100644 --- a/src/Api/methods.ts +++ b/src/Api/methods.ts @@ -43,28 +43,31 @@ export const postWithFileReturn = ( endpoint: string, params: PDFParams ): Promise => { - // Create the service worker on user interaction. - const date = new Intl.DateTimeFormat('en-US').format(new Date()); - const fileStream = createWriteStream( - `${params.slug}_${date}.pdf`.replace(/\s/g, '_') - ); const url = new URL(endpoint, window.location.origin); return authenticatedFetch(url.toString(), { method: 'POST', body: JSON.stringify(params), }) - .then((response) => - response.ok - ? response // If reposnse is ok, then continue to download the PDF + .then((response) => { + return response.ok + ? // If reposnse is ok, then continue to download the PDF + { response, size: response.headers.get('content-length') } : response // Else it is an error and we have to parse it as a json .json() .then((error: ApiJson) => Promise.reject({ status: response.status, error }) - ) - ) - .then((data) => data.body) - .then((stream) => { - if (stream) return saveStream(stream, fileStream); + ); + }) + .then(({ response, size }) => { + const date = new Intl.DateTimeFormat('en-US').format(new Date()); + const nSize = size ? +size : undefined; + const fileStream = createWriteStream( + `${params.slug}_${date}.pdf`.replace(/\s/g, '_'), + { + size: nSize, + } + ); + if (response.body) return saveStream(response.body, fileStream); }); }; From 26c21c000e9a9c7c9994ec48eddce46bf04a2b0a Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Wed, 20 Oct 2021 17:19:24 -0400 Subject: [PATCH 41/71] disabled next button and side nav on invalid entry --- .../Shared/Form/Steps/Details/index.js | 25 +++++++++++++ .../SavingsPlanner/Shared/Form/index.js | 36 ++++++++----------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js b/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js index 8c6501a82..1f51b9554 100644 --- a/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js +++ b/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js @@ -9,8 +9,11 @@ import { SelectOption, TextInput, NumberInput, + FormHelperText, } from '@patternfly/react-core'; +import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; + import { actions } from '../../../constants'; import { isPositiveNum } from '../../../../../../Utilities/helpers'; @@ -31,6 +34,15 @@ const Details = ({ options, formData, dispatch }) => { label="What do you want to automate?" isRequired fieldId="name-field" + // helperText={ + // } + // isHidden={formData.name} + // > + // Name is required + // + // } > { value: newName, }) } + onFocus={() => { + if (!formData.name || !formData.name === '') { + return ( + } + isHidden={formData.name} + > + Name is required + + ); + } + }} /> diff --git a/src/Containers/SavingsPlanner/Shared/Form/index.js b/src/Containers/SavingsPlanner/Shared/Form/index.js index 2ae11e01d..d66a2021d 100644 --- a/src/Containers/SavingsPlanner/Shared/Form/index.js +++ b/src/Containers/SavingsPlanner/Shared/Form/index.js @@ -4,7 +4,6 @@ import { useHistory, useLocation, Redirect } from 'react-router-dom'; import { Button, - Tooltip, Wizard, WizardFooter, WizardContextConsumer, @@ -45,7 +44,6 @@ const Form = ({ title, options, data = {} }) => { ); const { formData, requestPayload, dispatch } = usePlanData(data); - const steps = [ { step_number: 1, @@ -60,6 +58,7 @@ const Form = ({ title, options, data = {} }) => { id: 'tasks', name: 'Tasks', component: , + canJumpTo: formData.name, }, { step_number: 3, @@ -68,6 +67,7 @@ const Form = ({ title, options, data = {} }) => { component: ( ), + canJumpTo: formData.name, nextButtonText: 'Save', }, ]; @@ -79,7 +79,12 @@ const Form = ({ title, options, data = {} }) => { if (activeStep.step_number !== 3) { return ( <> - {activeStep.step_number !== 1 && ( @@ -96,25 +101,14 @@ const Form = ({ title, options, data = {} }) => { // Final step buttons return ( <> - -
- -
-
+ Save + From aecca3a3599656f3dc2312152dacd1672e3a4635 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 6 Oct 2021 09:36:21 +0200 Subject: [PATCH 42/71] Modified the dev config so it can proxy to stage --- config/dev.webpack.config.js | 53 ++++++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/config/dev.webpack.config.js b/config/dev.webpack.config.js index 19490b0f4..84b90a419 100644 --- a/config/dev.webpack.config.js +++ b/config/dev.webpack.config.js @@ -5,28 +5,47 @@ const { defaultServices, } = require('@redhat-cloud-services/frontend-components-config-utilities/standalone'); +// TODO: Add 'prod' - currently it is not wokring while returns +// errors on backend queries: strict cross origin policy +const validEnvValues = ['standalone', 'stage']; + +const proxy = validEnvValues.includes(process.env.npm_config_env) + ? process.env.npm_config_env + : 'standalone'; + +const environmentSetup = { + ...(proxy === 'standalone' && { + https: false, + standalone: { + apiAnalytics: { + context: ['/api/tower-analytics'], + target: 'http://localhost:8004', + }, + rbac, + ...defaultServices, + }, + registry: [ + ({ app }) => + app.get('(/beta)?/config/chrome/ansible-navigation.json', (_req, res) => + res.sendFile(resolve(__dirname, './ansible-navigation.json')) + ), + ], + }), + ...(['prod', 'stage'].includes(proxy) && { + https: true, + useProxy: true, + proxyVerbose: true, + env: `${proxy}-beta`, + }), +}; + const { config: webpackConfig, plugins } = config({ rootFolder: resolve(__dirname, '../'), debug: true, sassPrefix: '.automation-analytics, .automationAnalytics', - https: false, - standalone: { - apiAnalytics: { - context: ['/api/tower-analytics'], - target: 'http://localhost:8004', - }, - rbac, - ...defaultServices, - }, - registry: [ - ({ app }) => - app.get('(/beta)?/config/chrome/ansible-navigation.json', (_req, res) => - res.sendFile(resolve(__dirname, './ansible-navigation.json')) - ), - ], + ...environmentSetup, appUrl: ['/beta/ansible/insights/', '/ansible/insights/'], - proxyVerbose: true, - ...(process.env.BETA && { deployment: 'beta/apps' }), + deployment: 'beta/apps', }); plugins.push( diff --git a/package.json b/package.json index 6713cb13b..43f3bce9a 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "integration:headless": "cypress run --browser=chrome", "lint": "(eslint config src) && (stylelint 'src/**/*.scss' --config .stylelintrc.json)", "lint:fix": "eslint config src --fix", - "start": "BETA=true NODE_ENV=development webpack serve --config config/dev.webpack.config.js", + "start": "NODE_ENV=development webpack serve --config config/dev.webpack.config.js", "start:container": "NODE_ENV=development webpack serve --config config/dev.webpack.config.js --host 0.0.0.0", "build:prod": "NODE_ENV=production webpack --config config/prod.webpack.config.js", "deploy": "npm-run-all build:prod lint test", From 19f136d8e598d1832ee8c3c1c5e5b1ebed35a141 Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Wed, 6 Oct 2021 09:38:49 +0200 Subject: [PATCH 43/71] Updated readme for the new proxy option --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 81f76cbf7..a2bac1af1 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,12 @@ Automation Analytics provides data analytics for Ansible Tower that provides vis 3. `npm start` - starts standalone: webpack serves the files alongside with insights, rbac and keycloak. 4. Go to `http://localhost:1337/beta/ansible/insights` and use the admin/admin credentials to login. +#### Developing against a deployed backend + +1. `npm ci` - install dependencies from the lockfile +2. `npm start --env=stage` - starts local frontend while proxying all the request to the stage environment. +3. Follow the link the proxy outputs to the terminal - this is different from env to env. You need valid credentials for the environment you are running against to be able to log in + ### Testing - `npm run lint` - runs eslint From dfe869a2d260e82d40a37a0e6953d9bc3b257dff Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Mon, 11 Oct 2021 16:23:23 +0200 Subject: [PATCH 44/71] Added the option to run agains an ephemeral env --- README.md | 6 + config/dev.webpack.config.js | 23 +- package-lock.json | 853 ++++++++++++++++++++++++++--------- package.json | 2 +- 4 files changed, 661 insertions(+), 223 deletions(-) diff --git a/README.md b/README.md index a2bac1af1..d60aaf09f 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,12 @@ Automation Analytics provides data analytics for Ansible Tower that provides vis 2. `npm start --env=stage` - starts local frontend while proxying all the request to the stage environment. 3. Follow the link the proxy outputs to the terminal - this is different from env to env. You need valid credentials for the environment you are running against to be able to log in +#### Developing against a backend on the ephemeral + +1. `npm ci` - install dependencies from the lockfile +2. `npm start --env=eph --eph_id=YOUR_EPH_ID` - starts local frontend while proxying all the request to the eph environment. +3. Follow the link the proxy outputs to the terminal - this is different from env to env. You need valid credentials for the environment you are running against to be able to log in + ### Testing - `npm run lint` - runs eslint diff --git a/config/dev.webpack.config.js b/config/dev.webpack.config.js index 84b90a419..374bbc97c 100644 --- a/config/dev.webpack.config.js +++ b/config/dev.webpack.config.js @@ -7,14 +7,17 @@ const { // TODO: Add 'prod' - currently it is not wokring while returns // errors on backend queries: strict cross origin policy -const validEnvValues = ['standalone', 'stage']; +const validEnvValues = ['standalone', 'stage', 'eph']; -const proxy = validEnvValues.includes(process.env.npm_config_env) +const env = validEnvValues.includes(process.env.npm_config_env) ? process.env.npm_config_env : 'standalone'; +// Only when using ephemeral environment +const ephId = process.env.npm_config_eph_id ?? '1'; + const environmentSetup = { - ...(proxy === 'standalone' && { + ...(env === 'standalone' && { https: false, standalone: { apiAnalytics: { @@ -31,11 +34,19 @@ const environmentSetup = { ), ], }), - ...(['prod', 'stage'].includes(proxy) && { + ...(['prod', 'stage'].includes(env) && { https: true, useProxy: true, proxyVerbose: true, - env: `${proxy}-beta`, + env: `${env}-beta`, + }), + ...(['eph'].includes(env) && { + https: true, + useProxy: true, + proxyVerbose: true, + env: 'qa-beta', // TODO change to whatewer the aggregator pulls data from + keycloakUri: `https://keycloak-ephemeral-${ephId}.apps.c-rh-c-eph.8p0c.p1.openshiftapps.com`, + target: `https://front-end-aggregator-ephemeral-${ephId}.apps.c-rh-c-eph.8p0c.p1.openshiftapps.com`, }), }; @@ -43,9 +54,9 @@ const { config: webpackConfig, plugins } = config({ rootFolder: resolve(__dirname, '../'), debug: true, sassPrefix: '.automation-analytics, .automationAnalytics', - ...environmentSetup, appUrl: ['/beta/ansible/insights/', '/ansible/insights/'], deployment: 'beta/apps', + ...environmentSetup, }); plugins.push( diff --git a/package-lock.json b/package-lock.json index a06567863..972148c09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.13.0", "@redhat-cloud-services/eslint-config-redhat-cloud-services": "^1.2.1", - "@redhat-cloud-services/frontend-components-config": "^4.3.5", + "@redhat-cloud-services/frontend-components-config": "^4.4.1", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.1.0", "@testing-library/react-hooks": "^7.0.2", @@ -2890,22 +2890,24 @@ } }, "node_modules/@redhat-cloud-services/frontend-components-config": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-4.3.9.tgz", - "integrity": "sha512-Rdphv9jKtHuhqW2iLHlwdPGG24xlp3PaPQVfzWS3U3Zj6iOQOE00UdhBnyQ+L8zG1DXhTok3e2twzYirlh3RKQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-4.4.1.tgz", + "integrity": "sha512-UgTqLe3JMXTLsiWwrEN/++KklegFt/QGG80S4hpFJ0ittD1e2K7vvZsTZlBqhmrntWcsZWE/KrHF7vMPEktKkA==", "dev": true, "dependencies": { - "@redhat-cloud-services/frontend-components-config-utilities": "^1.4.16", + "@redhat-cloud-services/frontend-components-config-utilities": "^1.4.17", "assert": "^2.0.0", "babel-loader": "^8.2.2", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "clean-webpack-plugin": "^3.0.0", + "concurrently": "^6.3.0", "css-loader": "^5.2.6", "git-revision-webpack-plugin": "^3.0.6", "glob": "^7.0.0", "html-replace-webpack-plugin": "^2.6.0", "html-webpack-plugin": "^5.3.1", + "http-server": "^13.0.2", "https-proxy-agent": "^5.0.0", "js-yaml": "^4.0.0", "jws": "^4.0.0", @@ -2922,13 +2924,17 @@ "webpack": "^5.55.1", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.3.0", - "write-file-webpack-plugin": "^4.5.1" + "write-file-webpack-plugin": "^4.5.1", + "yargs": "^17.2.1" + }, + "bin": { + "fec": "bin/fec.js" } }, "node_modules/@redhat-cloud-services/frontend-components-config-utilities": { - "version": "1.4.16", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config-utilities/-/frontend-components-config-utilities-1.4.16.tgz", - "integrity": "sha512-TCp7FMAKYKqtk2uivEor2iq30zbFaon/SCf9ToMq6n/nSRGdkkxBAs6gweK3y43vUJD3N1Dpx41kOTFMwxFV/A==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config-utilities/-/frontend-components-config-utilities-1.5.1.tgz", + "integrity": "sha512-e0dxHZZRW4QSEP7aNSmgb5T+/hQanSOnqj/gkz4/pTpAspkelpyStK4DtXxP2eZCQ4Ozme/jxo4J+EiRDEbBNg==", "dev": true, "peerDependencies": { "webpack": "^5.0.0" @@ -2965,6 +2971,17 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@redhat-cloud-services/frontend-components-config/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/@redhat-cloud-services/frontend-components-config/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3122,6 +3139,33 @@ "webpack": "*" } }, + "node_modules/@redhat-cloud-services/frontend-components-config/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@redhat-cloud-services/frontend-components-config/node_modules/yargs": { + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", + "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@redhat-cloud-services/frontend-components-utilities": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-utilities/-/frontend-components-utilities-3.2.5.tgz", @@ -3308,9 +3352,9 @@ } }, "node_modules/@testing-library/dom": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.9.0.tgz", - "integrity": "sha512-fhmAYtGpFqzKdPq5aLNn/T396qfhYkttHT/5RytdDNSCzg9K/0F/WXF5iDsNBK1M3ZIQbPy7Y0qm4Kup5bqT/w==", + "version": "8.7.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.7.2.tgz", + "integrity": "sha512-2zN0Zv9dMnaMAd4c/1E1ZChu4QrICyvWtkUvHFQBPhS1oG3VYGcM7SLGLYdda7187ILRXzIUOvOsbXQm4EASjA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", @@ -3754,9 +3798,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.10.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.9.tgz", - "integrity": "sha512-H9ReOt+yqIJPCutkTYjFjlyK6WEMQYT9hLZMlWtOjFQY2ItppsWZ6RJf8Aw+jz5qTYceuHvFgPIaKOHtLAEWBw==", + "version": "16.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", + "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -3783,9 +3827,9 @@ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "node_modules/@types/react": { - "version": "17.0.29", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.29.tgz", - "integrity": "sha512-HSenIfBEBZ70BLrrVhtEtHpqaP79waauPtA8XKlczTxL3hXrW/ElGNLTpD1TmqkykgGlOAK55+D3SmUHEirpFw==", + "version": "17.0.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.27.tgz", + "integrity": "sha512-zgiJwtsggVGtr53MndV7jfiUESTqrbxOcBvwfe6KS/9bzaVPCTDieTWnFNecVNx6EAaapg5xsLLWFfHHR437AA==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4900,12 +4944,6 @@ "url": "https://tidelift.com/funding/github/npm/autoprefixer" } }, - "node_modules/autoprefixer/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "node_modules/autoprefixer/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -5350,6 +5388,15 @@ } ] }, + "node_modules/basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -5507,16 +5554,16 @@ } }, "node_modules/browserslist": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", - "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", + "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001265", - "electron-to-chromium": "^1.3.867", + "caniuse-lite": "^1.0.30001264", + "electron-to-chromium": "^1.3.857", "escalade": "^3.1.1", - "node-releases": "^2.0.0", - "picocolors": "^1.0.0" + "node-releases": "^1.1.77", + "picocolors": "^0.2.1" }, "bin": { "browserslist": "cli.js" @@ -6210,7 +6257,6 @@ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, - "optional": true, "engines": { "node": ">=0.1.90" } @@ -6307,6 +6353,151 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/concurrently": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.3.0.tgz", + "integrity": "sha512-k4k1jQGHHKsfbqzkUszVf29qECBrkvBKkcPJEUDTyVR7tZd1G/JOfnst4g1sYbFvJ4UjHZisj1aWQR8yLKpGPw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "bin": { + "concurrently": "bin/concurrently.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/concurrently/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/concurrently/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concurrently/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/concurrently/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", @@ -6371,9 +6562,9 @@ } }, "node_modules/core-js": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.3.tgz", - "integrity": "sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw==", + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.2.tgz", + "integrity": "sha512-zNhPOUoSgoizoSQFdX1MeZO16ORRb9FFQLts8gSYbZU5FcgXhp24iMWMxnOQo5uIaIG7/6FA/IqJPwev1o9ZXQ==", "dev": true, "hasInstallScript": true, "funding": { @@ -6382,9 +6573,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz", - "integrity": "sha512-4zP6/y0a2RTHN5bRGT7PTq9lVt3WzvffTNjqnTKsXhkAYNDTkdCLOIfAdOLcQ/7TDdyRj3c+NeHe1NmF1eDScw==", + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.2.tgz", + "integrity": "sha512-25VJYCJtGjZwLguj7d66oiHfmnVw3TMOZ0zV8DyMJp/aeQ3OjR519iOOeck08HMyVVRAqXxafc2Hl+5QstJrsQ==", "dev": true, "dependencies": { "browserslist": "^4.17.3", @@ -6405,9 +6596,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.18.3.tgz", - "integrity": "sha512-qfskyO/KjtbYn09bn1IPkuhHl5PlJ6IzJ9s9sraJ1EqcuGyLGKzhSM1cY0zgyL9hx42eulQLZ6WaeK5ycJCkqw==", + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.18.2.tgz", + "integrity": "sha512-4hMMLUlZhKJKOWbbGD1/VDUxGPEhEoN/T01k7bx271WiBKCvCfkgPzy0IeRS4PB50p6/N1q/SZL4B/TRsTE5bA==", "dev": true, "hasInstallScript": true, "funding": { @@ -6421,6 +6612,15 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -6683,9 +6883,9 @@ } }, "node_modules/cypress/node_modules/@types/node": { - "version": "14.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.26.tgz", - "integrity": "sha512-eSTNkK/nfmnC7IKpOJZixDgG0W2/eHz1qyFN7o/rwwwIHsVRp+G9nbh4BrQ77kbQ2zPu286AQRxkuRLPcR3gXw==", + "version": "14.17.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.21.tgz", + "integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA==", "dev": true }, "node_modules/cypress/node_modules/ansi-styles": { @@ -7114,6 +7314,19 @@ "node": ">=10" } }, + "node_modules/date-fns": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", + "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==", + "dev": true, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/dayjs": { "version": "1.10.7", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", @@ -7614,9 +7827,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.3.867", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.867.tgz", - "integrity": "sha512-WbTXOv7hsLhjJyl7jBfDkioaY++iVVZomZ4dU6TMe/SzucV6mUAs2VZn/AehBwuZMiNEQDaPuTGn22YK5o+aDw==", + "version": "1.3.866", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.866.tgz", + "integrity": "sha512-iYze6TpDXWxk+sfcpUUdTs6Pv/3kG45Pnjer2DxEeFw0N08bZeNLuz97s2lMgy8yObon48o0WHY2Bkg3xuAPOA==", "dev": true }, "node_modules/emittery": { @@ -10136,6 +10349,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/http-server": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-13.0.2.tgz", + "integrity": "sha512-R8kvPT7qp11AMJWLZsRShvm6heIXdlR/+tL5oAWNG/86A/X+IAFX6q0F9SA2G+dR5aH/759+9PLH0V34Q6j4rg==", + "dev": true, + "dependencies": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "he": "^1.1.0", + "http-proxy": "^1.18.0", + "mime": "^1.6.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^2.0.5" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/http-server/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -11163,9 +11414,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", - "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-bFjUnc95rHjdCR63WMHUS7yfJJh8T9IPSWavvR02hhjVwezWALZ5axF9EqjmwZHpXqkzbgAMP8DmAtiyNxrdrQ==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -14449,9 +14700,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", - "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", "dev": true }, "node_modules/normalize-package-data": { @@ -15249,10 +15500,9 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" }, "node_modules/picomatch": { "version": "2.3.0", @@ -15513,12 +15763,6 @@ "node": ">=6.14.4" } }, - "node_modules/postcss-less/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "node_modules/postcss-less/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -15628,12 +15872,6 @@ "node": ">=6.0.0" } }, - "node_modules/postcss-safe-parser/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "node_modules/postcss-safe-parser/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -15670,12 +15908,6 @@ "postcss": "^7.0.21" } }, - "node_modules/postcss-sass/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "node_modules/postcss-sass/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -15714,12 +15946,6 @@ "node": ">=6.0.0" } }, - "node_modules/postcss-scss/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "node_modules/postcss-scss/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -15774,11 +16000,6 @@ "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", "dev": true }, - "node_modules/postcss/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -17374,9 +17595,9 @@ } }, "node_modules/sanitize-html": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.5.2.tgz", - "integrity": "sha512-sJ1rO2YixFIqs2kIcEUb6PTrCjvz8DMq1XqWWuy0kjgjrn58GNLK1DKSIRybFZDO1WNgsEgD+WiEzTEYS8xEug==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.5.1.tgz", + "integrity": "sha512-hUITPitQk+eFNLtr4dEkaaiAJndG2YE87IOpcfBSL1XdklWgwcNDJdr9Ppe8QKL/C3jFt1xH/Mbj20e0GZQOfg==", "dependencies": { "deepmerge": "^4.2.2", "escape-string-regexp": "^4.0.0", @@ -17486,6 +17707,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -18184,6 +18411,12 @@ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, "node_modules/spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -18868,12 +19101,6 @@ "node": ">=8" } }, - "node_modules/stylelint/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "node_modules/stylelint/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -18921,12 +19148,6 @@ "postcss": "^7.0.2" } }, - "node_modules/sugarss/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "node_modules/sugarss/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -19509,6 +19730,15 @@ "punycode": "^2.1.0" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -19732,9 +19962,9 @@ } }, "node_modules/typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -19826,6 +20056,18 @@ "node": ">=8" } }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -19987,6 +20229,12 @@ "querystring": "0.2.0" } }, + "node_modules/url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, "node_modules/url/node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -20531,9 +20779,9 @@ } }, "node_modules/webpack": { - "version": "5.58.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.58.2.tgz", - "integrity": "sha512-3S6e9Vo1W2ijk4F4PPWRIu6D/uGgqaPmqw+av3W3jLDujuNkdxX5h5c+RQ6GkjVR+WwIPOfgY8av+j5j4tMqJw==", + "version": "5.58.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.58.1.tgz", + "integrity": "sha512-4Z/dmbTU+VmkCb2XNgW7wkE5TfEcSooclprn/UEuVeAkwHhn07OcgUsyaKHGtCY/VobjnsYBlyhKeMLiSoOqPg==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.0", @@ -23525,22 +23773,24 @@ } }, "@redhat-cloud-services/frontend-components-config": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-4.3.9.tgz", - "integrity": "sha512-Rdphv9jKtHuhqW2iLHlwdPGG24xlp3PaPQVfzWS3U3Zj6iOQOE00UdhBnyQ+L8zG1DXhTok3e2twzYirlh3RKQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-4.4.1.tgz", + "integrity": "sha512-UgTqLe3JMXTLsiWwrEN/++KklegFt/QGG80S4hpFJ0ittD1e2K7vvZsTZlBqhmrntWcsZWE/KrHF7vMPEktKkA==", "dev": true, "requires": { - "@redhat-cloud-services/frontend-components-config-utilities": "^1.4.16", + "@redhat-cloud-services/frontend-components-config-utilities": "^1.4.17", "assert": "^2.0.0", "babel-loader": "^8.2.2", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "clean-webpack-plugin": "^3.0.0", + "concurrently": "^6.3.0", "css-loader": "^5.2.6", "git-revision-webpack-plugin": "^3.0.6", "glob": "^7.0.0", "html-replace-webpack-plugin": "^2.6.0", "html-webpack-plugin": "^5.3.1", + "http-server": "^13.0.2", "https-proxy-agent": "^5.0.0", "js-yaml": "^4.0.0", "jws": "^4.0.0", @@ -23557,7 +23807,8 @@ "webpack": "^5.55.1", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.3.0", - "write-file-webpack-plugin": "^4.5.1" + "write-file-webpack-plugin": "^4.5.1", + "yargs": "^17.2.1" }, "dependencies": { "ansi-styles": { @@ -23579,6 +23830,17 @@ "supports-color": "^7.1.0" } }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -23687,13 +23949,34 @@ "micromatch": "^4.0.0", "semver": "^7.3.4" } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", + "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } } } }, "@redhat-cloud-services/frontend-components-config-utilities": { - "version": "1.4.16", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config-utilities/-/frontend-components-config-utilities-1.4.16.tgz", - "integrity": "sha512-TCp7FMAKYKqtk2uivEor2iq30zbFaon/SCf9ToMq6n/nSRGdkkxBAs6gweK3y43vUJD3N1Dpx41kOTFMwxFV/A==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config-utilities/-/frontend-components-config-utilities-1.5.1.tgz", + "integrity": "sha512-e0dxHZZRW4QSEP7aNSmgb5T+/hQanSOnqj/gkz4/pTpAspkelpyStK4DtXxP2eZCQ4Ozme/jxo4J+EiRDEbBNg==", "dev": true, "requires": {} }, @@ -23854,9 +24137,9 @@ } }, "@testing-library/dom": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.9.0.tgz", - "integrity": "sha512-fhmAYtGpFqzKdPq5aLNn/T396qfhYkttHT/5RytdDNSCzg9K/0F/WXF5iDsNBK1M3ZIQbPy7Y0qm4Kup5bqT/w==", + "version": "8.7.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.7.2.tgz", + "integrity": "sha512-2zN0Zv9dMnaMAd4c/1E1ZChu4QrICyvWtkUvHFQBPhS1oG3VYGcM7SLGLYdda7187ILRXzIUOvOsbXQm4EASjA==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", @@ -24224,9 +24507,9 @@ "dev": true }, "@types/node": { - "version": "16.10.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.9.tgz", - "integrity": "sha512-H9ReOt+yqIJPCutkTYjFjlyK6WEMQYT9hLZMlWtOjFQY2ItppsWZ6RJf8Aw+jz5qTYceuHvFgPIaKOHtLAEWBw==", + "version": "16.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", + "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", "dev": true }, "@types/normalize-package-data": { @@ -24253,9 +24536,9 @@ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "@types/react": { - "version": "17.0.29", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.29.tgz", - "integrity": "sha512-HSenIfBEBZ70BLrrVhtEtHpqaP79waauPtA8XKlczTxL3hXrW/ElGNLTpD1TmqkykgGlOAK55+D3SmUHEirpFw==", + "version": "17.0.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.27.tgz", + "integrity": "sha512-zgiJwtsggVGtr53MndV7jfiUESTqrbxOcBvwfe6KS/9bzaVPCTDieTWnFNecVNx6EAaapg5xsLLWFfHHR437AA==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -25124,12 +25407,6 @@ "postcss-value-parser": "^4.1.0" }, "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -25462,6 +25739,12 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -25603,16 +25886,16 @@ } }, "browserslist": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", - "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", + "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001265", - "electron-to-chromium": "^1.3.867", + "caniuse-lite": "^1.0.30001264", + "electron-to-chromium": "^1.3.857", "escalade": "^3.1.1", - "node-releases": "^2.0.0", - "picocolors": "^1.0.0" + "node-releases": "^1.1.77", + "picocolors": "^0.2.1" } }, "bser": { @@ -26140,8 +26423,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true + "dev": true }, "combined-stream": { "version": "1.0.8", @@ -26222,6 +26504,116 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concurrently": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.3.0.tgz", + "integrity": "sha512-k4k1jQGHHKsfbqzkUszVf29qECBrkvBKkcPJEUDTyVR7tZd1G/JOfnst4g1sYbFvJ4UjHZisj1aWQR8yLKpGPw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, "connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", @@ -26271,15 +26663,15 @@ "dev": true }, "core-js": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.3.tgz", - "integrity": "sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw==", + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.2.tgz", + "integrity": "sha512-zNhPOUoSgoizoSQFdX1MeZO16ORRb9FFQLts8gSYbZU5FcgXhp24iMWMxnOQo5uIaIG7/6FA/IqJPwev1o9ZXQ==", "dev": true }, "core-js-compat": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz", - "integrity": "sha512-4zP6/y0a2RTHN5bRGT7PTq9lVt3WzvffTNjqnTKsXhkAYNDTkdCLOIfAdOLcQ/7TDdyRj3c+NeHe1NmF1eDScw==", + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.2.tgz", + "integrity": "sha512-25VJYCJtGjZwLguj7d66oiHfmnVw3TMOZ0zV8DyMJp/aeQ3OjR519iOOeck08HMyVVRAqXxafc2Hl+5QstJrsQ==", "dev": true, "requires": { "browserslist": "^4.17.3", @@ -26295,9 +26687,9 @@ } }, "core-js-pure": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.18.3.tgz", - "integrity": "sha512-qfskyO/KjtbYn09bn1IPkuhHl5PlJ6IzJ9s9sraJ1EqcuGyLGKzhSM1cY0zgyL9hx42eulQLZ6WaeK5ycJCkqw==", + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.18.2.tgz", + "integrity": "sha512-4hMMLUlZhKJKOWbbGD1/VDUxGPEhEoN/T01k7bx271WiBKCvCfkgPzy0IeRS4PB50p6/N1q/SZL4B/TRsTE5bA==", "dev": true }, "core-util-is": { @@ -26306,6 +26698,12 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, "cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -26517,9 +26915,9 @@ }, "dependencies": { "@types/node": { - "version": "14.17.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.26.tgz", - "integrity": "sha512-eSTNkK/nfmnC7IKpOJZixDgG0W2/eHz1qyFN7o/rwwwIHsVRp+G9nbh4BrQ77kbQ2zPu286AQRxkuRLPcR3gXw==", + "version": "14.17.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.21.tgz", + "integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA==", "dev": true }, "ansi-styles": { @@ -26903,6 +27301,12 @@ } } }, + "date-fns": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", + "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==", + "dev": true + }, "dayjs": { "version": "1.10.7", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", @@ -27306,9 +27710,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.867", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.867.tgz", - "integrity": "sha512-WbTXOv7hsLhjJyl7jBfDkioaY++iVVZomZ4dU6TMe/SzucV6mUAs2VZn/AehBwuZMiNEQDaPuTGn22YK5o+aDw==", + "version": "1.3.866", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.866.tgz", + "integrity": "sha512-iYze6TpDXWxk+sfcpUUdTs6Pv/3kG45Pnjer2DxEeFw0N08bZeNLuz97s2lMgy8yObon48o0WHY2Bkg3xuAPOA==", "dev": true }, "emittery": { @@ -29245,6 +29649,34 @@ } } }, + "http-server": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-13.0.2.tgz", + "integrity": "sha512-R8kvPT7qp11AMJWLZsRShvm6heIXdlR/+tL5oAWNG/86A/X+IAFX6q0F9SA2G+dR5aH/759+9PLH0V34Q6j4rg==", + "dev": true, + "requires": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "he": "^1.1.0", + "http-proxy": "^1.18.0", + "mime": "^1.6.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^2.0.5" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -29954,9 +30386,9 @@ } }, "istanbul-reports": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", - "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-bFjUnc95rHjdCR63WMHUS7yfJJh8T9IPSWavvR02hhjVwezWALZ5axF9EqjmwZHpXqkzbgAMP8DmAtiyNxrdrQ==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -32458,9 +32890,9 @@ } }, "node-releases": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", - "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", "dev": true }, "normalize-package-data": { @@ -33071,10 +33503,9 @@ "dev": true }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" }, "picomatch": { "version": "2.3.0", @@ -33186,13 +33617,6 @@ "nanoid": "^3.1.28", "picocolors": "^0.2.1", "source-map-js": "^0.6.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - } } }, "postcss-html": { @@ -33284,12 +33708,6 @@ "postcss": "^7.0.14" }, "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -33365,12 +33783,6 @@ "postcss": "^7.0.26" }, "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -33399,12 +33811,6 @@ "postcss": "^7.0.21" }, "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -33432,12 +33838,6 @@ "postcss": "^7.0.6" }, "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -34726,9 +35126,9 @@ } }, "sanitize-html": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.5.2.tgz", - "integrity": "sha512-sJ1rO2YixFIqs2kIcEUb6PTrCjvz8DMq1XqWWuy0kjgjrn58GNLK1DKSIRybFZDO1WNgsEgD+WiEzTEYS8xEug==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.5.1.tgz", + "integrity": "sha512-hUITPitQk+eFNLtr4dEkaaiAJndG2YE87IOpcfBSL1XdklWgwcNDJdr9Ppe8QKL/C3jFt1xH/Mbj20e0GZQOfg==", "requires": { "deepmerge": "^4.2.2", "escape-string-regexp": "^4.0.0", @@ -34794,6 +35194,12 @@ "ajv-keywords": "^3.5.2" } }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -35387,6 +35793,12 @@ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -35882,12 +36294,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -35953,12 +36359,6 @@ "postcss": "^7.0.2" }, "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, "postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", @@ -36401,6 +36801,12 @@ "punycode": "^2.1.0" } }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, "trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -36563,9 +36969,9 @@ } }, "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", "dev": true }, "unbox-primitive": { @@ -36630,6 +37036,15 @@ } } }, + "union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "requires": { + "qs": "^6.4.0" + } + }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -36771,6 +37186,12 @@ } } }, + "url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -37202,9 +37623,9 @@ "dev": true }, "webpack": { - "version": "5.58.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.58.2.tgz", - "integrity": "sha512-3S6e9Vo1W2ijk4F4PPWRIu6D/uGgqaPmqw+av3W3jLDujuNkdxX5h5c+RQ6GkjVR+WwIPOfgY8av+j5j4tMqJw==", + "version": "5.58.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.58.1.tgz", + "integrity": "sha512-4Z/dmbTU+VmkCb2XNgW7wkE5TfEcSooclprn/UEuVeAkwHhn07OcgUsyaKHGtCY/VobjnsYBlyhKeMLiSoOqPg==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", diff --git a/package.json b/package.json index 43f3bce9a..5daabc9c0 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.13.0", "@redhat-cloud-services/eslint-config-redhat-cloud-services": "^1.2.1", - "@redhat-cloud-services/frontend-components-config": "^4.3.5", + "@redhat-cloud-services/frontend-components-config": "^4.4.1", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.1.0", "@testing-library/react-hooks": "^7.0.2", From 9ab34ccf1cc68439173255a79da14b0dbc56dd5b Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Thu, 21 Oct 2021 16:42:19 +0200 Subject: [PATCH 45/71] Updated readme about ephemeral support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d60aaf09f..346851d6c 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Automation Analytics provides data analytics for Ansible Tower that provides vis 2. `npm start --env=stage` - starts local frontend while proxying all the request to the stage environment. 3. Follow the link the proxy outputs to the terminal - this is different from env to env. You need valid credentials for the environment you are running against to be able to log in -#### Developing against a backend on the ephemeral +#### WIP: Developing against a backend on the ephemeral (ephemeral is not supporting it yet) 1. `npm ci` - install dependencies from the lockfile 2. `npm start --env=eph --eph_id=YOUR_EPH_ID` - starts local frontend while proxying all the request to the eph environment. From fa6bc9e7b9b5e1d9190a8116916be4dc0406a6a7 Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Thu, 21 Oct 2021 14:10:16 -0400 Subject: [PATCH 46/71] error text --- .../Shared/Form/Steps/Details/index.js | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js b/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js index 1f51b9554..1885b48d8 100644 --- a/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js +++ b/src/Containers/SavingsPlanner/Shared/Form/Steps/Details/index.js @@ -25,6 +25,11 @@ const Details = ({ options, formData, dispatch }) => { const [categoryIsOpen, setCategoryIsOpen] = useState(false); const [manualTimeIsOpen, setManualTimeIsOpen] = useState(false); const [frequencyPeriodIsOpen, setFrequencyPeriodIsOpen] = useState(false); + const [showError, setShowError] = useState(false); + + const handleFocus = (name) => { + !name || !name === '' ? setShowError(true) : setShowError(false); + }; return (
@@ -34,15 +39,6 @@ const Details = ({ options, formData, dispatch }) => { label="What do you want to automate?" isRequired fieldId="name-field" - // helperText={ - // } - // isHidden={formData.name} - // > - // Name is required - // - // } > { }) } onFocus={() => { - if (!formData.name || !formData.name === '') { - return ( - } - isHidden={formData.name} - > - Name is required - - ); - } + handleFocus(formData.name); }} + onBlur={() => setShowError(false)} /> + {(!formData.name || !formData.name === '') && showError && ( + } + isHidden={!showError} + > + Name is required + + )}
setIsExpanded(!isExpanded), - }} - /> - )} - - {getText(legendEntry, key)} - setIsExpanded(!isExpanded), + }} + /> + )} + {headers.map(({ key }) => ( + {getText(legendEntry, key)}
} {headers.map(({ key, value }) => ( {value} From c9b28e0c84ce24697b9132462b05ade72f4e7ed3 Mon Sep 17 00:00:00 2001 From: Mat Wilson Date: Wed, 13 Oct 2021 09:31:16 -0700 Subject: [PATCH 19/71] bump cypress to 8.6.0; fix timeout on dashboard; savings planner filter --- cypress/integration/Dashboard.spec.js | 9 ++++++--- cypress/integration/SavingsPlanner.spec.js | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cypress/integration/Dashboard.spec.js b/cypress/integration/Dashboard.spec.js index 954d510f0..dac8776da 100644 --- a/cypress/integration/Dashboard.spec.js +++ b/cypress/integration/Dashboard.spec.js @@ -42,9 +42,12 @@ async function fuzzClustersPage() { // click it and wait for the jobexplorer page to load ... cy.get(appid) - .find('#d3-bar-chart-root', { timeout: 1000 }) + .find('#d3-bar-chart-root', { timeout: 3000 }) .should('be.visible'); - cy.get(appid).find('rect').eq(barid).click({ force: true }); + cy.get(appid) + .find('rect') + .eq(barid) + .click({ force: true, waitForAnimations: true }); cy.url().should('include', 'job-explorer'); cy.screenshot('clusters-bar-' + barid + '-jobexplorer-details.png', { capture: 'fullPage', @@ -61,7 +64,7 @@ describe('Dashboard page smoketests', () => { cy.visit(dashboardUrl); }); - it('can interact with the clusters page without breaking the UI', () => { + it.only('can interact with the clusters page without breaking the UI', () => { fuzzClustersPage(); }); diff --git a/cypress/integration/SavingsPlanner.spec.js b/cypress/integration/SavingsPlanner.spec.js index bf9acd3b1..e59c4a938 100644 --- a/cypress/integration/SavingsPlanner.spec.js +++ b/cypress/integration/SavingsPlanner.spec.js @@ -13,7 +13,7 @@ describe('Savings Planner page smoketests', () => { // Add more once fixtures are implemented - other filters are content-dependent. cy.get('[data-cy="sort_options"]').click(); cy.contains('Manual Time').click(); - cy.url().should('include', 'savings-planner.sort_options=manual_time'); + cy.url().should('include', 'sort_options=manual_time'); }); }); diff --git a/package.json b/package.json index 951ac8fe2..60a77e687 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "babel-jest": "^26.6.3", "babel-plugin-lodash": "^3.3.4", "css-loader": "^6.3.0", - "cypress": "^8.5.0", + "cypress": "^8.6.0", "enzyme": "^3.11.0", "enzyme-to-json": "^3.6.2", "eslint": "7.32.0", From d83937d1669a2c077b1b388cc207d7bcaa47cd1a Mon Sep 17 00:00:00 2001 From: Salma Kochay Date: Wed, 13 Oct 2021 16:50:19 -0400 Subject: [PATCH 20/71] various ux improvements --- .../Shared/schemas/affectedHostsByPlaybook.ts | 13 +++++++--- .../Reports/Shared/schemas/changesMade.ts | 13 +++++++--- .../Shared/schemas/hostsByOrganizations.ts | 13 +++++++--- .../Shared/schemas/jobsTasksByOrganization.ts | 13 +++++++--- .../Reports/Shared/schemas/playbookRunRate.ts | 13 +++++++--- .../Shared/schemas/templatesExplorer.ts | 24 ++++++++++++------- 6 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts index c85469837..2fa8e278b 100644 --- a/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts +++ b/src/Containers/Reports/Shared/schemas/affectedHostsByPlaybook.ts @@ -66,8 +66,10 @@ const schemaFnc = ( props: { height: 400, padding: { - top: 10, - right: 100, + top: 40, + bottom: 85, + right: 90, + left: 90, }, domainPadding: { y: 25, @@ -78,6 +80,11 @@ const schemaFnc = ( xAxis: { label: 'Date', tickFormat: xTickFormat, + style: { + axisLabel: { + padding: 50, + }, + }, }, yAxis: { tickFormat: 'formatNumberAsK', @@ -85,7 +92,7 @@ const schemaFnc = ( label, style: { axisLabel: { - padding: 55, + padding: 60, }, }, }, diff --git a/src/Containers/Reports/Shared/schemas/changesMade.ts b/src/Containers/Reports/Shared/schemas/changesMade.ts index 6ca23db07..3cd9ac0b6 100644 --- a/src/Containers/Reports/Shared/schemas/changesMade.ts +++ b/src/Containers/Reports/Shared/schemas/changesMade.ts @@ -68,8 +68,10 @@ const schemaFnc = ( props: { height: 400, padding: { - top: 10, - right: 100, + top: 40, + bottom: 85, + right: 90, + left: 90, }, domainPadding: { y: 25, @@ -80,6 +82,11 @@ const schemaFnc = ( xAxis: { label: 'Date', tickFormat: xTickFormat, + style: { + axisLabel: { + padding: 50, + }, + }, }, yAxis: { tickFormat: 'formatNumberAsK', @@ -87,7 +94,7 @@ const schemaFnc = ( label, style: { axisLabel: { - padding: 55, + padding: 60, }, }, }, diff --git a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts index 451478db5..0eaf0ec9f 100644 --- a/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts +++ b/src/Containers/Reports/Shared/schemas/hostsByOrganizations.ts @@ -66,8 +66,10 @@ const schemaFnc = ( props: { height: 400, padding: { - top: 10, - right: 100, + top: 40, + bottom: 85, + right: 90, + left: 90, }, domainPadding: { y: 25, @@ -78,6 +80,11 @@ const schemaFnc = ( xAxis: { label: 'Date', tickFormat: xTickFormat, + style: { + axisLabel: { + padding: 50, + }, + }, }, yAxis: { tickFormat: 'formatNumberAsK', @@ -85,7 +92,7 @@ const schemaFnc = ( label, style: { axisLabel: { - padding: 55, + padding: 60, }, }, }, diff --git a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts index 21dc2cceb..8dcc3aa90 100644 --- a/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts +++ b/src/Containers/Reports/Shared/schemas/jobsTasksByOrganization.ts @@ -63,8 +63,10 @@ const schemaFnc = ( props: { height: 400, padding: { - top: 10, - right: 100, + top: 40, + bottom: 85, + right: 90, + left: 90, }, domainPadding: { y: 25, @@ -75,6 +77,11 @@ const schemaFnc = ( xAxis: { label: 'Date', tickFormat: xTickFormat, + style: { + axisLabel: { + padding: 50, + }, + }, }, yAxis: { tickFormat: 'formatNumberAsK', @@ -82,7 +89,7 @@ const schemaFnc = ( label, style: { axisLabel: { - padding: 55, + padding: 60, }, }, }, diff --git a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts index a876deea1..c1e87f942 100644 --- a/src/Containers/Reports/Shared/schemas/playbookRunRate.ts +++ b/src/Containers/Reports/Shared/schemas/playbookRunRate.ts @@ -67,8 +67,10 @@ const schemaFnc = ( props: { height: 400, padding: { - top: 10, - right: 100, + top: 40, + bottom: 85, + right: 90, + left: 90, }, domainPadding: { y: 25, @@ -79,6 +81,11 @@ const schemaFnc = ( xAxis: { label: 'Date', tickFormat: xTickFormat, + style: { + axisLabel: { + padding: 50, + }, + }, }, yAxis: { tickFormat: 'formatNumberAsK', @@ -86,7 +93,7 @@ const schemaFnc = ( label, style: { axisLabel: { - padding: 55, + padding: 60, }, }, }, diff --git a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts index 20a2b0f65..8e89ad896 100644 --- a/src/Containers/Reports/Shared/schemas/templatesExplorer.ts +++ b/src/Containers/Reports/Shared/schemas/templatesExplorer.ts @@ -20,7 +20,7 @@ const name = 'Templates explorer'; const description = 'An overview of the job templates that have ran across your Ansible cluster.\n\nYou can use this report to review the status of particular job templates across its job runs, giving you an overview of the times a template fails a job run, a host, or a task. You can also review the host and task status for tasks that fail the most, allowing you to identify any bottlenecks or problems with the templates you are running.'; -const categories = [CATEGORIES.executive]; +const categories = [CATEGORIES.operations]; const defaultTableHeaders: AttributesType = [ { key: 'id', value: 'ID' }, @@ -91,18 +91,26 @@ const schemaFnc = ( type: ChartTopLevelType.chart, parent: null, props: { - height: 600, - domainPadding: { - x: 100, - }, + height: 400, padding: { - bottom: 60, - left: 80, + top: 40, + bottom: 85, + right: 90, + left: 90, + }, + domainPadding: { + y: 25, + x: 85, }, themeColor: ChartThemeColor.multiOrdered, }, xAxis: { label: 'Template', + style: { + axisLabel: { + padding: 50, + }, + }, // It is using names instead of dates so no need for formatting. // tickFormat: xTickFormat, }, @@ -112,7 +120,7 @@ const schemaFnc = ( label, style: { axisLabel: { - padding: 55, + padding: 60, }, }, }, From 57b546a4aed0dfd2a06bd45efda7cfae70cef58c Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Wed, 13 Oct 2021 09:03:42 -0400 Subject: [PATCH 21/71] Open an Alert Modal for reports that do not have PDF implemented yet https://issues.redhat.com/browse/AA-800 --- src/Api/methods.ts | 12 +++++-- src/Components/ErrorDetail/ErrorDetail.js | 11 ++++++- src/Components/Toolbar/DownloadPdfButton.js | 35 +++++++++++++++++++-- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/Api/methods.ts b/src/Api/methods.ts index 82b117b66..a5cc370fe 100644 --- a/src/Api/methods.ts +++ b/src/Api/methods.ts @@ -1,6 +1,6 @@ import { stringify } from 'query-string'; import { ApiJson, Params, ParamsWithPagination } from './types'; - +import { inspect } from 'util' // or directly declare global { interface Window { insights: { @@ -46,7 +46,15 @@ export const postWithFileReturn = ( method: 'POST', body: JSON.stringify(params), }) - .then((data) => data.body) + .then((data) => { + if (data.status === 404) { + return Promise.reject({ + status: data.status, + error: 'PDF layout is not implemented for this report yet' + }); + } + return data.body + }) .then((stream) => new Response(stream)) .then((response) => response.blob()) .then((blob) => { diff --git a/src/Components/ErrorDetail/ErrorDetail.js b/src/Components/ErrorDetail/ErrorDetail.js index 0a44c831e..2e82b41db 100644 --- a/src/Components/ErrorDetail/ErrorDetail.js +++ b/src/Components/ErrorDetail/ErrorDetail.js @@ -35,7 +35,7 @@ function ErrorDetail({ error }) { const handleToggle = () => { setIsExpanded(!isExpanded); }; - + console.log('errrrrrr', error) return ( <> {Array.isArray(error) && error.length && ( @@ -55,6 +55,15 @@ function ErrorDetail({ error }) { )} + {typeof error === 'string' && ( + + +
    +
  • {error}
  • +
+
+
+ )} ); } diff --git a/src/Components/Toolbar/DownloadPdfButton.js b/src/Components/Toolbar/DownloadPdfButton.js index 5f20b3875..7acbbc1e3 100644 --- a/src/Components/Toolbar/DownloadPdfButton.js +++ b/src/Components/Toolbar/DownloadPdfButton.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useState} from 'react'; import PropTypes from 'prop-types'; import { Button, @@ -12,8 +12,13 @@ import { DownloadIcon, ExclamationCircleIcon } from '@patternfly/react-icons'; import useRequest from '../../Utilities/useRequest'; import { useCallback } from 'react'; import { generatePdf } from '../../Api'; +import AlertModal from "../AlertModal"; +import ErrorDetail from "../ErrorDetail"; const DownloadPdfButton = ({ slug, data, y, label, xTickFormat }) => { + const [isModalOpen, setIsModalOpen] = useState(false); + const [isOpen, setIsOpen] = useState(true); + const { error, isLoading, request } = useRequest( useCallback((data) => generatePdf({ @@ -27,7 +32,20 @@ const DownloadPdfButton = ({ slug, data, y, label, xTickFormat }) => { null ); - const getPdfButtonText = (error) => error || 'Download PDF version of report'; + const getPdfButtonText = (error) => { + if (typeof error === 'string') + return error; + + if (typeof error === 'object') + return error?.error; + + return 'Download PDF version of report'; + } + + const toggleModal = async (isOpen) => { + setIsModalOpen(isOpen); + setIsOpen(false); + }; return ( { isDanger={error} > {isLoading && } - {error && } + {!isLoading && error?.status === 404 && isOpen && + { + toggleModal(false); + }} + > + + + } + {!isLoading && error && } {!isLoading && !error && } From 91a1d6fc21630460fad41c50d134587d778ca487 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Wed, 13 Oct 2021 09:05:48 -0400 Subject: [PATCH 22/71] Changes to support PDF implemented yet https://issues.redhat.com/browse/AA-800 --- src/Api/methods.ts | 13 ++-- src/Components/ErrorDetail/ErrorDetail.js | 11 +-- src/Components/Toolbar/DownloadPdfButton.js | 79 +++++++++------------ 3 files changed, 43 insertions(+), 60 deletions(-) diff --git a/src/Api/methods.ts b/src/Api/methods.ts index a5cc370fe..344e7a786 100644 --- a/src/Api/methods.ts +++ b/src/Api/methods.ts @@ -1,6 +1,6 @@ import { stringify } from 'query-string'; import { ApiJson, Params, ParamsWithPagination } from './types'; -import { inspect } from 'util' // or directly + declare global { interface Window { insights: { @@ -46,14 +46,17 @@ export const postWithFileReturn = ( method: 'POST', body: JSON.stringify(params), }) + .then((response) => { + return response.status === 404 ? response.json() : response; + }) .then((data) => { - if (data.status === 404) { + if (data.detail?.status === 404) { return Promise.reject({ - status: data.status, - error: 'PDF layout is not implemented for this report yet' + status: data.detail?.status, + error: data.detail?.name, }); } - return data.body + return data.body; }) .then((stream) => new Response(stream)) .then((response) => response.blob()) diff --git a/src/Components/ErrorDetail/ErrorDetail.js b/src/Components/ErrorDetail/ErrorDetail.js index 2e82b41db..0a44c831e 100644 --- a/src/Components/ErrorDetail/ErrorDetail.js +++ b/src/Components/ErrorDetail/ErrorDetail.js @@ -35,7 +35,7 @@ function ErrorDetail({ error }) { const handleToggle = () => { setIsExpanded(!isExpanded); }; - console.log('errrrrrr', error) + return ( <> {Array.isArray(error) && error.length && ( @@ -55,15 +55,6 @@ function ErrorDetail({ error }) { )} - {typeof error === 'string' && ( - - -
    -
  • {error}
  • -
-
-
- )} ); } diff --git a/src/Components/Toolbar/DownloadPdfButton.js b/src/Components/Toolbar/DownloadPdfButton.js index 7acbbc1e3..abcb0d4a9 100644 --- a/src/Components/Toolbar/DownloadPdfButton.js +++ b/src/Components/Toolbar/DownloadPdfButton.js @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { Button, @@ -10,70 +10,59 @@ import { import { DownloadIcon, ExclamationCircleIcon } from '@patternfly/react-icons'; import useRequest from '../../Utilities/useRequest'; -import { useCallback } from 'react'; import { generatePdf } from '../../Api'; -import AlertModal from "../AlertModal"; -import ErrorDetail from "../ErrorDetail"; +import AlertModal from '../AlertModal'; +import ErrorDetail from '../ErrorDetail'; const DownloadPdfButton = ({ slug, data, y, label, xTickFormat }) => { const [isModalOpen, setIsModalOpen] = useState(false); - const [isOpen, setIsOpen] = useState(true); const { error, isLoading, request } = useRequest( - useCallback((data) => + (data) => generatePdf({ slug, data, y, label, x_tick_format: xTickFormat, - }) - ), + }), null ); const getPdfButtonText = (error) => { - if (typeof error === 'string') - return error; - - if (typeof error === 'object') - return error?.error; - - return 'Download PDF version of report'; - } - - const toggleModal = async (isOpen) => { - setIsModalOpen(isOpen); - setIsOpen(false); + return error ? error.error : 'Download PDF version of report'; }; + useEffect(() => { + if (error) { + setIsModalOpen(true); + } + }, [error]); + return ( - {getPdfButtonText(error)}} - > - + + { + setIsModalOpen(false); + }} > - {isLoading && } - {!isLoading && error?.status === 404 && isOpen && - { - toggleModal(false); - }} - > - - - } - {!isLoading && error && } - {!isLoading && !error && } - - + + + ); }; From 334c0b3d279482615853ffcc3820a47f90873e1a Mon Sep 17 00:00:00 2001 From: Levente Berky Date: Thu, 14 Oct 2021 13:16:00 +0200 Subject: [PATCH 23/71] Updated the API methods to accept any error message --- src/Api/methods.ts | 22 ++++++++++----------- src/Components/Toolbar/DownloadPdfButton.js | 13 ++++++------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/Api/methods.ts b/src/Api/methods.ts index 344e7a786..4bd0adc3b 100644 --- a/src/Api/methods.ts +++ b/src/Api/methods.ts @@ -46,18 +46,16 @@ export const postWithFileReturn = ( method: 'POST', body: JSON.stringify(params), }) - .then((response) => { - return response.status === 404 ? response.json() : response; - }) - .then((data) => { - if (data.detail?.status === 404) { - return Promise.reject({ - status: data.detail?.status, - error: data.detail?.name, - }); - } - return data.body; - }) + .then((response) => + response.ok + ? response // If reposnse is ok, then continue to download the PDF + : response // Else it is an error and we have to parse it as a json + .json() + .then((error: ApiJson) => + Promise.reject({ status: response.status, error }) + ) + ) + .then((data) => data.body) .then((stream) => new Response(stream)) .then((response) => response.blob()) .then((blob) => { diff --git a/src/Components/Toolbar/DownloadPdfButton.js b/src/Components/Toolbar/DownloadPdfButton.js index abcb0d4a9..b4db017b9 100644 --- a/src/Components/Toolbar/DownloadPdfButton.js +++ b/src/Components/Toolbar/DownloadPdfButton.js @@ -29,9 +29,10 @@ const DownloadPdfButton = ({ slug, data, y, label, xTickFormat }) => { null ); - const getPdfButtonText = (error) => { - return error ? error.error : 'Download PDF version of report'; - }; + const getErrorMessage = error?.error?.detail?.name; + + const getPdfButtonText = + getErrorMessage?.at(0) ?? 'Download PDF version of report'; useEffect(() => { if (error) { @@ -41,10 +42,10 @@ const DownloadPdfButton = ({ slug, data, y, label, xTickFormat }) => { return ( <> - +
} {headers.map(({ key, value }) => ( - + {value}
} {headers.map(({ key, value }) => ( - + {value}