Skip to content

feat: cpu info toggle – display top queries for last hour #1049

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

Merged
merged 1 commit into from
Jul 23, 2024
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
13 changes: 12 additions & 1 deletion src/components/DateRange/DateRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ export interface DateRangeValues {
to?: string;
}

const DEFAULT_VALUE = {
start: {
value: 'now-1h',
type: 'relative',
},
end: {
value: 'now',
type: 'relative',
},
} as const;

interface DateRangeProps extends DateRangeValues {
className?: string;
onChange?: (value: DateRangeValues) => void;
Expand All @@ -45,7 +56,7 @@ export const DateRange = ({from, to, className, onChange}: DateRangeProps) => {
withPresets
className={b('range-input', {[getdatePickerSize(value)]: true})}
timeZone={timeZoneString}
value={value || null}
value={value || DEFAULT_VALUE}
allowNullableValues
size="m"
format={i18n('date-time-format')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ import {useHistory, useLocation} from 'react-router-dom';

import {parseQuery} from '../../../../../routes';
import {changeUserInput} from '../../../../../store/reducers/executeQuery';
import {
setTopQueriesFilters,
topQueriesApi,
} from '../../../../../store/reducers/executeTopQueries/executeTopQueries';
import {
TENANT_DIAGNOSTICS_TABS_IDS,
TENANT_PAGE,
TENANT_PAGES_IDS,
TENANT_QUERY_TABS_ID,
} from '../../../../../store/reducers/tenant/constants';
import {topQueriesApi} from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries';
import {useAutoRefreshInterval, useTypedDispatch} from '../../../../../utils/hooks';
import {parseQueryErrorToString} from '../../../../../utils/query';
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
import {
TENANT_OVERVIEW_TOP_QUERUES_COLUMNS,
TOP_QUERIES_COLUMNS_WIDTH_LS_KEY,
getTenantOverviewTopQueriesColumns,
} from '../../TopQueries/getTopQueriesColumns';
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
import {getSectionTitle} from '../getSectionTitle';
Expand All @@ -35,9 +38,9 @@ export function TopQueries({tenantName}: TopQueriesProps) {
const query = parseQuery(location);

const [autoRefreshInterval] = useAutoRefreshInterval();
const columns = getTenantOverviewTopQueriesColumns();
const columns = TENANT_OVERVIEW_TOP_QUERUES_COLUMNS;

const {currentData, isFetching, error} = topQueriesApi.useGetOverviewTopQueriesQuery(
const {currentData, isFetching, error} = topQueriesApi.useGetTopQueriesQuery(
{database: tenantName},
{pollingInterval: autoRefreshInterval},
);
Expand Down Expand Up @@ -66,7 +69,10 @@ export function TopQueries({tenantName}: TopQueriesProps) {

const title = getSectionTitle({
entity: i18n('queries'),
postfix: i18n('by-cpu-time'),
postfix: i18n('by-cpu-time', {executionPeriod: i18n('executed-last-hour')}),
onClick: () => {
dispatch(setTopQueriesFilters({from: undefined, to: undefined}));
},
link: getTenantPath({
...query,
[TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.topQueries,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface GetSectionTitleParams {
postfix: string;
prefix?: string;
link?: string;
onClick?: () => void;
}

// Titles are formed by the principle "Top entities by parameter"
Expand All @@ -17,11 +18,16 @@ export const getSectionTitle = ({
entity,
postfix,
link,
onClick,
}: GetSectionTitleParams) => {
if (link) {
return (
<React.Fragment>
{prefix} <InternalLink to={link}>{entity}</InternalLink> {postfix}
{prefix}{' '}
<InternalLink to={link} onClick={onClick}>
{entity}
</InternalLink>{' '}
{postfix}
</React.Fragment>
);
}
Expand Down
6 changes: 4 additions & 2 deletions src/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"tables": "tables",

"by-pools-usage": "by pools usage",
"by-cpu-time": "by cpu time",
"by-cpu-time": "by cpu time, {{executionPeriod}}",
"by-cpu-usage": "by cpu usage",
"by-load": "by load",
"by-memory": "by memory",
Expand All @@ -34,5 +34,7 @@
"storage.tablet-storage-title": "Tablet storage",
"storage.tablet-storage-description": "Size of user data and indexes stored in schema objects (tables, topics, etc.)",
"storage.db-storage-title": "Database storage",
"storage.db-storage-description": "Size of data stored in distributed storage with all overheads for redundancy"
"storage.db-storage-description": "Size of data stored in distributed storage with all overheads for redundancy",

"executed-last-hour": "executed in the last hour"
}
4 changes: 2 additions & 2 deletions src/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {TenantTabsGroups, getTenantPath} from '../../TenantPages';
import {QUERY_TABLE_SETTINGS} from '../../utils/constants';
import {isColumnEntityType} from '../../utils/schema';

import {TOP_QUERIES_COLUMNS_WIDTH_LS_KEY, getTopQueriesColumns} from './getTopQueriesColumns';
import {TOP_QUERIES_COLUMNS, TOP_QUERIES_COLUMNS_WIDTH_LS_KEY} from './getTopQueriesColumns';
import i18n from './i18n';

import './TopQueries.scss';
Expand Down Expand Up @@ -57,7 +57,7 @@ export const TopQueries = ({tenantName, type}: TopQueriesProps) => {
const loading = isFetching && currentData === undefined;
const {result: data} = currentData || {};

const rawColumns = getTopQueriesColumns();
const rawColumns = TOP_QUERIES_COLUMNS;
const columns = rawColumns.map((column) => ({
...column,
sortable: isSortableTopQueriesProperty(column.name),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,18 @@ const durationColumn: Column<KeyValueRow> = {
width: 150,
};

export const getTopQueriesColumns = (): Column<KeyValueRow>[] => {
return [
cpuTimeUsColumn,
queryTextColumn,
endTimeColumn,
durationColumn,
readRowsColumn,
readBytesColumn,
userSIDColumn,
];
};
export const TOP_QUERIES_COLUMNS = [
cpuTimeUsColumn,
queryTextColumn,
endTimeColumn,
durationColumn,
readRowsColumn,
readBytesColumn,
userSIDColumn,
];

export const getTenantOverviewTopQueriesColumns = (): Column<KeyValueRow>[] => {
return [queryHashColumn, oneLineQueryTextColumn, cpuTimeUsColumn];
};
export const TENANT_OVERVIEW_TOP_QUERUES_COLUMNS = [
queryHashColumn,
oneLineQueryTextColumn,
cpuTimeUsColumn,
];
15 changes: 14 additions & 1 deletion src/containers/Tenant/TenantPages.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import routes, {createHref} from '../../routes';
import {TENANT_SUMMARY_TABS_IDS} from '../../store/reducers/tenant/constants';
import type {paramSetup} from '../../store/state-url-mapping';
import type {ExtractType} from '../../types/common';

type TenantQueryParams = {
[K in keyof (typeof paramSetup)['/tenant']]?: ExtractType<(typeof paramSetup)['/tenant'][K]>;
};

type AdditionalQueryParams = {
name?: string;
backend?: string;
};

type TenantQuery = TenantQueryParams | AdditionalQueryParams;

export const TenantTabsGroups = {
summaryTab: 'summaryTab',
Expand All @@ -26,6 +39,6 @@ export const TENANT_SCHEMA_TAB = [
},
];

export const getTenantPath = (query = {}) => {
export const getTenantPath = (query: TenantQuery) => {
return createHref(routes.tenant, undefined, query);
};
4 changes: 2 additions & 2 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ export function createHref(
) {
let extendedQuery = query;

const isBackendInQuery = Boolean(query.backend);
const isBackendInQuery = 'backend' in query && Boolean(query.backend);
if (backend && !isBackendInQuery && webVersion) {
extendedQuery = {...query, backend};
}

const isClusterNameInQuery = Boolean(query.clusterName);
const isClusterNameInQuery = 'clusterName' in query && Boolean(query.clusterName);
if (clusterName && !isClusterNameInQuery && webVersion) {
extendedQuery = {...extendedQuery, clusterName};
}
Expand Down
16 changes: 10 additions & 6 deletions src/store/reducers/executeTopQueries/executeTopQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,19 @@ export const topQueriesApi = api.injectEndpoints({
getTopQueries: build.query({
queryFn: async (
{database, filters}: {database: string; filters?: TopQueriesFilters},
{signal, dispatch},
{signal},
) => {
const preparedFilters = {
...filters,
from: filters?.from || 'now-1h',
to: filters?.to || 'now',
};

try {
const response = await window.api.sendQuery(
{
schema: 'modern',
query: getQueryText(database, filters),
query: getQueryText(database, preparedFilters),
database,
action: 'execute-scan',
},
Expand All @@ -64,17 +70,15 @@ export const topQueriesApi = api.injectEndpoints({
}

const data = parseQueryAPIExecuteResponse(response);

if (!filters?.from && !filters?.to) {
dispatch(setTopQueriesFilters({from: 'now-1h', to: 'now'}));
}
return {data};
} catch (error) {
return {error};
}
},
forceRefetch: ({currentArg}) => {
if (
!currentArg?.filters?.from ||
!currentArg?.filters?.to ||
isLikeRelative(currentArg?.filters?.from) ||
isLikeRelative(currentArg?.filters?.to)
) {
Expand Down

This file was deleted.

6 changes: 3 additions & 3 deletions src/store/state-url-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {stateToParams} from 'redux-location-state/lib/stateToParams';
import {initialState as initialHeatmapState} from './reducers/heatmap';
import {initialState as initialSettingsState} from './reducers/settings/settings';

const paramSetup: ParamSetup = {
export const paramSetup = {
global: {
problemFilter: {
stateKey: 'settings.problemFilter',
Expand Down Expand Up @@ -83,7 +83,7 @@ const paramSetup: ParamSetup = {
stateKey: 'tenants.searchValue',
},
},
};
} as const;

function mergeLocationToState<S>(state: S, location: Pick<LocationWithQuery, 'query'>): S {
return merge({}, state, location.query);
Expand All @@ -95,7 +95,7 @@ function restoreUnknownParams(location: Location, prevLocation: Location) {

// figure out which path key inside paramSetup matches location.pathname
const declaredPath = getMatchingDeclaredPath(paramSetup, location);
const entries = declaredPath && paramSetup[declaredPath];
const entries = declaredPath && paramSetup[declaredPath as keyof typeof paramSetup];

// remove params which are mapped for this page
each(keys(entries), (param) => {
Expand Down
1 change: 1 addition & 0 deletions src/types/common.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export type ValueOf<T extends Object> = T[keyof T];
export type ExtractType<T> = T extends {type: infer U} ? U : string;
Loading