diff --git a/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx b/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx index 260022a1d9..6e9377a819 100644 --- a/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx +++ b/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx @@ -10,7 +10,8 @@ import type {VersionToColorMap} from '../../../types/versions'; import i18n from '../i18n'; import {b} from './shared'; -import {getInfo, useClusterLinks} from './utils'; +import {useClusterLinks} from './utils/useClusterLinks'; +import {getInfo} from './utils/utils'; import './ClusterInfo.scss'; diff --git a/src/containers/Cluster/ClusterInfo/utils.tsx b/src/containers/Cluster/ClusterInfo/utils.tsx deleted file mode 100644 index 873ad31d37..0000000000 --- a/src/containers/Cluster/ClusterInfo/utils.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import React from 'react'; - -import {Flex} from '@gravity-ui/uikit'; - -import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer'; -import {Tags} from '../../../components/Tags'; -import {useClusterBaseInfo} from '../../../store/reducers/cluster/cluster'; -import type {ClusterLink} from '../../../types/additionalProps'; -import {isClusterInfoV2} from '../../../types/api/cluster'; -import type {TClusterInfo} from '../../../types/api/cluster'; -import type {EFlag} from '../../../types/api/enums'; -import type {InfoItem} from '../../../types/components'; -import {formatNumber} from '../../../utils/dataFormatters/dataFormatters'; -import {parseJson} from '../../../utils/utils'; -import i18n from '../i18n'; - -import {NodesState} from './components/NodesState/NodesState'; -import {b} from './shared'; - -const COLORS_PRIORITY: Record = { - Green: 5, - Blue: 4, - Yellow: 3, - Orange: 2, - Red: 1, - Grey: 0, -}; - -const getDCInfo = (cluster: TClusterInfo) => { - if (isClusterInfoV2(cluster) && cluster.MapDataCenters) { - return Object.entries(cluster.MapDataCenters).map(([dc, count]) => ( - - {dc}: {formatNumber(count)} - - )); - } - return undefined; -}; - -export const getInfo = (cluster: TClusterInfo, additionalInfo: InfoItem[]) => { - const info: InfoItem[] = []; - - if (isClusterInfoV2(cluster) && cluster.MapNodeStates) { - const arrayNodesStates = Object.entries(cluster.MapNodeStates) as [EFlag, number][]; - // sort stack to achieve order "green, orange, yellow, red, blue, grey" - arrayNodesStates.sort((a, b) => COLORS_PRIORITY[b[0]] - COLORS_PRIORITY[a[0]]); - const nodesStates = arrayNodesStates.map(([state, count]) => { - return ( - - {formatNumber(count)} - - ); - }); - info.push({ - label: i18n('label_nodes-state'), - value: {nodesStates}, - }); - } - - const dataCenters = getDCInfo(cluster); - if (dataCenters?.length) { - info.push({ - label: i18n('label_dc'), - value: , - }); - } - - info.push({ - label: i18n('label_load'), - value: , - }); - - info.push(...additionalInfo); - - return info; -}; - -/** - * parses stringified json in format {url: "href"} - */ -function prepareClusterLink(rawLink?: string) { - try { - const linkObject = parseJson(rawLink) as unknown; - - if ( - linkObject && - typeof linkObject === 'object' && - 'url' in linkObject && - typeof linkObject.url === 'string' - ) { - return linkObject.url; - } - } catch {} - - return undefined; -} - -export function useClusterLinks() { - const {cores, logging} = useClusterBaseInfo(); - - return React.useMemo(() => { - const result: ClusterLink[] = []; - - const coresLink = prepareClusterLink(cores); - const loggingLink = prepareClusterLink(logging); - - if (coresLink) { - result.push({ - title: i18n('link_cores'), - url: coresLink, - }); - } - - if (loggingLink) { - result.push({ - title: i18n('link_logging'), - url: loggingLink, - }); - } - - return result; - }, [cores, logging]); -} diff --git a/src/containers/Cluster/ClusterInfo/utils/__tests__/prepareLinks.test.ts b/src/containers/Cluster/ClusterInfo/utils/__tests__/prepareLinks.test.ts new file mode 100644 index 0000000000..c750c092a2 --- /dev/null +++ b/src/containers/Cluster/ClusterInfo/utils/__tests__/prepareLinks.test.ts @@ -0,0 +1,51 @@ +import {prepareClusterCoresLink, prepareClusterLoggingLinks} from '../useClusterLinks'; + +describe('prepareClusterCoresLink', () => { + it('It should parse stringified json with cores url', () => { + expect( + prepareClusterCoresLink('{"url":"https://coredumps.com?cluster=my_cluster"}'), + ).toEqual('https://coredumps.com?cluster=my_cluster'); + }); + + it('It should return undefined if input is undefined', () => { + expect(prepareClusterCoresLink(undefined)).toEqual(undefined); + }); + it('It should return undefined if input is incorrect', () => { + expect(prepareClusterCoresLink('hello')).toEqual(undefined); + }); +}); + +describe('prepareClusterLoggingLinks', () => { + it('It should parse stringified json with logging and slo logs urls', () => { + expect( + prepareClusterLoggingLinks( + '{"url":"https://logging.com/logs?cluster=my_cluster","slo_logs_url":"https://logging.com/slo-logs?cluster=my_cluster"}', + ), + ).toEqual({ + logsUrl: 'https://logging.com/logs?cluster=my_cluster', + sloLogsUrl: 'https://logging.com/slo-logs?cluster=my_cluster', + }); + }); + it('It should parse stringified json with only logging url', () => { + expect( + prepareClusterLoggingLinks('{"url":"https://logging.com/logs?cluster=my_cluster"}'), + ).toEqual({ + logsUrl: 'https://logging.com/logs?cluster=my_cluster', + }); + }); + it('It should parse stringified json with only slo logs url', () => { + expect( + prepareClusterLoggingLinks( + '{"slo_logs_url":"https://logging.com/slo-logs?cluster=my_cluster"}', + ), + ).toEqual({ + sloLogsUrl: 'https://logging.com/slo-logs?cluster=my_cluster', + }); + }); + it('It should return empty object if input is undefined', () => { + expect(prepareClusterLoggingLinks(undefined)).toEqual({}); + }); + it('It should return empty object if input is incorrect', () => { + expect(prepareClusterLoggingLinks('hello')).toEqual({}); + }); +}); diff --git a/src/containers/Cluster/ClusterInfo/utils/useClusterLinks.ts b/src/containers/Cluster/ClusterInfo/utils/useClusterLinks.ts new file mode 100644 index 0000000000..e1cb622f81 --- /dev/null +++ b/src/containers/Cluster/ClusterInfo/utils/useClusterLinks.ts @@ -0,0 +1,83 @@ +import React from 'react'; + +import {useClusterBaseInfo} from '../../../../store/reducers/cluster/cluster'; +import type {ClusterLink} from '../../../../types/additionalProps'; +import {parseJson} from '../../../../utils/utils'; +import i18n from '../../i18n'; + +/** + * parses stringified json in format {url: "href"} + */ +export function prepareClusterCoresLink(rawCoresString?: string) { + try { + const linkObject = parseJson(rawCoresString) as unknown; + + if ( + linkObject && + typeof linkObject === 'object' && + 'url' in linkObject && + typeof linkObject.url === 'string' + ) { + return linkObject.url; + } + } catch {} + + return undefined; +} + +/** + * parses stringified json in format {url: "href", slo_logs_url: "href"} + */ +export function prepareClusterLoggingLinks(rawLoggingString?: string) { + try { + const linkObject = parseJson(rawLoggingString) as unknown; + + if (linkObject && typeof linkObject === 'object') { + const logsUrl = + 'url' in linkObject && typeof linkObject.url === 'string' + ? linkObject.url + : undefined; + const sloLogsUrl = + 'slo_logs_url' in linkObject && typeof linkObject.slo_logs_url === 'string' + ? linkObject.slo_logs_url + : undefined; + return {logsUrl, sloLogsUrl}; + } + } catch {} + + return {}; +} + +export function useClusterLinks() { + const {cores, logging} = useClusterBaseInfo(); + + return React.useMemo(() => { + const result: ClusterLink[] = []; + + const coresUrl = prepareClusterCoresLink(cores); + const {logsUrl, sloLogsUrl} = prepareClusterLoggingLinks(logging); + + if (coresUrl) { + result.push({ + title: i18n('link_cores'), + url: coresUrl, + }); + } + + if (logsUrl) { + result.push({ + title: i18n('link_logging'), + url: logsUrl, + }); + } + + if (sloLogsUrl) { + result.push({ + title: i18n('link_slo-logs'), + url: sloLogsUrl, + }); + } + + return result; + }, [cores, logging]); +} diff --git a/src/containers/Cluster/ClusterInfo/utils/utils.tsx b/src/containers/Cluster/ClusterInfo/utils/utils.tsx new file mode 100644 index 0000000000..5abc43505a --- /dev/null +++ b/src/containers/Cluster/ClusterInfo/utils/utils.tsx @@ -0,0 +1,72 @@ +import React from 'react'; + +import {Flex} from '@gravity-ui/uikit'; + +import {ProgressViewer} from '../../../../components/ProgressViewer/ProgressViewer'; +import {Tags} from '../../../../components/Tags'; +import {isClusterInfoV2} from '../../../../types/api/cluster'; +import type {TClusterInfo} from '../../../../types/api/cluster'; +import type {EFlag} from '../../../../types/api/enums'; +import type {InfoItem} from '../../../../types/components'; +import {formatNumber} from '../../../../utils/dataFormatters/dataFormatters'; +import i18n from '../../i18n'; +import {NodesState} from '../components/NodesState/NodesState'; +import {b} from '../shared'; + +const COLORS_PRIORITY: Record = { + Green: 5, + Blue: 4, + Yellow: 3, + Orange: 2, + Red: 1, + Grey: 0, +}; + +const getDCInfo = (cluster: TClusterInfo) => { + if (isClusterInfoV2(cluster) && cluster.MapDataCenters) { + return Object.entries(cluster.MapDataCenters).map(([dc, count]) => ( + + {dc}: {formatNumber(count)} + + )); + } + return undefined; +}; + +export const getInfo = (cluster: TClusterInfo, additionalInfo: InfoItem[]) => { + const info: InfoItem[] = []; + + if (isClusterInfoV2(cluster) && cluster.MapNodeStates) { + const arrayNodesStates = Object.entries(cluster.MapNodeStates) as [EFlag, number][]; + // sort stack to achieve order "green, orange, yellow, red, blue, grey" + arrayNodesStates.sort((a, b) => COLORS_PRIORITY[b[0]] - COLORS_PRIORITY[a[0]]); + const nodesStates = arrayNodesStates.map(([state, count]) => { + return ( + + {formatNumber(count)} + + ); + }); + info.push({ + label: i18n('label_nodes-state'), + value: {nodesStates}, + }); + } + + const dataCenters = getDCInfo(cluster); + if (dataCenters?.length) { + info.push({ + label: i18n('label_dc'), + value: , + }); + } + + info.push({ + label: i18n('label_load'), + value: , + }); + + info.push(...additionalInfo); + + return info; +}; diff --git a/src/containers/Cluster/i18n/en.json b/src/containers/Cluster/i18n/en.json index 2cd3ae4010..07ec6c9ae2 100644 --- a/src/containers/Cluster/i18n/en.json +++ b/src/containers/Cluster/i18n/en.json @@ -11,6 +11,7 @@ "links": "Links", "link_cores": "Coredumps", "link_logging": "Logging", + "link_slo-logs": "Slo Logs", "context_cores": "cores", "title_cpu": "CPU", "title_storage": "Storage",