diff --git a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json index ea66a561f..01f75602d 100644 --- a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json +++ b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json @@ -408,6 +408,9 @@ "View details": "View details", "View provider details": "View provider details", "Virtual Machine Migrations": "Virtual Machine Migrations", + "Virtual Machine Migrations (last 24 hours)": "Virtual Machine Migrations (last 24 hours)", + "Virtual Machine Migrations (last 31 days)": "Virtual Machine Migrations (last 31 days)", + "Virtual Machine Migrations (last 7 days)": "Virtual Machine Migrations (last 7 days)", "Virtual machines": "Virtual machines", "Virtual Machines": "Virtual Machines", "VMs": "VMs", diff --git a/packages/forklift-console-plugin/src/modules/Overview/views/overview/tabs/Metrics/cards/ChartsCard.tsx b/packages/forklift-console-plugin/src/modules/Overview/views/overview/tabs/Metrics/cards/ChartsCard.tsx index 94733b2d3..05639f3da 100644 --- a/packages/forklift-console-plugin/src/modules/Overview/views/overview/tabs/Metrics/cards/ChartsCard.tsx +++ b/packages/forklift-console-plugin/src/modules/Overview/views/overview/tabs/Metrics/cards/ChartsCard.tsx @@ -3,6 +3,7 @@ import { DateTime, Interval } from 'luxon'; import { useForkliftTranslation } from 'src/utils/i18n'; import { MigrationModelGroupVersionKind, V1beta1Migration } from '@kubev2v/types'; +import { V1beta1MigrationStatusVms } from '@kubev2v/types/dist/models/V1beta1MigrationStatusVms'; import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; import { Chart, ChartAxis, ChartBar, ChartGroup, ChartTooltip } from '@patternfly/react-charts'; import { @@ -33,8 +34,10 @@ enum TimeRangeOptions { Last24H = 'Last24H', } -const toStarted = (m: V1beta1Migration): string => m.status.started; -const toFinished = (m: V1beta1Migration): string => m.status.completed; +const toStartedMigration = (m: V1beta1Migration): string => m.status.started; +const toStartedVmMigration = (v: V1beta1MigrationStatusVms): string => v.started; +const toFinishedMigration = (m: V1beta1Migration): string => m.status.completed; +const toFinishedVmMigration = (v: V1beta1MigrationStatusVms): string => v.completed; const hasTimestamp = (timestamp: string) => timestamp && DateTime.fromISO(timestamp).isValid; const toDateTime = (timestamp: string): DateTime => DateTime.fromISO(timestamp); const isLast7Days = (date: DateTime) => date.diffNow('days').get('days') <= 7; @@ -46,7 +49,9 @@ const toHourLabel = (date: DateTime): string => date.toFormat('HH:mm'); const TimeRangeOptionsDictionary = { Last7Days: { // t('Migrations (last 7 days)') - labelKey: 'Migrations (last 7 days)', + migrationsLabelKey: 'Migrations (last 7 days)', + // t('Virtual Machine Migrations (last 7 days)') + vmMigrationsLabelKey: 'Virtual Machine Migrations (last 7 days)', span: { days: 7 }, bucket: { day: 1 }, unit: 'day', @@ -54,7 +59,9 @@ const TimeRangeOptionsDictionary = { }, Last31Days: { // t('Migrations (last 31 days)') - labelKey: 'Migrations (last 31 days)', + migrationsLabelKey: 'Migrations (last 31 days)', + // t('Virtual Machine Migrations (last 31 days)') + vmMigrationsLabelKey: 'Virtual Machine Migrations (last 31 days)', span: { days: 31 }, bucket: { day: 4 }, unit: 'day', @@ -62,7 +69,9 @@ const TimeRangeOptionsDictionary = { }, Last24H: { // t('Migrations (last 24 hours)') - labelKey: 'Migrations (last 24 hours)', + migrationsLabelKey: 'Migrations (last 24 hours)', + // t('Virtual Machine Migrations (last 24 hours)') + vmMigrationsLabelKey: 'Virtual Machine Migrations (last 24 hours)', span: { hours: 24 }, bucket: { hour: 4 }, unit: 'hour', @@ -90,12 +99,10 @@ const groupByBucket = (acc: [Interval, DateTime[]][], date: DateTime) => ); const toDataPoints = ( - allMigrations: V1beta1Migration[], - toTimestamp: (m: V1beta1Migration) => string, + filteredMigrations: string[], selectedTimeRange: TimeRangeOptions, ): MigrationDataPoint[] => - allMigrations - .map(toTimestamp) + filteredMigrations .filter(hasTimestamp) .map(toDateTime) .filter(TimeRangeOptionsDictionary[selectedTimeRange].filter) @@ -110,13 +117,29 @@ const toDataPoints = ( value: points.length, })); +const toDataPointsForMigrations = ( + allMigrations: V1beta1Migration[], + toTimestamp: (m: V1beta1Migration) => string, + selectedTimeRange: TimeRangeOptions, +): MigrationDataPoint[] => toDataPoints(allMigrations.map(toTimestamp), selectedTimeRange); + +const toDataPointsForVmMigrations = ( + allVmMigrations: V1beta1MigrationStatusVms[], + toTimestamp: (m: V1beta1MigrationStatusVms) => string, + selectedTimeRange: TimeRangeOptions, +): MigrationDataPoint[] => toDataPoints(allVmMigrations.map(toTimestamp), selectedTimeRange); + export const ChartsCard: React.FC = () => { const { t } = useForkliftTranslation(); - const [isDropdownOpened, setIsDropdownOpened] = useState(false); - const onToggle = () => setIsDropdownOpened(!isDropdownOpened); - const [selectedTimeRange, setSelectedTimeRange] = useState( + const [isMigrationsDropdownOpened, setIsMigrationsDropdownOpened] = useState(false); + const [isVmMigrationsDropdownOpened, setIsVmMigrationsDropdownOpened] = useState(false); + const onToggleMigrations = () => setIsMigrationsDropdownOpened(!isMigrationsDropdownOpened); + const onToggleVmMigrations = () => setIsVmMigrationsDropdownOpened(!isVmMigrationsDropdownOpened); + const [selectedTimeRangeMigrations, setSelectedTimeRangeMigrations] = useState( TimeRangeOptions.Last7Days, ); + const [selectedTimeRangeVmMigrations, setSelectedTimeRangeVmMigrations] = + useState(TimeRangeOptions.Last7Days); const [migrations] = useK8sWatchResource({ groupVersionKind: MigrationModelGroupVersionKind, namespaced: true, @@ -127,20 +150,60 @@ export const ChartsCard: React.FC = () => { failed: MigrationDataPoint[]; succeeded: MigrationDataPoint[]; } = { - running: toDataPoints( + running: toDataPointsForMigrations( migrations.filter((m) => m?.status?.conditions?.find((it) => it?.type === 'Running')), - toStarted, - selectedTimeRange, + toStartedMigration, + selectedTimeRangeMigrations, ), - failed: toDataPoints( + failed: toDataPointsForMigrations( migrations.filter((m) => m?.status?.conditions?.find((it) => it?.type === 'Failed')), - toFinished, - selectedTimeRange, + toFinishedMigration, + selectedTimeRangeMigrations, ), - succeeded: toDataPoints( + succeeded: toDataPointsForMigrations( migrations.filter((m) => m?.status?.conditions?.find((it) => it?.type === 'Succeeded')), - toFinished, - selectedTimeRange, + toFinishedMigration, + selectedTimeRangeMigrations, + ), + }; + + const VmMigrationsDataPoints: { + running: MigrationDataPoint[]; + failed: MigrationDataPoint[]; + succeeded: MigrationDataPoint[]; + } = { + running: toDataPointsForVmMigrations( + migrations + .map((migration) => + migration?.status?.vms.filter( + (vm) => vm?.phase !== 'Completed' && vm?.phase != 'Canceled', + ), + ) + .reduce((append, vm) => append.concat(vm), []), + toStartedVmMigration, + selectedTimeRangeVmMigrations, + ), + failed: toDataPointsForVmMigrations( + migrations + .map((migration) => + migration?.status?.vms.filter((vm) => + vm?.conditions?.find((it) => it?.type === 'Failed'), + ), + ) + .reduce((append, vm) => append.concat(vm), []), + toFinishedVmMigration, + selectedTimeRangeVmMigrations, + ), + succeeded: toDataPointsForVmMigrations( + migrations + .map((migration) => + migration?.status?.vms.filter((vm) => + vm?.conditions?.find((it) => it?.type === 'Succeeded'), + ), + ) + .reduce((append, vm) => append.concat(vm), []), + toFinishedVmMigration, + selectedTimeRangeVmMigrations, ), }; @@ -150,22 +213,28 @@ export const ChartsCard: React.FC = () => { ...migrationsDataPoints.succeeded.map((m) => m.value), ); + const maxVmMigrationValue = Math.max( + ...VmMigrationsDataPoints.running.map((m) => m.value), + ...VmMigrationsDataPoints.failed.map((m) => m.value), + ...VmMigrationsDataPoints.succeeded.map((m) => m.value), + ); + return ( - {t(TimeRangeOptionsDictionary[selectedTimeRange].labelKey)} + {t(TimeRangeOptionsDictionary[selectedTimeRangeMigrations].migrationsLabelKey)} } - isOpen={isDropdownOpened} + toggle={} + isOpen={isMigrationsDropdownOpened} isPlain dropdownItems={[ { - onToggle(); - setSelectedTimeRange(TimeRangeOptions.Last7Days); + onToggleMigrations(); + setSelectedTimeRangeMigrations(TimeRangeOptions.Last7Days); }} key="7days" > @@ -173,8 +242,8 @@ export const ChartsCard: React.FC = () => { , { - onToggle(); - setSelectedTimeRange(TimeRangeOptions.Last31Days); + onToggleMigrations(); + setSelectedTimeRangeMigrations(TimeRangeOptions.Last31Days); }} key="31days" > @@ -182,8 +251,8 @@ export const ChartsCard: React.FC = () => { , { - onToggle(); - setSelectedTimeRange(TimeRangeOptions.Last24H); + onToggleMigrations(); + setSelectedTimeRangeMigrations(TimeRangeOptions.Last24H); }} key="24hours" > @@ -253,6 +322,108 @@ export const ChartsCard: React.FC = () => { + + + + {t(TimeRangeOptionsDictionary[selectedTimeRangeVmMigrations].vmMigrationsLabelKey)} + + + } + isOpen={isVmMigrationsDropdownOpened} + isPlain + dropdownItems={[ + { + onToggleVmMigrations(); + setSelectedTimeRangeVmMigrations(TimeRangeOptions.Last7Days); + }} + key="7days" + > + {t('7 days')} + , + { + onToggleVmMigrations(); + setSelectedTimeRangeVmMigrations(TimeRangeOptions.Last31Days); + }} + key="31days" + > + {t('31 days')} + , + { + onToggleVmMigrations(); + setSelectedTimeRangeVmMigrations(TimeRangeOptions.Last24H); + }} + key="24hours" + > + {t('24 hours')} + , + ]} + /> + + + + + + + + + ({ + x: dateLabel, + y: value, + name: t('Running'), + label: t('{{dateLabel}} Running: {{value}}', { dateLabel, value }), + }))} + labelComponent={} + /> + ({ + x: dateLabel, + y: value, + name: t('Failed'), + label: t('{{dateLabel}} Failed: {{value}}', { dateLabel, value }), + }))} + labelComponent={} + /> + ({ + x: dateLabel, + y: value, + name: 'Succeeded', + label: t('{{dateLabel}} Succeeded: {{value}}', { dateLabel, value }), + }))} + labelComponent={} + /> + + + + ); };