Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-4.14] Bug 2239093: Fix tooltips messages in the graphs at DR Policy dashboard #1070

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,10 @@
"Loading Empty Page": "Loading Empty Page",
"You are not authorized to complete this action. See your cluster administrator for role-based access control information.": "You are not authorized to complete this action. See your cluster administrator for role-based access control information.",
"Not Authorized": "Not Authorized",
"Alerts are displayed for both <1>ApplicationSet</1> and <4>Subscription</4> type applications.": "Alerts are displayed for both <1>ApplicationSet</1> and <4>Subscription</4> type applications.",
"{{ currentStatus }} to {{ preferredCluster }}": "{{ currentStatus }} to {{ preferredCluster }}",
"{{ currentStatus }} to {{ failoverCluster }}": "{{ currentStatus }} to {{ failoverCluster }}",
"Unknown": "Unknown",
"Protected PVCs": "Protected PVCs",
"{{ pvcsWithIssueCount }} with issues": "{{ pvcsWithIssueCount }} with issues",
"Snapshot": "Snapshot",
"Last replicated on: {{ lastSyncTime }}": "Last replicated on: {{ lastSyncTime }}",
"Operator health": "Operator health",
Expand All @@ -80,30 +79,31 @@
"Operators health": "Operators health",
"Peer connection": "Peer connection",
" {{ peerConnectedCount }} Connected": " {{ peerConnectedCount }} Connected",
"Total applications": "Total applications",
"Total applications (ApplicationSet)": "Total applications (ApplicationSet)",
" {{ protectedAppSetsCount }} protected apps": " {{ protectedAppSetsCount }} protected apps",
" {{ appsWithIssues }} of {{ protectedAppSetsCount }} apps with issues": " {{ appsWithIssues }} of {{ protectedAppSetsCount }} apps with issues",
"PVCs": "PVCs",
" {{ protectedPVCsCount }} protected": " {{ protectedPVCsCount }} protected",
"Current value: ": "Current value: ",
"Max value: ": "Max value: ",
"Min value: ": "Min value: ",
"Utilization": "Utilization",
"Snapshots synced": "Snapshots synced",
"The y-axis shows the number of snapshots taken. It represents the rate of difference in snapshot creation count during a failover.": "The y-axis shows the number of snapshots taken. It represents the rate of difference in snapshot creation count during a failover.",
"Replication throughput": "Replication throughput",
"The y-axis shows the average throughput for syncing snapshot bytes from the primary to the secondary cluster.": "The y-axis shows the average throughput for syncing snapshot bytes from the primary to the secondary cluster.",
"Volume replication health": "Volume replication health",
"Block volumes snapshots synced": "Block volumes snapshots synced",
"The graph displays the total number of block volumes inbound snapshots, by cluster, from all ApplicationSet and Subscription type applications. Applications that use file volumes are excluded in the total snapshot count.": "The graph displays the total number of block volumes inbound snapshots, by cluster, from all ApplicationSet and Subscription type applications. Applications that use file volumes are excluded in the total snapshot count.",
"Block volumes replication throughput": "Block volumes replication throughput",
"The graph displays the average replication throughput inbound, by cluster, from all ApplicationSet and Subscription type applications. Applications that use file volumes are excluded in the replication throughput.": "The graph displays the average replication throughput inbound, by cluster, from all ApplicationSet and Subscription type applications. Applications that use file volumes are excluded in the replication throughput.",
"Volume replication health (ApplicationSet)": "Volume replication health (ApplicationSet)",
"Volumes": "Volumes",
"Cluster: {{clusterName}}": "Cluster: {{clusterName}}",
"Select a cluster": "Select a cluster",
"Application:": "Application:",
"Namespace: ": "Namespace: ",
"Protected PVCs (ApplicationSet)": "Protected PVCs (ApplicationSet)",
"{{ pvcsWithIssueCount }} with issues": "{{ pvcsWithIssueCount }} with issues",
"Operator status": "Operator status",
"Cluster operator": "Cluster operator",
"{{ healthy }} healthy": "{{ healthy }} healthy",
"{{ issues }} with issues": "{{ issues }} with issues",
"{{ protected }} DR protected": "{{ protected }} DR protected",
"The applications count displays the total number of <2>ApplicationSet</2> type applications in all disaster recovery configured clusters.": "The applications count displays the total number of <2>ApplicationSet</2> type applications in all disaster recovery configured clusters.",
"{{ protected }} protected": "{{ protected }} protected",
"Systems": "Systems",
"Storage System status": "Storage System status",
"StorageSystem is responsible for ensuring different types of file and block storage availability, storage capacity management and generic operations on storage.": "StorageSystem is responsible for ensuring different types of file and block storage availability, storage capacity management and generic operations on storage.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import * as React from 'react';
import { filterDRAlerts } from '@odf/mco/utils';
import AlertsPanel from '@odf/shared/alert/AlertsPanel';
import useAlerts from '@odf/shared/monitoring/useAlert';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { Trans } from 'react-i18next';
import { Card, CardBody } from '@patternfly/react-core';
import AlertItem from './alert-item';
import './alert-card.scss';

export const AlertsCard: React.FC = () => {
const [alerts, loaded, loadError] = useAlerts();
const { t } = useCustomTranslation();

return (
<Card data-test="alerts-card">
Expand All @@ -16,6 +19,12 @@ export const AlertsCard: React.FC = () => {
alerts={alerts}
AlertItemComponent={AlertItem}
alertsFilter={filterDRAlerts}
titleToolTip={
<Trans t={t}>
Alerts are displayed for both <b>ApplicationSet</b> and{' '}
<b>Subscription</b> type applications.
</Trans>
}
loaded={loaded}
loadError={loadError}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,19 @@
*/

import * as React from 'react';
import { VOLUME_REPLICATION_HEALTH, DRPC_STATUS } from '@odf/mco/constants';
import {
PlacementInfo,
ProtectedAppSetsMap,
ProtectedPVCData,
} from '@odf/mco/types';
import { getVolumeReplicationHealth, getDRStatus } from '@odf/mco/utils';
import { DRPC_STATUS } from '@odf/mco/constants';
import { PlacementInfo, ProtectedAppSetsMap } from '@odf/mco/types';
import { getDRStatus } from '@odf/mco/utils';
import { utcDateTimeFormatter } from '@odf/shared/details-page/datetime';
import {
fromNow,
getTimeDifferenceInSeconds,
} 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 { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import {
PrometheusResponse,
StatusIconAndText,
} from '@openshift-console/dynamic-plugin-sdk';
import { TFunction } from 'i18next';
import { TextVariants, Text } from '@patternfly/react-core';
import { Text } from '@patternfly/react-core';
import { StatusText } from './common';

const getCurrentActivity = (
Expand Down Expand Up @@ -54,54 +47,6 @@ const getCurrentActivity = (
}
};

export const ProtectedPVCsSection: React.FC<ProtectedPVCsSectionProps> = ({
protectedPVCData,
selectedAppSet,
}) => {
const { t } = useCustomTranslation();
const clearSetIntervalId = React.useRef<NodeJS.Timeout>();
const [protectedPVC, setProtectedPVC] = React.useState([0, 0]);
const [protectedPVCsCount, pvcsWithIssueCount] = protectedPVC;

const updateProtectedPVC = React.useCallback(() => {
const placementInfo = selectedAppSet?.placementInfo?.[0];
const issueCount =
protectedPVCData?.reduce((acc, protectedPVCItem) => {
if (
protectedPVCItem?.drpcName === placementInfo?.drpcName &&
protectedPVCItem?.drpcNamespace === placementInfo?.drpcNamespace &&
getVolumeReplicationHealth(
getTimeDifferenceInSeconds(protectedPVCItem?.lastSyncTime),
protectedPVCItem?.schedulingInterval
)[0] !== VOLUME_REPLICATION_HEALTH.HEALTHY
)
return acc + 1;
else return acc;
}, 0) || 0;

setProtectedPVC([protectedPVCData?.length || 0, issueCount]);
}, [selectedAppSet, protectedPVCData, setProtectedPVC]);

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

return (
<div className="mco-dashboard__contentColumn">
<Text component={TextVariants.h1}>{protectedPVCsCount}</Text>
<StatusText>{t('Protected PVCs')}</StatusText>
<Text className="text-muted">
{t('{{ pvcsWithIssueCount }} with issues', { pvcsWithIssueCount })}
</Text>
</div>
);
};

export const ActivitySection: React.FC<CommonProps> = ({ selectedAppSet }) => {
const { t } = useCustomTranslation();

Expand Down Expand Up @@ -162,11 +107,6 @@ export const SnapshotSection: React.FC<CommonProps> = ({ selectedAppSet }) => {
);
};

type ProtectedPVCsSectionProps = {
protectedPVCData: ProtectedPVCData[];
selectedAppSet: ProtectedAppSetsMap;
};

type CommonProps = {
selectedAppSet: ProtectedAppSetsMap;
lastSyncTimeData?: PrometheusResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,18 @@ import {
CSVStatusesContext,
DRResourcesContext,
} from '../dr-dashboard-context';
import {
ProtectedPVCsSection,
ActivitySection,
SnapshotSection,
} from './argo-application-set';
import { ActivitySection, SnapshotSection } from './argo-application-set';
import {
HealthSection,
PeerConnectionSection,
ApplicationsSection,
PVCsSection,
UtilizationCard,
} from './cluster';
import { ClusterAppDropdown, VolumeSummarySection } from './common';
import {
ClusterAppDropdown,
ProtectedPVCsSection,
VolumeSummarySection,
} from './common';
import './cluster-app-card.scss';

export const ClusterWiseCard: React.FC<ClusterWiseCardProps> = ({
Expand Down Expand Up @@ -97,10 +96,7 @@ export const ClusterWiseCard: React.FC<ClusterWiseCardProps> = ({
/>
</GridItem>
<GridItem lg={9} rowSpan={10} sm={12}>
<PVCsSection
protectedPVCData={protectedPVCData}
clusterName={clusterName}
/>
<ProtectedPVCsSection protectedPVCData={protectedPVCData} />
</GridItem>
<GridItem lg={12} rowSpan={8} sm={12}>
<VolumeSummarySection protectedPVCData={protectedPVCData} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,17 @@ import * as React from 'react';
import {
DRDashboard,
getRBDSnapshotUtilizationQuery,
getTotalPVCCountPerClusterQuery,
} from '@odf/mco/components/mco-dashboard/queries';
import {
ODR_CLUSTER_OPERATOR,
VOL_SYNC,
HUB_CLUSTER_NAME,
ACM_ENDPOINT,
VOLUME_REPLICATION_HEALTH,
OBJECT_NAMESPACE,
OBJECT_NAME,
MANAGED_CLUSTER_CONDITION_AVAILABLE,
} from '@odf/mco/constants';
import {
DrClusterAppsMap,
PlacementInfo,
ProtectedPVCData,
} from '@odf/mco/types';
import { DrClusterAppsMap, PlacementInfo } from '@odf/mco/types';
import {
getVolumeReplicationHealth,
getManagedClusterCondition,
Expand All @@ -33,7 +27,6 @@ import { healthStateMapping } from '@odf/shared/dashboards/status-card/states';
import { PrometheusUtilizationItem } from '@odf/shared/dashboards/utilization-card/prometheus-utilization-item';
import { CustomUtilizationSummaryProps } from '@odf/shared/dashboards/utilization-card/utilization-item';
import { FieldLevelHelp } from '@odf/shared/generic';
import { useCustomPrometheusPoll } from '@odf/shared/hooks/custom-prometheus-poll';
import Status, { StatusPopupSection } from '@odf/shared/popup/status-popup';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { humanizeDecimalBytesPerSec, humanizeNumber } from '@odf/shared/utils';
Expand Down Expand Up @@ -212,7 +205,7 @@ export const ApplicationsSection: React.FC<ApplicationsSectionProps> = ({
return (
<div className="mco-dashboard__contentColumn">
<Text component={TextVariants.h1}>{totalAppSetsCount || 0}</Text>
<StatusText>{t('Total applications')}</StatusText>
<StatusText>{t('Total applications (ApplicationSet)')}</StatusText>
<Text className="text-muted mco-dashboard__statusText--margin">
{t(' {{ protectedAppSetsCount }} protected apps', {
protectedAppSetsCount,
Expand All @@ -228,33 +221,6 @@ export const ApplicationsSection: React.FC<ApplicationsSectionProps> = ({
);
};

export const PVCsSection: React.FC<PVCsSectionProps> = ({
protectedPVCData,
clusterName,
}) => {
const { t } = useCustomTranslation();
const [pvcsCount] = useCustomPrometheusPoll({
endpoint: 'api/v1/query' as any,
query: !!clusterName ? getTotalPVCCountPerClusterQuery(clusterName) : null,
basePath: ACM_ENDPOINT,
cluster: HUB_CLUSTER_NAME,
});
let totalPVCsCount = pvcsCount?.data?.result?.[0]?.value?.[1] || '0';
let protectedPVCsCount = protectedPVCData?.length || 0;

return (
<div className="mco-dashboard__contentColumn">
<Text component={TextVariants.h1}>{totalPVCsCount}</Text>
<StatusText>{t('PVCs')}</StatusText>
<Text className="text-muted">
{t(' {{ protectedPVCsCount }} protected', {
protectedPVCsCount,
})}
</Text>
</div>
);
};

const getDescription = (result: PrometheusResult, _index: number) =>
// Returning cluster name as a description
result.metric?.['cluster'] || '';
Expand Down Expand Up @@ -354,22 +320,22 @@ export const UtilizationCard: React.FC<UtilizationCardProps> = ({
<div className="mco-cluster-app__graph--margin-bottom">
<SnapshotUtilizationCard
clusters={peerClusters}
title={t('Snapshots synced')}
title={t('Block volumes snapshots synced')}
queryType={DRDashboard.RBD_SNAPSHOT_SNAPSHOTS}
titleToolTip={t(
'The y-axis shows the number of snapshots taken. It represents the rate of difference in snapshot creation count during a failover.'
'The graph displays the total number of block volumes inbound snapshots, by cluster, from all ApplicationSet and Subscription type applications. Applications that use file volumes are excluded in the total snapshot count.'
)}
humanizeValue={humanizeNumber}
/>
</div>
<div className="mco-cluster-app__graph--margin-bottom">
<SnapshotUtilizationCard
clusters={[clusterName]}
title={t('Replication throughput')}
title={t('Block volumes replication throughput')}
queryType={DRDashboard.RBD_SNAPSHOTS_SYNC_BYTES}
humanizeValue={humanizeDecimalBytesPerSec}
titleToolTip={t(
'The y-axis shows the average throughput for syncing snapshot bytes from the primary to the secondary cluster.'
'The graph displays the average replication throughput inbound, by cluster, from all ApplicationSet and Subscription type applications. Applications that use file volumes are excluded in the replication throughput.'
)}
CustomUtilizationSummary={CustomUtilizationSummary}
/>
Expand Down Expand Up @@ -403,18 +369,13 @@ type ApplicationsSectionProps = {
lastSyncTimeData: PrometheusResponse;
};

type PVCsSectionProps = {
protectedPVCData: ProtectedPVCData[];
clusterName: string;
};

type SnapshotUtilizationCardProps = {
title: string;
queryType: DRDashboard;
humanizeValue: Humanize;
chartLabel?: string;
clusters?: string[];
titleToolTip: string;
titleToolTip: JSX.Element;
CustomUtilizationSummary?: React.FC<CustomUtilizationSummaryProps>;
};

Expand Down
Loading
Loading