Skip to content

Commit

Permalink
Fix bugs in UI and refactor code (#15)
Browse files Browse the repository at this point in the history
Signed-off-by: Chenyang Ji <cyji@amazon.com>
  • Loading branch information
ansjcy authored Sep 11, 2024
1 parent 4e7549d commit dcda4b8
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 88 deletions.
13 changes: 13 additions & 0 deletions common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export const TIMESTAMP = 'Timestamp';
export const LATENCY = 'Latency';
export const CPU_TIME = 'CPU Time';
export const MEMORY_USAGE = 'Memory Usage';
export const INDICES = 'Indices';
export const SEARCH_TYPE = 'Search type';
export const NODE_ID = 'Coordinator node ID';
export const TOTAL_SHARDS = 'Total shards';
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@testing-library/dom": "^8.11.3",
"@testing-library/user-event": "^14.4.3",
"@types/react-dom": "^16.9.8",
"@types/object-hash": "^3.0.0",
"@types/react-router-dom": "^5.3.2",
"cypress": "9.5.4",
"cypress-real-events": "1.7.6",
Expand Down
14 changes: 7 additions & 7 deletions public/components/__snapshots__/app.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
aria-live="polite"
aria-sort="none"
class="euiTableHeaderCell"
data-test-subj="tableHeaderCell_latency_1"
data-test-subj="tableHeaderCell_measurements_1"
role="columnheader"
scope="col"
>
Expand All @@ -477,7 +477,7 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
aria-live="polite"
aria-sort="none"
class="euiTableHeaderCell"
data-test-subj="tableHeaderCell_cpu_2"
data-test-subj="tableHeaderCell_measurements_2"
role="columnheader"
scope="col"
>
Expand All @@ -491,9 +491,9 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
>
<span
class="euiTableCellContent__text"
title="CPU usage"
title="CPU Time"
>
CPU usage
CPU Time
</span>
</span>
</button>
Expand All @@ -502,7 +502,7 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
aria-live="polite"
aria-sort="none"
class="euiTableHeaderCell"
data-test-subj="tableHeaderCell_memory_3"
data-test-subj="tableHeaderCell_measurements_3"
role="columnheader"
scope="col"
>
Expand All @@ -516,9 +516,9 @@ exports[`<QueryInsightsDashboardsApp /> spec renders the component 1`] = `
>
<span
class="euiTableCellContent__text"
title="Memory"
title="Memory Usage"
>
Memory
Memory Usage
</span>
</span>
</button>
Expand Down
2 changes: 1 addition & 1 deletion public/pages/Configuration/Configuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
EuiTitle,
} from '@elastic/eui';
import { useHistory, useLocation } from 'react-router-dom';
import { CoreStart } from '../../../../../src/core/public';
import { CoreStart } from 'opensearch-dashboards/public';
import { QUERY_INSIGHTS, MetricSettings } from '../TopNQueries/TopNQueries';

const Configuration = ({
Expand Down
88 changes: 39 additions & 49 deletions public/pages/QueryDetails/Components/QuerySummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,68 +5,58 @@

import React from 'react';
import { EuiFlexGrid, EuiFlexItem, EuiHorizontalRule, EuiPanel, EuiText } from '@elastic/eui';
import { SearchQueryRecord } from '../../../../types/types';
import {
CPU_TIME,
INDICES,
LATENCY,
MEMORY_USAGE,
NODE_ID,
SEARCH_TYPE,
TIMESTAMP,
TOTAL_SHARDS,
} from '../../../../common/constants';

const QuerySummary = ({ query }: { query: any }) => {
// Panel component for displaying query detail values
const PanelItem = ({ label, value }: { label: string; value: string | number }) => (
<EuiFlexItem>
<EuiText size="xs">
<h4>{label}</h4>
</EuiText>
<EuiText size="xs">{value}</EuiText>
</EuiFlexItem>
);

const QuerySummary = ({ query }: { query: SearchQueryRecord }) => {
const convertTime = (unixTime: number) => {
const date = new Date(unixTime);
const loc = date.toDateString().split(' ');
return `${loc[1]} ${loc[2]}, ${loc[3]} @ ${date.toLocaleTimeString('en-US')}`;
};
// eslint-disable-next-line @typescript-eslint/naming-convention
const { timestamp, measurements, indices, search_type, node_id, total_shards } = query;
return (
<EuiPanel>
<EuiText size="xs">
<h2>Summary</h2>
</EuiText>
<EuiHorizontalRule margin="m" />
<EuiFlexGrid columns={4}>
<EuiFlexItem>
<EuiText size="xs">
<h4>Timestamp</h4>
</EuiText>
<EuiText size="xs">{convertTime(query.timestamp)}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Latency</h4>
</EuiText>
<EuiText size="xs">{`${query.latency} ms`}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>CPU Usage</h4>
</EuiText>
<EuiText size="xs">{`${query.cpu} ns`}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Memory</h4>
</EuiText>
<EuiText size="xs">{`${query.memory} B`}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Indexes</h4>
</EuiText>
<EuiText size="xs">{query.indices.toString()}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Search type</h4>
</EuiText>
<EuiText size="xs">{query.search_type.replaceAll('_', ' ')}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Coordinator node ID</h4>
</EuiText>
<EuiText size="xs">{query.node_id}</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="xs">
<h4>Total shards</h4>
</EuiText>
<EuiText size="xs">{query.total_shards}</EuiText>
</EuiFlexItem>
<PanelItem label={TIMESTAMP} value={convertTime(timestamp)} />
<PanelItem label={LATENCY} value={`${measurements.latency?.number ?? 'N/A'} ms`} />
<PanelItem
label={CPU_TIME}
value={
measurements.cpu?.number !== undefined
? `${measurements.cpu.number / 1000000} ms`
: 'N/A'
}
/>
<PanelItem label={MEMORY_USAGE} value={`${measurements.memory?.number ?? 'N/A'} B`} />
<PanelItem label={INDICES} value={indices.toString()} />
<PanelItem label={SEARCH_TYPE} value={search_type.replaceAll('_', ' ')} />
<PanelItem label={NODE_ID} value={node_id} />
<PanelItem label={TOTAL_SHARDS} value={total_shards} />
</EuiFlexGrid>
</EuiPanel>
);
Expand Down
2 changes: 1 addition & 1 deletion public/pages/QueryDetails/QueryDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from '@elastic/eui';
import hash from 'object-hash';
import { useParams, useHistory, useLocation } from 'react-router-dom';
import { CoreStart } from '../../../../../src/core/public';
import { CoreStart } from 'opensearch-dashboards/public';
import QuerySummary from './Components/QuerySummary';
import { QUERY_INSIGHTS } from '../TopNQueries/TopNQueries';

Expand Down
68 changes: 41 additions & 27 deletions public/pages/QueryInsights/QueryInsights.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ import React, { useEffect, useState } from 'react';
import { EuiBasicTableColumn, EuiInMemoryTable, EuiLink, EuiSuperDatePicker } from '@elastic/eui';
import { useHistory, useLocation } from 'react-router-dom';
import hash from 'object-hash';
import { CoreStart } from '../../../../../src/core/public';
import { CoreStart } from 'opensearch-dashboards/public';
import { QUERY_INSIGHTS } from '../TopNQueries/TopNQueries';
import { SearchQueryRecord } from '../../../types/types';
import {
CPU_TIME,
INDICES,
LATENCY,
MEMORY_USAGE,
NODE_ID,
SEARCH_TYPE,
TIMESTAMP,
TOTAL_SHARDS,
} from '../../../common/constants';

const TIMESTAMP_FIELD = 'timestamp';
const LATENCY_FIELD = 'latency';
const CPU_FIELD = 'cpu';
const MEMORY_FIELD = 'memory';
const MEASUREMENTS_FIELD = 'measurements';
const INDICES_FIELD = 'indices';
const SEARCH_TYPE_FIELD = 'search_type';
const NODE_ID_FIELD = 'node_id';
Expand All @@ -29,7 +38,7 @@ const QueryInsights = ({
currEnd,
core,
}: {
queries: any[];
queries: SearchQueryRecord[];
loading: boolean;
onTimeChange: any;

Check warning on line 43 in public/pages/QueryInsights/QueryInsights.tsx

View workflow job for this annotation

GitHub Actions / Run lint

Unexpected any. Specify a different type
recentlyUsedRanges: any[];

Check warning on line 44 in public/pages/QueryInsights/QueryInsights.tsx

View workflow job for this annotation

GitHub Actions / Run lint

Unexpected any. Specify a different type
Expand Down Expand Up @@ -63,7 +72,7 @@ const QueryInsights = ({
const cols: Array<EuiBasicTableColumn<any>> = [
{
// Make into flyout instead?
name: 'Timestamp',
name: TIMESTAMP,
render: (query: any) => {
return (
<span>
Expand All @@ -77,51 +86,58 @@ const QueryInsights = ({
truncateText: true,
},
{
field: LATENCY_FIELD,
name: 'Latency',
render: (latency: number) =>
typeof latency !== 'undefined' ? `${latency} ms` : `${METRIC_DEFAULT_MSG}`,
field: MEASUREMENTS_FIELD,
name: LATENCY,
render: (measurements: any) => {
const latencyValue = measurements?.latency?.number;
return latencyValue !== undefined ? `${latencyValue} ms` : METRIC_DEFAULT_MSG;
},
sortable: true,
truncateText: true,
},
{
field: CPU_FIELD,
name: 'CPU usage',
render: (cpu: number) => (typeof cpu !== 'undefined' ? `${cpu} ns` : `${METRIC_DEFAULT_MSG}`),
field: MEASUREMENTS_FIELD,
name: CPU_TIME,
render: (measurements: { cpu?: { number?: number } }) => {
const cpuValue = measurements?.cpu?.number;
return cpuValue !== undefined ? `${cpuValue / 1000000} ms` : METRIC_DEFAULT_MSG;
},
sortable: true,
truncateText: true,
},
{
field: MEMORY_FIELD,
name: 'Memory',
render: (memory: number) =>
typeof memory !== 'undefined' ? `${memory} B` : `${METRIC_DEFAULT_MSG}`,
field: MEASUREMENTS_FIELD,
name: MEMORY_USAGE,
render: (measurements: { memory?: { number?: number } }) => {
const memoryValue = measurements?.memory?.number;
return memoryValue !== undefined ? `${memoryValue} B` : METRIC_DEFAULT_MSG;
},
sortable: true,
truncateText: true,
},
{
field: INDICES_FIELD,
name: 'Indices',
name: INDICES,
render: (indices: string[]) => Array.from(new Set(indices.flat())).join(', '),
sortable: true,
truncateText: true,
},
{
field: SEARCH_TYPE_FIELD,
name: 'Search type',
name: SEARCH_TYPE,
render: (searchType: string) => searchType.replaceAll('_', ' '),
sortable: true,
truncateText: true,
},
{
field: NODE_ID_FIELD,
name: 'Coordinator node ID',
name: NODE_ID,
sortable: true,
truncateText: true,
},
{
field: TOTAL_SHARDS_FIELD,
name: 'Total shards',
name: TOTAL_SHARDS,
sortable: true,
truncateText: true,
},
Expand Down Expand Up @@ -158,7 +174,7 @@ const QueryInsights = ({
{
type: 'field_value_selection',
field: INDICES_FIELD,
name: 'Indices',
name: INDICES,
multiSelect: true,
options: filterDuplicates(
queries.map((query) => {
Expand All @@ -174,7 +190,7 @@ const QueryInsights = ({
{
type: 'field_value_selection',
field: SEARCH_TYPE_FIELD,
name: 'Search type',
name: SEARCH_TYPE,
multiSelect: false,
options: filterDuplicates(
queries.map((query) => ({
Expand All @@ -187,7 +203,7 @@ const QueryInsights = ({
{
type: 'field_value_selection',
field: NODE_ID_FIELD,
name: 'Coordinator node ID',
name: NODE_ID,
multiSelect: true,
options: filterDuplicates(
queries.map((query) => ({
Expand All @@ -212,9 +228,7 @@ const QueryInsights = ({
executeQueryOptions={{
defaultFields: [
TIMESTAMP_FIELD,
LATENCY_FIELD,
CPU_FIELD,
MEMORY_FIELD,
MEASUREMENTS_FIELD,
INDICES_FIELD,
SEARCH_TYPE_FIELD,
NODE_ID_FIELD,
Expand Down
11 changes: 8 additions & 3 deletions public/pages/TopNQueries/TopNQueries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CoreStart } from 'opensearch-dashboards/public';
import QueryInsights from '../QueryInsights/QueryInsights';
import Configuration from '../Configuration/Configuration';
import QueryDetails from '../QueryDetails/QueryDetails';
import { SearchQueryRecord } from '../../../types/types';

export const QUERY_INSIGHTS = '/queryInsights';
export const CONFIGURATION = '/configuration';
Expand Down Expand Up @@ -66,7 +67,7 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
}
};

const [queries, setQueries] = useState<any[]>([]);
const [queries, setQueries] = useState<SearchQueryRecord[]>([]);

const tabs: Array<{ id: string; name: string; route: string }> = [
{
Expand Down Expand Up @@ -114,7 +115,11 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
};
const fetchMetric = async (endpoint: string) => {
try {
const response = await core.http.get(endpoint, params);
// TODO: #13 refactor the interface definitions for requests and responses
const response: { response: { top_queries: SearchQueryRecord[] } } = await core.http.get(
endpoint,
params
);
return {
response: {
top_queries: Array.isArray(response?.response?.top_queries)
Expand Down Expand Up @@ -142,7 +147,7 @@ const TopNQueries = ({ core }: { core: CoreStart }) => {
...respCpu.response.top_queries,
...respMemory.response.top_queries,
];
const noDuplicates = Array.from(
const noDuplicates: SearchQueryRecord[] = Array.from(
new Set(newQueries.map((item) => JSON.stringify(item)))
).map((item) => JSON.parse(item));
setQueries(noDuplicates);
Expand Down
Loading

0 comments on commit dcda4b8

Please sign in to comment.