Skip to content

Commit

Permalink
More commits
Browse files Browse the repository at this point in the history
Signed-off-by: Bipul Adhikari <[email protected]>
  • Loading branch information
bipuladh committed Dec 5, 2023
1 parent c646536 commit 1e020e0
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.odf-storageSystemPopup__item--margin {
.odf-status-card__popup--margin {
// Overriding PF default margin for FlexItem
margin-bottom: 0 !important;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import Status, { StatusPopupSection } from '@odf/shared/popup/status-popup';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { HealthState } from '@openshift-console/dynamic-plugin-sdk';
import { Link } from 'react-router-dom';
import { Flex, FlexItem } from '@patternfly/react-core';
Expand All @@ -9,17 +8,19 @@ import {
ExclamationCircleIcon,
ExclamationTriangleIcon,
} from '@patternfly/react-icons';
import './storage-system-popup.scss';
import './status-card-popover.scss';

type SystemHealthMap = {
systemName: string;
export type ResourceHealthMap = {
itemName: string;
healthState: HealthState;
link: string;
link?: string;
extraTexts?: string[];
};

type StorageSystemPopopProps = {
systemHealthMap: SystemHealthMap[];
type StatusCardPopoverProps = {
resourceHealthMap: ResourceHealthMap[];
firstColumnName: string;
secondColumnName: string;
};

const healthStateToIcon = {
Expand All @@ -34,27 +35,32 @@ const healthStateToIcon = {
),
};

const StorageSystemPopup: React.FC<StorageSystemPopopProps> = ({
systemHealthMap,
const StatusCardPopover: React.FC<StatusCardPopoverProps> = ({
resourceHealthMap,
firstColumnName,
secondColumnName,
}) => {
const { t } = useCustomTranslation();
return (
<StatusPopupSection
firstColumn={t('Storage System')}
secondColumn={t('Health')}
firstColumn={firstColumnName}
secondColumn={secondColumnName}
>
{systemHealthMap.map((system) => (
{resourceHealthMap.map((resource) => (
<Status
key={system.systemName}
icon={healthStateToIcon[system.healthState]}
key={resource.itemName}
icon={healthStateToIcon[resource.healthState]}
>
<Flex direction={{ default: 'column' }}>
<FlexItem className="odf-storageSystemPopup__item--margin">
<Link to={system.link}>{system.systemName}</Link>
<FlexItem className="odf-status-card__popup--margin">
{resource.link ? (
<Link to={resource.link}>{resource.itemName}</Link>
) : (
<>{resource.itemName}</>
)}
</FlexItem>
{!!system.extraTexts && (
{!!resource.extraTexts && (
<FlexItem>
{system.extraTexts.map((extraText, i) => (
{resource.extraTexts.map((extraText, i) => (
<div className="text-muted" key={i}>
{extraText}
</div>
Expand All @@ -68,4 +74,4 @@ const StorageSystemPopup: React.FC<StorageSystemPopopProps> = ({
);
};

export default StorageSystemPopup;
export default StatusCardPopover;
56 changes: 42 additions & 14 deletions packages/odf/components/odf-dashboard/status-card/status-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { StorageClientModel } from '@odf/client/src/models';
import { useSafeK8sWatchResource } from '@odf/core/hooks';
import { K8sResourceObj } from '@odf/core/types';
import { useGetOCSHealth } from '@odf/ocs/hooks';
import { StorageConsumerKind, getName } from '@odf/shared';
import { ODF_OPERATOR } from '@odf/shared/constants';
import HealthItem from '@odf/shared/dashboards/status-card/HealthItem';
import { healthStateMap } from '@odf/shared/dashboards/status-card/states';
Expand All @@ -24,6 +25,7 @@ import {
} from '@odf/shared/utils';
import {
HealthState,
useFlag,
useK8sWatchResource,
} from '@openshift-console/dynamic-plugin-sdk';
import { HealthBody } from '@openshift-console/dynamic-plugin-sdk-internal';
Expand All @@ -36,10 +38,16 @@ import {
CardHeader,
CardTitle,
} from '@patternfly/react-core';
import { PROVIDER_MODE } from '../../../features';
import { getVendorDashboardLinkFromMetrics } from '../../utils';
import { StorageDashboard, STATUS_QUERIES } from '../queries';
import StorageSystemPopup from './storage-system-popup';
import StatusCardPopover, { ResourceHealthMap } from './status-card-popover';
import './status-card.scss';
import {
getAggregateClientHealthState,
getClientHealthState,
getClientText,
} from './utils';

const operatorResource: K8sResourceObj = (ns) => ({
kind: 'operators.coreos.com~v1alpha1~ClusterServiceVersion',
Expand All @@ -53,8 +61,6 @@ const storageSystemResource: K8sResourceObj = (ns) => ({
isList: true,
});

const getStatusVector = (clients) => [];

export const StatusCard: React.FC = () => {
const { t } = useCustomTranslation();
const [csvData, csvLoaded, csvLoadError] =
Expand Down Expand Up @@ -135,14 +141,23 @@ export const StatusCard: React.FC = () => {
csvLoadError
);

const [clients, clientsLoaded, clientsLoadError] = useK8sWatchResource({
const isProviderMode = useFlag(PROVIDER_MODE);

const [clients, clientsLoaded, clientsLoadError] = useK8sWatchResource<
StorageConsumerKind[]
>({
kind: referenceForModel(StorageClientModel),
isList: true,
});

const clientStatus: { connected: number; total: number } = getStatusVector(
clients
) as any;
const clientAggregateHealth = getAggregateClientHealthState(clients);

const storageClientHealthMap: ResourceHealthMap[] = clients.map((client) => {
return {
itemName: getName(client),
healthState: getClientHealthState(client),
};
});

return (
<Card className="odfDashboard-card--height">
Expand All @@ -164,7 +179,11 @@ export const StatusCard: React.FC = () => {
title={pluralize(healthySystems.length, 'Storage System')}
state={HealthState.OK}
>
<StorageSystemPopup systemHealthMap={healthySystems} />
<StatusCardPopover
resourceHealthMap={healthySystems}
firstColumnName={t('Storage System')}
secondColumnName={t('Health')}
/>
</HealthItem>
</GalleryItem>
)}
Expand All @@ -175,17 +194,26 @@ export const StatusCard: React.FC = () => {
state={HealthState.ERROR}
maxWidth="35rem"
>
<StorageSystemPopup systemHealthMap={unHealthySystems} />
<StatusCardPopover
resourceHealthMap={unHealthySystems}
firstColumnName={t('Storage System')}
secondColumnName={t('Health')}
/>
</HealthItem>
</GalleryItem>
)}
{clientStatus && (
{isProviderMode && clientsLoaded && !clientsLoadError && (
<GalleryItem>
<HealthItem
title={`${
clientStatus.connected / clientStatus.total
} clients connected`}
></HealthItem>
title={getClientText(clients, t)}
state={clientAggregateHealth}
>
<StatusCardPopover
resourceHealthMap={storageClientHealthMap}
firstColumnName={t('Client Name')}
secondColumnName={t('Connection')}
/>
</HealthItem>
</GalleryItem>
)}
</Gallery>
Expand Down
60 changes: 60 additions & 0 deletions packages/odf/components/odf-dashboard/status-card/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { StorageConsumerKind, StorageConsumerState } from '@odf/shared';
import { HealthState } from '@openshift-console/dynamic-plugin-sdk';
import { TFunction } from 'i18next';

export const getClientHealthState = (
client: StorageConsumerKind
): HealthState => {
const state = client.status.state;
let health = HealthState.UNKNOWN;
switch (state) {
case StorageConsumerState.Ready:
health = HealthState.OK;
break;
case StorageConsumerState.Configuring:
case StorageConsumerState.Deleting:
health = HealthState.LOADING;
break;
case StorageConsumerState.Disabled:
case StorageConsumerState.Failed:
health = HealthState.ERROR;
break;
default:
health = HealthState.UNKNOWN;
}
return health;
};

export const getAggregateClientHealthState = (
clients: StorageConsumerKind[]
) => {
const totalConnectedClients = clients.filter(
(client) => client.status.state === StorageConsumerState.Ready
).length;
const total = clients.length;
if (total === totalConnectedClients) {
return HealthState.OK;
}
if (totalConnectedClients === 0 && total > 0) {
return HealthState.ERROR;
}
if (total === 0) {
return HealthState.NOT_AVAILABLE;
}
return HealthState.NOT_AVAILABLE;
};

export const getClientText = (clients: StorageConsumerKind[], t: TFunction) => {
const connectedClients = clients.filter(
(client) => client.status.state === StorageConsumerState.Ready
);
const total = clients.length;
if (total === 0) {
return t('0 connected clients');
} else {
return t('{{connected}} / {{total}} clients connected', {
connected: connectedClients.length,
total,
});
}
};
4 changes: 2 additions & 2 deletions packages/odf/components/storage-consumers/client-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import {
useListPageFilter,
useModal,
} from '@openshift-console/dynamic-plugin-sdk';
import { StorageConsumerModel } from 'packages/odf/models';
import { Button } from '@patternfly/react-core';
import { sortable } from '@patternfly/react-table';
import { StorageConsumerModel } from '../../models';
import { ClientOnBoardingModal } from './onboarding-modal';

const tableColumns = [
Expand Down Expand Up @@ -156,7 +156,7 @@ const StorageClientRow: React.FC<RowProps<StorageConsumerKind, {}>> = ({
};

const storageClientFilter = (_t): RowFilter<StorageConsumerKind> => {
throw new Error('function not defined');
return {} as any;
};

type ClientListPageProps = {
Expand Down
52 changes: 31 additions & 21 deletions packages/odf/components/storage-consumers/onboarding-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import * as React from 'react';
import { ModalBody, ModalTitle, useCustomTranslation } from '@odf/shared';
import { SecretValue } from '@odf/shared/utils/SecretValue';
import { ModalComponent } from '@openshift-console/dynamic-plugin-sdk/lib/app/modal-support/ModalProvider';
import { Modal, Button } from '@patternfly/react-core';
import {
Modal,
Button,
ModalVariant,
FlexItem,
Flex,
} from '@patternfly/react-core';
import { EyeIcon, EyeSlashIcon } from '@patternfly/react-icons';

type ClientOnBoardingModalProps = ModalComponent<{
Expand All @@ -23,28 +29,32 @@ export const ClientOnBoardingModal: ClientOnBoardingModalProps = ({
// Todo(bipuladh): Add a HTTP request to proxy to get ticket

return (
<Modal isOpen={isOpen} onClose={closeModal}>
<Modal isOpen={isOpen} onClose={closeModal} variant={ModalVariant.small}>
<ModalTitle>{MODAL_TITLE}</ModalTitle>
<ModalBody>
<SecretValue value={ticket} reveal={showSecret} encoded={false} />
<Button
type="button"
onClick={() => toggleSecret(!showSecret)}
variant="link"
className="pf-m-link--align-right"
>
{showSecret ? (
<>
<EyeSlashIcon className="co-icon-space-r" />
{t('Hide Values')}
</>
) : (
<>
<EyeIcon className="co-icon-space-r" />
{t('Reveal Values')}
</>
)}
</Button>
<Flex>
<FlexItem grow={{ default: 'grow' }}>
<SecretValue value={ticket} reveal={showSecret} encoded={false} />
</FlexItem>
<FlexItem maxLength={5}>
<Button
type="button"
onClick={() => toggleSecret(!showSecret)}
variant="link"
className="pf-m-link--align-right"
>
{showSecret ? (
<>
<EyeSlashIcon className="co-icon-space-r" />
</>
) : (
<>
<EyeIcon className="co-icon-space-r" />
</>
)}
</Button>
</FlexItem>
</Flex>
</ModalBody>
</Modal>
);
Expand Down
5 changes: 5 additions & 0 deletions packages/odf/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const CEPH_FLAG = 'CEPH'; // Based on the existence of CephCluster
export const OCS_FLAG = 'OCS'; // Based on the existence of StorageCluster
export const OCS_NFS_ENABLED = 'NFS'; // Based on the enablement of NFS from StorageCluster spec
export const ODF_ADMIN = 'ODF_ADMIN'; // Set to "true" if user is an "openshift-storage" admin (access to StorageSystems)
export const PROVIDER_MODE = 'PROVIDER_MODE'; // Set to "true" if user has deployed it in provider mode

// Check the user's access to some resources.
const ssarChecks = [
Expand All @@ -43,6 +44,9 @@ const ssarChecks = [
},
];

const isProviderMode = (cluster: StorageClusterKind): boolean =>
!!cluster.spec.allowRemoteStorageConsumers;

const setOCSFlagsFalse = (setFlag: SetFeatureFlag) => {
setFlag(OCS_FLAG, false);
setFlag(OCS_CONVERGED_FLAG, false);
Expand Down Expand Up @@ -81,6 +85,7 @@ export const setOCSFlags = async (setFlag: SetFeatureFlag) => {
'standalone'
);
setFlag(OCS_NFS_ENABLED, storageCluster?.spec?.nfs?.enable === true);
setFlag(PROVIDER_MODE, isProviderMode(storageCluster));
clearInterval(ocsIntervalId);
} else if (setFlagFalse) {
setFlagFalse = false;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/types/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export type StorageClusterKind = K8sResourceCommon & {
dbStorageClassName: string;
};
externalStorage?: {};
allowRemoteStorageConsumers?: boolean;
};
status?: {
phase: string;
Expand Down
Loading

0 comments on commit 1e020e0

Please sign in to comment.