Skip to content

Commit

Permalink
Merge pull request #1128 from GowthamShanmugam/RHSTOR-4991
Browse files Browse the repository at this point in the history
Application view for subscription application monitoring
  • Loading branch information
openshift-merge-bot[bot] authored Dec 19, 2023
2 parents f7e9a93 + a85da72 commit 49b10b1
Show file tree
Hide file tree
Showing 14 changed files with 479 additions and 141 deletions.
6 changes: 5 additions & 1 deletion locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
"Unknown": "Unknown",
"Snapshot": "Snapshot",
"Last replicated on: {{ lastSyncTime }}": "Last replicated on: {{ lastSyncTime }}",
"Subscription": "Subscription",
"Snapshot last replicated on": "Snapshot last replicated on",
"Subscription details": "Subscription details",
"Application: ": "Application: ",
"Type: {{type}}": "Type: {{type}}",
"Operator health": "Operator health",
"Operators are responsible for maintaining and reconciling the state of the cluster.": "Operators are responsible for maintaining and reconciling the state of the cluster.",
"Degraded": "Degraded",
Expand Down Expand Up @@ -1175,7 +1180,6 @@
"Deployment": "Deployment",
"Infrastructure": "Infrastructure",
"Infrastructures": "Infrastructures",
"Subscription": "Subscription",
"Subscriptions": "Subscriptions",
"Project": "Project",
"Show password": "Show password",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,49 @@ import { PlacementInfo, ProtectedAppsMap } from '@odf/mco/types';
import { getDRStatus } from '@odf/mco/utils';
import { utcDateTimeFormatter } from '@odf/shared/details-page/datetime';
import { fromNow } from '@odf/shared/details-page/datetime';
import { URL_POLL_DEFAULT_DELAY } from '@odf/shared/hooks/custom-prometheus-poll/use-url-poll';
import { useScheduler } from '@odf/shared/hooks';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { getPageRange } from '@odf/shared/utils';
import {
PrometheusResponse,
RowProps,
StatusIconAndText,
TableColumn,
TableData,
VirtualizedTable,
useActiveColumns,
} from '@openshift-console/dynamic-plugin-sdk';
import { TFunction } from 'i18next';
import { Text } from '@patternfly/react-core';
import {
Pagination,
PaginationVariant,
Text,
TextVariants,
} from '@patternfly/react-core';
import { sortable } from '@patternfly/react-table';
import { StatusText } from './common';

const getCurrentActivity = (
const INITIAL_PAGE_NUMBER = 1;
const COUNT_PER_PAGE_NUMBER = 5;

const subscriptionTableColumnProps = [
{
id: 'name',
},
{
id: 'activity',
},
{
id: 'lastSnapshotSyncTime',
},
];

const formatSyncTimeWithRPO = (lastSnapshotSyncTime: string, rpo: string) => {
const dateTime = utcDateTimeFormatter.format(new Date(lastSnapshotSyncTime));
return `${dateTime} (${rpo})`;
};

export const getCurrentActivity = (
currentStatus: string,
failoverCluster: string,
preferredCluster: string,
Expand Down Expand Up @@ -47,6 +79,34 @@ const getCurrentActivity = (
}
};

const getSubscriptionRow = (
placementInfoList: PlacementInfo[] = []
): SubscriptionRowProps[] => {
const _getRowProps = (
subscriptions: string[],
{
status,
lastGroupSyncTime,
failoverCluster,
preferredCluster,
}: PlacementInfo
): SubscriptionRowProps[] =>
subscriptions?.map((subscriptionName) => ({
name: subscriptionName,
activity: status,
lastSnapshotSyncTime: lastGroupSyncTime,
failoverCluster: failoverCluster,
preferredCluster: preferredCluster,
}));
return placementInfoList.reduce(
(acc, placementInfo) => [
...acc,
..._getRowProps(placementInfo?.subscriptions, placementInfo),
],
[]
);
};

export const ActivitySection: React.FC<CommonProps> = ({
selectedApplication,
}) => {
Expand Down Expand Up @@ -80,24 +140,17 @@ export const SnapshotSection: React.FC<CommonProps> = ({
const [lastSyncTime, setLastSyncTime] = React.useState('N/A');
const lastGroupSyncTime =
selectedApplication?.placementInfo?.[0]?.lastGroupSyncTime;
const clearSetIntervalId = React.useRef<NodeJS.Timeout>();
const updateSyncTime = React.useCallback(() => {
if (!!lastGroupSyncTime) {
const dateTime = utcDateTimeFormatter.format(new Date(lastGroupSyncTime));
setLastSyncTime(`${dateTime} (${fromNow(lastGroupSyncTime)})`);
setLastSyncTime(
formatSyncTimeWithRPO(lastGroupSyncTime, fromNow(lastGroupSyncTime))
);
} else {
setLastSyncTime('N/A');
}
}, [lastGroupSyncTime]);

React.useEffect(() => {
updateSyncTime();
clearSetIntervalId.current = setInterval(
updateSyncTime,
URL_POLL_DEFAULT_DELAY
);
return () => clearInterval(clearSetIntervalId.current);
}, [updateSyncTime]);
useScheduler(updateSyncTime);

return (
<div className="mco-dashboard__contentColumn">
Expand All @@ -111,7 +164,177 @@ export const SnapshotSection: React.FC<CommonProps> = ({
);
};

const SubscriptionRow: React.FC<
RowProps<SubscriptionRowProps, SubscriptionWiseRPOMap>
> = ({
obj: {
name,
activity,
lastSnapshotSyncTime,
failoverCluster,
preferredCluster,
},
rowData: subsWiseRPO,
activeColumnIDs,
}) => {
const { t } = useCustomTranslation();
const lastSyncTimeWithRPO = !!lastSnapshotSyncTime
? formatSyncTimeWithRPO(lastSnapshotSyncTime, subsWiseRPO[name])
: 'N/A';

return (
<>
<TableData
{...subscriptionTableColumnProps[0]}
activeColumnIDs={activeColumnIDs}
>
{name}
</TableData>
<TableData
{...subscriptionTableColumnProps[1]}
activeColumnIDs={activeColumnIDs}
>
{getCurrentActivity(activity, failoverCluster, preferredCluster, t)}
</TableData>
<TableData
{...subscriptionTableColumnProps[2]}
activeColumnIDs={activeColumnIDs}
>
{lastSyncTimeWithRPO}
</TableData>
</>
);
};

export const SubscriptionSection: React.FC<SubscriptionSectionProps> = ({
selectedApplication,
}) => {
const { t } = useCustomTranslation();
const subsCount = selectedApplication?.placementInfo?.reduce(
(acc, placement) => acc + placement.subscriptions?.length || 0,
0
);
return (
<div className="mco-dashboard__contentColumn">
<Text component={TextVariants.h1}>{subsCount}</Text>
<StatusText>{t('Subscription')}</StatusText>
</div>
);
};

export const SubscriptionDetailsTable: React.FC<SubscriptionDetailsTableProps> =
({ selectedApplication }) => {
const { placementInfo } = selectedApplication;
const { t } = useCustomTranslation();
const [subsWiseRPO, setSubsWiseRPO] =
React.useState<SubscriptionWiseRPOMap>({});
const [page, setPage] = React.useState(INITIAL_PAGE_NUMBER);
const [perPage, setPerPage] = React.useState(COUNT_PER_PAGE_NUMBER);
const subscriptionsTableColumns = React.useMemo<
TableColumn<SubscriptionRowProps>[]
>(
() => [
{
title: t('Name'),
sort: 'name',
transforms: [sortable],
id: subscriptionTableColumnProps[0].id,
},
{
title: t('Activity'),
sort: 'activity',
transforms: [sortable],
id: subscriptionTableColumnProps[1].id,
},
{
title: t('Snapshot last replicated on'),
sort: 'lastSnapshotSyncTime',
transforms: [sortable],
id: subscriptionTableColumnProps[2].id,
},
],
[t]
);
const [columns] = useActiveColumns({
columns: subscriptionsTableColumns,
showNamespaceOverride: false,
columnManagementID: null,
});
const [subscriptionRows, numberOfRows]: [SubscriptionRowProps[], number] =
React.useMemo(() => {
const [start, end] = getPageRange(page, perPage);
const subscriptionRowList = getSubscriptionRow(placementInfo);
return [
subscriptionRowList.slice(start, end),
subscriptionRowList.length,
];
}, [placementInfo, page, perPage]);
const updatedRPO = React.useCallback(() => {
const rpoMap = subscriptionRows.reduce((acc, row) => {
const { name, lastSnapshotSyncTime } = row;
acc[name] = !!lastSnapshotSyncTime ? fromNow(lastSnapshotSyncTime) : '';
return acc;
}, {});
setSubsWiseRPO(rpoMap);
}, [subscriptionRows, setSubsWiseRPO]);

useScheduler(updatedRPO);

return (
<div className="mco-dashboard__contentColumn">
<Text component={TextVariants.h3}>{t('Subscription details')}</Text>
<div className="mco-cluster-app__subs-table--width">
<VirtualizedTable
data={subscriptionRows}
unfilteredData={subscriptionRows}
aria-label={t('Subscription details')}
columns={columns}
Row={SubscriptionRow}
rowData={subsWiseRPO}
loaded={true}
loadError=""
/>
<Pagination
perPageComponent="button"
itemCount={numberOfRows}
widgetId="subscription-table"
perPage={perPage}
page={page}
variant={PaginationVariant.bottom}
perPageOptions={[]}
isStatic
onSetPage={(_event, newPage) => setPage(newPage)}
onPerPageSelect={(_event, newPerPage, newPage) => {
setPerPage(newPerPage);
setPage(newPage);
}}
/>
</div>
</div>
);
};

type CommonProps = {
selectedApplication: ProtectedAppsMap;
lastSyncTimeData?: PrometheusResponse;
};

type SubscriptionSectionProps = {
selectedApplication: ProtectedAppsMap;
};

type SubscriptionDetailsTableProps = {
selectedApplication: ProtectedAppsMap;
};

type SubscriptionRowProps = {
name: string;
activity: string;
lastSnapshotSyncTime: string;
failoverCluster: string;
preferredCluster: string;
};

type SubscriptionWiseRPOMap = {
[subscriptionName: string]: string;
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
&__dropdown--padding {
padding-right: var(--pf-global--spacer--xs);
}
&__dropdownHeight {
max-height: 30rem;
overflow-y: auto;
}
&__text--padding-left {
padding-left: var(--pf-global--spacer--sm);
}
Expand Down Expand Up @@ -57,3 +61,8 @@
.co-utilization-card__item-summary .bold {
font-weight: bold;
}

.mco-cluster-app__subs-table--width {
min-width: 10rem;
max-width: 55rem;
}
Loading

0 comments on commit 49b10b1

Please sign in to comment.