Skip to content
Merged
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

This file was deleted.

59 changes: 6 additions & 53 deletions src/containers/Cluster/ClusterInfo/utils/useClusterLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,79 +2,32 @@ 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) {
if (cores?.url) {
result.push({
title: i18n('link_cores'),
url: coresUrl,
url: cores?.url,
});
}

if (logsUrl) {
if (logging?.url) {
result.push({
title: i18n('link_logging'),
url: logsUrl,
url: logging?.url,
});
}

if (sloLogsUrl) {
if (logging?.slo_logs_url) {
result.push({
title: i18n('link_slo-logs'),
url: sloLogsUrl,
url: logging.slo_logs_url,
});
}

Expand Down
16 changes: 0 additions & 16 deletions src/services/parsers/parseMetaCluster.ts

This file was deleted.

99 changes: 99 additions & 0 deletions src/store/reducers/cluster/__test__/parseFields.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {parseCoresUrl, parseLoggingUrls, parseTraceField} from '../parseFields';

describe('parseCoresUrl', () => {
test('It should parse stringified json with cores url', () => {
expect(parseCoresUrl('{"url":"https://coredumps.com?cluster=my_cluster"}')).toEqual({
url: 'https://coredumps.com?cluster=my_cluster',
});
});

test('It should return undefined if input is undefined', () => {
expect(parseCoresUrl(undefined)).toEqual(undefined);
});
test('It should return undefined if input is incorrect', () => {
expect(parseCoresUrl('hello')).toEqual(undefined);
});

test('It should return the object as-is if input is already an object', () => {
const coresObject = {url: 'https://coredumps.com?cluster=my_cluster'};
expect(parseCoresUrl(coresObject)).toEqual(coresObject);
});
});

describe('parseLoggingUrls', () => {
test('It should parse stringified json with logging and slo logs urls', () => {
expect(
parseLoggingUrls(
'{"url":"https://logging.com/logs?cluster=my_cluster","slo_logs_url":"https://logging.com/slo-logs?cluster=my_cluster"}',
),
).toEqual({
url: 'https://logging.com/logs?cluster=my_cluster',
slo_logs_url: 'https://logging.com/slo-logs?cluster=my_cluster',
});
});
test('It should parse stringified json with only logging url', () => {
expect(parseLoggingUrls('{"url":"https://logging.com/logs?cluster=my_cluster"}')).toEqual({
url: 'https://logging.com/logs?cluster=my_cluster',
});
});
test('It should parse stringified json with only slo logs url', () => {
expect(
parseLoggingUrls('{"slo_logs_url":"https://logging.com/slo-logs?cluster=my_cluster"}'),
).toEqual({
slo_logs_url: 'https://logging.com/slo-logs?cluster=my_cluster',
});
});
test('It should return undefined if input is undefined', () => {
expect(parseLoggingUrls(undefined)).toEqual(undefined);
});
test('It should return undefined if input is incorrect', () => {
expect(parseLoggingUrls('hello')).toEqual(undefined);
});

test('It should return the object as-is if input is already an object', () => {
const loggingObject = {
url: 'https://logging.com/logs?cluster=my_cluster',
slo_logs_url: 'https://logging.com/slo-logs?cluster=my_cluster',
};
expect(parseLoggingUrls(loggingObject)).toEqual(loggingObject);
});

test('It should return the object as-is if input is already an object with only url', () => {
const loggingObject = {url: 'https://logging.com/logs?cluster=my_cluster'};
expect(parseLoggingUrls(loggingObject)).toEqual(loggingObject);
});

test('It should return the object as-is if input is already an object with only slo_logs_url', () => {
const loggingObject = {slo_logs_url: 'https://logging.com/slo-logs?cluster=my_cluster'};
expect(parseLoggingUrls(loggingObject)).toEqual(loggingObject);
});
});

describe('parseTraceField', () => {
test('It should parse stringified json with trace view url', () => {
expect(parseTraceField('{"url":"https://tracing.com/trace?cluster=my_cluster"}')).toEqual({
url: 'https://tracing.com/trace?cluster=my_cluster',
});
});

test('It should return undefined if input is undefined', () => {
expect(parseTraceField(undefined)).toEqual(undefined);
});

test('It should return undefined if input is empty string', () => {
expect(parseTraceField('')).toEqual(undefined);
});

test('It should return undefined if input is incorrect json', () => {
expect(parseTraceField('hello')).toEqual(undefined);
});

test('It should return undefined if parsed json does not match schema', () => {
expect(parseTraceField('{"invalid":"field"}')).toEqual(undefined);
});

test('It should return the object as-is if input is already an object', () => {
const traceObject = {url: 'https://tracing.com/trace?cluster=my_cluster'};
expect(parseTraceField(traceObject)).toEqual(traceObject);
});
});
13 changes: 9 additions & 4 deletions src/store/reducers/cluster/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {skipToken} from '@reduxjs/toolkit/query';

import type {ClusterTab} from '../../../containers/Cluster/utils';
import {clusterTabsIds, isClusterTab} from '../../../containers/Cluster/utils';
import {parseTraceFields} from '../../../services/parsers/parseMetaCluster';
import {isClusterInfoV2} from '../../../types/api/cluster';
import type {TClusterInfo} from '../../../types/api/cluster';
import type {TTabletStateInfo} from '../../../types/api/tablet';
Expand All @@ -16,6 +15,7 @@ import type {RootState} from '../../defaultStore';
import {api} from '../api';
import {selectNodesMap} from '../nodesList';

import {parseCoresUrl, parseLoggingUrls, parseTraceField} from './parseFields';
import type {ClusterGroupsStats, ClusterState} from './types';
import {
createSelectClusterGroupsQuery,
Expand Down Expand Up @@ -147,7 +147,7 @@ export function useClusterBaseInfo() {
skip: !isViewerUser,
});

const {solomon: monitoring, name, title, trace_view: traceView, ...data} = currentData || {};
const {solomon: monitoring, name, title, ...data} = currentData || {};

// name is used for requests, title is used for display
// Example:
Expand All @@ -158,10 +158,15 @@ export function useClusterBaseInfo() {

return {
...data,
...parseTraceFields({traceView}),

monitoring,

name: clusterName,
title: clusterTitle,
monitoring,

traceView: parseTraceField(data.trace_view),
cores: parseCoresUrl(data.cores),
logging: parseLoggingUrls(data.logging),
};
}

Expand Down
67 changes: 67 additions & 0 deletions src/store/reducers/cluster/parseFields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {z} from 'zod';

import type {
MetaBaseClusterInfo,
MetaClusterCoresUrl,
MetaClusterLogsUrls,
MetaClusterTraceView,
} from '../../../types/api/meta';

const traceViewSchema = z.object({
url: z.string().url(),
});

export function parseTraceField(
traceView: MetaBaseClusterInfo['trace_view'],
): MetaClusterTraceView | undefined {
if (traceView && typeof traceView === 'object') {
return traceView;
}
try {
return traceView ? traceViewSchema.parse(JSON.parse(traceView)) : undefined;
} catch (e) {
console.error('Error parsing trace_view field:', e);
}

return undefined;
}

const coresUrlSchema = z.object({
url: z.string().url(),
});

export function parseCoresUrl(
cores: MetaBaseClusterInfo['cores'],
): MetaClusterCoresUrl | undefined {
if (cores && typeof cores === 'object') {
return cores;
}
try {
return cores ? coresUrlSchema.parse(JSON.parse(cores)) : undefined;
} catch (e) {
console.error('Error parsing cores field:', e);
}

return undefined;
}

const loggingUrlsSchema = z.object({
url: z.string().url().optional(),
slo_logs_url: z.string().url().optional(),
monium_cluster: z.string().optional(),
});

export function parseLoggingUrls(
logging: MetaBaseClusterInfo['logging'],
): MetaClusterLogsUrls | undefined {
if (logging && typeof logging === 'object') {
return logging;
}
try {
return logging ? loggingUrlsSchema.parse(JSON.parse(logging)) : undefined;
} catch (e) {
console.error('Error parsing logging field:', e);
}

return undefined;
}
Loading
Loading