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

feat: parse logging link as default value #2036

Merged
merged 6 commits into from
Mar 24, 2025
Merged
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion src/containers/AppWithClusters/AppWithClusters.tsx
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ import React from 'react';
import type {Store} from '@reduxjs/toolkit';
import type {History} from 'history';

import {getLogsLink as getLogsLinkDefault} from '../../utils/logs';
import type {
GetLogsLink,
GetMonitoringClusterLink,
@@ -31,7 +32,7 @@ export interface AppWithClustersProps {
export function AppWithClusters({
store,
history,
getLogsLink,
getLogsLink = getLogsLinkDefault,
getMonitoringLink = getMonitoringLinkDefault,
getMonitoringClusterLink = getMonitoringClusterLinkDefault,
userSettings,
65 changes: 42 additions & 23 deletions src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx
Original file line number Diff line number Diff line change
@@ -38,12 +38,19 @@ const getAdditionalBalancerInfo = (balancer: string) => {
};
};

const getAdditionalClusterProps = (
clusterName: string | undefined,
monitoring: string | undefined,
balancer: string | undefined,
getMonitoringClusterLink?: GetMonitoringClusterLink,
) => {
interface GetAdditionalClusterProps {
clusterName: string | undefined;
monitoring: string | undefined;
balancer: string | undefined;
getMonitoringClusterLink?: GetMonitoringClusterLink;
}

const getAdditionalClusterProps = ({
clusterName,
monitoring,
balancer,
getMonitoringClusterLink,
}: GetAdditionalClusterProps) => {
const additionalClusterProps: AdditionalClusterProps = {};

if (monitoring && getMonitoringClusterLink) {
@@ -61,14 +68,25 @@ const getAdditionalClusterProps = (
return additionalClusterProps;
};

const getAdditionalTenantsProps = (
clusterName: string | undefined,
monitoring: string | undefined,
balancer: string | undefined,
useClusterBalancerAsBackend: boolean | undefined,
getMonitoringLink?: GetMonitoringLink,
getLogsLink?: GetLogsLink,
) => {
interface GetAdditionalTenantsProps {
clusterName: string | undefined;
monitoring: string | undefined;
balancer: string | undefined;
logging: string | undefined;
useClusterBalancerAsBackend: boolean | undefined;
getMonitoringLink?: GetMonitoringLink;
getLogsLink?: GetLogsLink;
}

const getAdditionalTenantsProps = ({
clusterName,
monitoring,
balancer,
logging,
useClusterBalancerAsBackend,
getMonitoringLink,
getLogsLink,
}: GetAdditionalTenantsProps) => {
const additionalTenantsProps: AdditionalTenantsProps = {};

additionalTenantsProps.prepareTenantBackend = (
@@ -104,12 +122,12 @@ const getAdditionalTenantsProps = (
};
}

if (clusterName && getLogsLink) {
if (logging && getLogsLink) {
additionalTenantsProps.getLogsLink = (dbName?: string) => {
if (dbName) {
return getLogsLink({
dbName,
clusterName,
logging,
});
}

@@ -133,27 +151,28 @@ export function ExtendedCluster({
getLogsLink,
}: ExtendedClusterProps) {
const additionalNodesProps = useAdditionalNodesProps();
const {name, balancer, monitoring} = useClusterBaseInfo();
const {name, balancer, monitoring, logging} = useClusterBaseInfo();

const [useClusterBalancerAsBackend] = useSetting<boolean>(USE_CLUSTER_BALANCER_AS_BACKEND_KEY);

return (
<div className={b()}>
<ClusterComponent
additionalClusterProps={getAdditionalClusterProps(
name,
additionalClusterProps={getAdditionalClusterProps({
clusterName: name,
monitoring,
balancer,
getMonitoringClusterLink,
)}
additionalTenantsProps={getAdditionalTenantsProps(
name,
})}
additionalTenantsProps={getAdditionalTenantsProps({
clusterName: name,
monitoring,
balancer,
logging,
useClusterBalancerAsBackend,
getMonitoringLink,
getLogsLink,
)}
})}
additionalNodesProps={additionalNodesProps}
/>
</div>
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ export function ExtendedTenant({
getMonitoringLink,
getLogsLink,
}: ExtendedTenantProps) {
const {monitoring, name: clusterName} = useClusterBaseInfo();
const {monitoring, logging} = useClusterBaseInfo();
const additionalNodesProps = useAdditionalNodesProps();

const additionalTenantProps = {
@@ -31,10 +31,10 @@ export function ExtendedTenant({
return null;
},
getLogsLink: (dbName?: string) => {
if (clusterName && dbName && getLogsLink) {
if (logging && dbName && getLogsLink) {
return getLogsLink({
dbName,
clusterName,
logging,
});
}

51 changes: 51 additions & 0 deletions src/utils/__test__/logs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {getLogsLink} from '../logs';

describe('getLogsLink', () => {
test('should insert dbName into logs URL query', () => {
const loggingData = {
url: 'https://monitoring.yandex-team.ru/projects/kikimr/logs?from=now-1h&to=now&query=%7Bproject+%3D+%22kikimr%22%2C+service+%3D+%22ydb%22%2C+cluster+%3D+%22ydb-ru-prestable%22%7D',
};

const result = getLogsLink({
logging: JSON.stringify(loggingData),
dbName: 'testdb',
});

// The URL should contain the dbName in the query parameter
expect(result).toContain('database+%3D+%22testdb%22');
// Original query parts should still be present
expect(result).toContain('project+%3D+%22kikimr%22');
expect(result).toContain('service+%3D+%22ydb%22%');
expect(result).toContain('cluster+%3D+%22ydb-ru-prestable%22');
});

test('should handle empty query parameters', () => {
const loggingData = {
url: 'https://monitoring.yandex-team.ru/projects/kikimr/logs?from=now-1h&to=now&query=%7B%7D',
};

const result = getLogsLink({
logging: JSON.stringify(loggingData),
dbName: 'testdb',
});

// Should add dbName to empty query
expect(result).toContain('database+%3D+%22testdb%22');
});

test('should return empty string for invalid data', () => {
expect(
getLogsLink({
logging: 'invalid json',
dbName: 'testdb',
}),
).toBe('');

expect(
getLogsLink({
logging: JSON.stringify({}),
dbName: 'testdb',
}),
).toBe('');
});
});
37 changes: 37 additions & 0 deletions src/utils/logs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
interface GetLogsLinkProps {
dbName: string;
logging: string;
}

export type GetLogsLink = (props: GetLogsLinkProps) => string;

export function getLogsLink({dbName, logging}: GetLogsLinkProps): string {
try {
const data = JSON.parse(logging);

if (typeof data === 'object' && 'url' in data) {
const logUrl = data.url;
if (!logUrl) {
return '';
}

const url = new URL(logUrl);

const queryParam = url.searchParams.get('query');
if (queryParam) {
const decodedQuery = decodeURIComponent(queryParam);

const updatedQuery = decodedQuery.replace(/\{([^}]*)\}/, (_match, contents) => {
const trimmedContents = contents.trim();
return `{${trimmedContents}${trimmedContents ? ', ' : ''}database = "${dbName}"}`;
});

url.searchParams.set('query', updatedQuery);
}

return url.toString();
}
} catch {}

return '';
}
2 changes: 1 addition & 1 deletion src/utils/monitoring.ts
Original file line number Diff line number Diff line change
@@ -102,7 +102,7 @@ export function parseMonitoringData(monitoring: string): ParsedMonitoringData |

interface GetLogsLinkProps {
dbName: string;
clusterName: string;
logging: string;
}

export type GetLogsLink = (props: GetLogsLinkProps) => string;

Unchanged files with check annotations Beta

defaultValueFormatter?: (value: Shape[keyof Shape]) => React.ReactNode;
}
export function createInfoFormatter<Shape extends Record<string, any>>({

Check warning on line 35 in src/components/InfoViewer/utils.ts

GitHub Actions / Verify Files

Unexpected any. Specify a different type
values: valueFormatters,
labels: labelMap,
defaultValueFormatter,
className?: string;
}
type IllustrationStore = Record<string, Record<string, () => Promise<{default: any}>>>;

Check warning on line 12 in src/components/Illustration/Illustration.tsx

GitHub Actions / Verify Files

Unexpected any. Specify a different type
const store: IllustrationStore = {
light: {
srcGetter()
.then((svg) => setSrc(svg.default))
.catch((e) => {
console.error(e);

Check warning on line 39 in src/components/Illustration/Illustration.tsx

GitHub Actions / Verify Files

Unexpected console statement
setSrc('');
});
}
type RegistryEntity<T = any> = T;

Check warning on line 1 in src/components/ComponentsProvider/registry.ts

GitHub Actions / Verify Files

Unexpected any. Specify a different type
type RegistryEntities = Record<string, RegistryEntity>;
export class Registry<Entities extends RegistryEntities = {}> {
type?: Entities;
private entities: any = {};

Check warning on line 7 in src/components/ComponentsProvider/registry.ts

GitHub Actions / Verify Files

Unexpected any. Specify a different type
set<Id extends keyof Entities>(id: Id, entity: Entities[Id]) {
this.entities[id] = entity;
}
type ComponentType<T> =
T extends React.ComponentType<any>

Check warning on line 27 in src/components/ComponentsProvider/registry.ts

GitHub Actions / Verify Files

Unexpected any. Specify a different type
? React.ComponentType<React.ComponentPropsWithoutRef<T>>
: never;
});
if (env === 'production') {
config.output.path = path.resolve(__dirname, 'build/');

Check warning on line 35 in config-overrides.js

GitHub Actions / Verify Files

Assignment to property of function parameter 'config'
}
config.plugins.push(
new MonacoWebpackPlugin({
// By default jest does not transform anything in node_modules
// So this override excludes node_modules except @gravity-ui
// see https://github.com/timarney/react-app-rewired/issues/241
config.transformIgnorePatterns = ['node_modules/(?!(@gravity-ui|@mjackson)/)'];

Check warning on line 61 in config-overrides.js

GitHub Actions / Verify Files

Assignment to property of function parameter 'config'
// Add .github directory to roots
config.roots = ['<rootDir>/src', '<rootDir>/.github'];

Check warning on line 64 in config-overrides.js

GitHub Actions / Verify Files

Assignment to property of function parameter 'config'
// Update testMatch to include .github directory
config.testMatch = [

Check warning on line 67 in config-overrides.js

GitHub Actions / Verify Files

Assignment to property of function parameter 'config'
'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
'<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}',
'<rootDir>/.github/**/*.{spec,test}.{js,jsx,ts,tsx}',