Skip to content

Commit

Permalink
Merge branch 'main' into optimize_management_overview
Browse files Browse the repository at this point in the history
  • Loading branch information
ashwin-pc authored Aug 31, 2023
2 parents e674738 + 89013da commit bdac65c
Show file tree
Hide file tree
Showing 57 changed files with 3,027 additions and 297 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"dependencies": {
"@aws-crypto/client-node": "^3.1.1",
"@elastic/datemath": "5.0.3",
"@elastic/eui": "npm:@opensearch-project/[email protected]alpha.2",
"@elastic/eui": "npm:@opensearch-project/[email protected]beta.2",
"@elastic/good": "^9.0.1-kibana3",
"@elastic/numeral": "^2.5.0",
"@elastic/request-crypto": "2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/osd-ui-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"enzyme-adapter-react-16": "^1.9.1"
},
"devDependencies": {
"@elastic/eui": "npm:@opensearch-project/[email protected]alpha.2",
"@elastic/eui": "npm:@opensearch-project/[email protected]beta.2",
"@osd/babel-preset": "1.0.0",
"@osd/optimizer": "1.0.0",
"comment-stripper": "^0.0.4",
Expand Down
3 changes: 2 additions & 1 deletion packages/osd-ui-shared-deps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
},
"dependencies": {
"@elastic/charts": "31.1.0",
"@elastic/eui": "npm:@opensearch-project/[email protected]alpha.2",
"@elastic/eui": "npm:@opensearch-project/[email protected]beta.2",
"@elastic/numeral": "^2.5.0",
"@opensearch/datemath": "5.0.3",
"@osd/i18n": "1.0.0",
"@osd/monaco": "1.0.0",
"abortcontroller-polyfill": "^1.4.0",
Expand Down
3 changes: 0 additions & 3 deletions src/core/public/styles/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
@import "@elastic/charts/dist/theme";
@import "@elastic/eui/src/themes/charts/theme";

// Grab some nav-specific EUI vars
@import "@elastic/eui/src/components/collapsible_nav/variables";

// Application Layout
$euiCollapsibleNavWidth: $euiSize * 20;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.dscHistogram__header--partial {
font-weight: $euiFontWeightRegular;
min-width: $euiSize * 12;
}

// Temporary override to inlined styles provided by ElasticCharts theming
// Will be unnecessary when we migrate the histogram to a different rendering library:
// https: //github.com/opensearch-project/OpenSearch-Dashboards/issues/4643
.dscHistogram .echChartBackground {
background-color: inherit !important;
}
16 changes: 12 additions & 4 deletions src/plugins/discover/public/application/components/chart/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

import './_histogram.scss';

import React, { useCallback } from 'react';
import moment from 'moment';
import dateMath from '@elastic/datemath';
Expand All @@ -15,6 +17,8 @@ import { TimechartHeader, TimechartHeaderBucketInterval } from './timechart_head
import { DiscoverHistogram } from './histogram/histogram';
import { DiscoverServices } from '../../../build_services';
import { Chart } from './utils';
import { useDiscoverContext } from '../../view_components/context';
import { setInterval, useDispatch, useSelector } from '../../utils/state_management';

interface DiscoverChartProps {
bucketInterval: TimechartHeaderBucketInterval;
Expand All @@ -39,14 +43,18 @@ export const DiscoverChart = ({
services,
showResetButton = false,
}: DiscoverChartProps) => {
const { refetch$ } = useDiscoverContext();
const { from, to } = data.query.timefilter.timefilter.getTime();
const timeRange = {
from: dateMath.parse(from)?.format('YYYY-MM-DDTHH:mm:ss.SSSZ') || '',
to: dateMath.parse(to, { roundUp: true })?.format('YYYY-MM-DDTHH:mm:ss.SSSZ') || '',
};

const onChangeInterval = () => {};

const { interval } = useSelector((state) => state.discover);
const dispatch = useDispatch();
const onChangeInterval = (newInterval: string) => {
dispatch(setInterval(newInterval));
refetch$.next();
};
const timefilterUpdateHandler = useCallback(
(ranges: { from: number; to: number }) => {
data.query.timefilter.timefilter.setTime({
Expand Down Expand Up @@ -75,7 +83,7 @@ export const DiscoverChart = ({
timeRange={timeRange}
options={search.aggs.intervalOptions}
onChangeInterval={onChangeInterval}
stateInterval={'auto'}
stateInterval={interval || ''}
/>
</EuiFlexItem>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export const toolbarVisibility = {
allowReorder: true,
},
showStyleSelector: false,
showFullScreenSelector: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import { DocViewInspectButton } from './data_grid_table_docview_inspect_button';
import { DataGridFlyout } from './data_grid_table_flyout';
import { DiscoverGridContextProvider } from './data_grid_table_context';
import { toolbarVisibility } from './constants';
import { DocViewFilterFn } from '../../doc_views/doc_views_types';
import { DocViewFilterFn, OpenSearchSearchHit } from '../../doc_views/doc_views_types';
import { DiscoverServices } from '../../../build_services';
import { OpenSearchSearchHit } from '../../doc_views/doc_views_types';
import { usePagination } from '../utils/use_pagination';
import { SortOrder } from '../../../saved_searches/types';
import { buildColumns } from '../../utils/columns';

export interface DataGridTableProps {
columns: string[];
Expand All @@ -31,6 +31,7 @@ export interface DataGridTableProps {
displayTimeColumn: boolean;
services: DiscoverServices;
isToolbarVisible?: boolean;
isContextView?: boolean;
}

export const DataGridTable = ({
Expand All @@ -45,19 +46,31 @@ export const DataGridTable = ({
rows,
displayTimeColumn,
isToolbarVisible = true,
isContextView = false,
}: DataGridTableProps) => {
const [inspectedHit, setInspectedHit] = useState<OpenSearchSearchHit | undefined>();
const rowCount = useMemo(() => (rows ? rows.length : 0), [rows]);
const pagination = usePagination(rowCount);

let adjustedColumns = buildColumns(columns);
// handle case where the user removes selected filed and leaves only time column
if (
adjustedColumns.length === 1 &&
indexPattern &&
adjustedColumns[0] === indexPattern.timeFieldName
) {
adjustedColumns = [...adjustedColumns, '_source'];
}

const includeSourceInColumns = adjustedColumns.includes('_source');
const sortingColumns = useMemo(() => sort.map(([id, direction]) => ({ id, direction })), [sort]);
const rowHeightsOptions = useMemo(
() => ({
defaultHeight: {
lineCount: columns.includes('_source') ? 3 : 1,
lineCount: adjustedColumns.includes('_source') ? 3 : 1,
},
}),
[columns]
[adjustedColumns]
);

const onColumnSort = useCallback(
Expand All @@ -73,18 +86,29 @@ export const DataGridTable = ({
]);

const dataGridTableColumns = useMemo(
() => buildDataGridColumns(columns, indexPattern, displayTimeColumn),
[columns, indexPattern, displayTimeColumn]
() =>
buildDataGridColumns(
adjustedColumns,
indexPattern,
displayTimeColumn,
includeSourceInColumns,
isContextView
),
[adjustedColumns, indexPattern, displayTimeColumn, includeSourceInColumns, isContextView]
);

const dataGridTableColumnsVisibility = useMemo(
() => ({
visibleColumns: computeVisibleColumns(columns, indexPattern, displayTimeColumn) as string[],
visibleColumns: computeVisibleColumns(
adjustedColumns,
indexPattern,
displayTimeColumn
) as string[],
setVisibleColumns: (cols: string[]) => {
onSetColumns(cols);
},
}),
[columns, indexPattern, displayTimeColumn, onSetColumns]
[adjustedColumns, indexPattern, displayTimeColumn, onSetColumns]
);

const sorting: EuiDataGridSorting = useMemo(
Expand Down Expand Up @@ -152,7 +176,7 @@ export const DataGridTable = ({
<DataGridFlyout
indexPattern={indexPattern}
hit={inspectedHit}
columns={columns}
columns={adjustedColumns}
onRemoveColumn={onRemoveColumn}
onAddColumn={onAddColumn}
onFilter={onFilter}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,52 @@ import { getCellActions } from './data_grid_table_cell_actions';
export function buildDataGridColumns(
columnNames: string[],
idxPattern: IndexPattern,
displayTimeColumn: boolean
displayTimeColumn: boolean,
includeSourceInColumns: boolean,
isContextView: boolean
) {
const timeFieldName = idxPattern.timeFieldName;
let columnsToUse = columnNames;

if (displayTimeColumn && idxPattern.timeFieldName && !columnNames.includes(timeFieldName)) {
columnsToUse = [idxPattern.timeFieldName, ...columnNames];
if (displayTimeColumn && timeFieldName && !columnNames.includes(timeFieldName)) {
columnsToUse = [timeFieldName, ...columnNames];
}

return columnsToUse.map((colName) => generateDataGridTableColumn(colName, idxPattern));
return columnsToUse.map((colName) =>
generateDataGridTableColumn(colName, idxPattern, includeSourceInColumns, isContextView)
);
}

export function generateDataGridTableColumn(colName: string, idxPattern: IndexPattern) {
export function generateDataGridTableColumn(
colName: string,
idxPattern: IndexPattern,
includeSourceInColumns: boolean,
isContextView: boolean
) {
const timeLabel = i18n.translate('discover.timeLabel', {
defaultMessage: 'Time',
});
const idxPatternField = idxPattern.getFieldByName(colName);
const shouldHide = colName === '_source' || colName === idxPattern.timeFieldName;
const dataGridCol: EuiDataGridColumn = {
id: colName,
schema: idxPatternField?.type,
isSortable: idxPatternField?.sortable,
display: idxPatternField?.displayName,
actions: {
showHide: true,
showMoveLeft: false,
showMoveRight: false,
},
actions: isContextView
? false
: {
showHide: shouldHide
? false
: {
label: i18n.translate('discover.removeColumn.label', {
defaultMessage: 'Remove column',
}),
iconType: 'cross',
},
showMoveLeft: !includeSourceInColumns,
showMoveRight: !includeSourceInColumns,
},
cellActions: idxPatternField ? getCellActions(idxPatternField) : [],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { mount, shallow } from 'enzyme';
import { DocViewer } from './doc_viewer';
import { findTestSubject } from 'test_utils/helpers';
import { getDocViewsRegistry } from '../../../opensearch_dashboards_services';
import { DocViewRenderProps } from '../../doc_views/doc_views_types';
import { DocViewRenderProps } from '../../../doc_views/doc_views_types';

jest.mock('../../../opensearch_dashboards_services', () => {
let registry: any[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { DocViewRenderTab } from './doc_viewer_render_tab';
import { DocViewRenderProps } from '../../doc_views/doc_views_types';
import { DocViewRenderProps } from '../../../doc_views/doc_views_types';

test('Mounting and unmounting DocViewerRenderTab', () => {
const unmountFn = jest.fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/

import React, { useRef, useEffect } from 'react';
import { DocViewRenderFn, DocViewRenderProps } from '../../doc_views/doc_views_types';
import { DocViewRenderFn, DocViewRenderProps } from '../../../doc_views/doc_views_types';

interface Props {
render: DocViewRenderFn;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import { DocViewerLinks } from './doc_viewer_links';
import { getDocViewsLinksRegistry } from '../../../opensearch_dashboards_services';
import { DocViewLinkRenderProps } from '../../doc_views_links/doc_views_links_types';
import { DocViewLinkRenderProps } from '../doc_views/doc_views_links/doc_views_links_types';

jest.mock('../../../opensearch_dashboards_services', () => {
let registry: any[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Discover Context App Implementation Notes

## Principles
**Single Source of Truth**: A good user experience depends on the UI displaying consistent information across the whole page. To achieve this, there should always be a single source of truth for the application's state. In the updated application, this is managed via the useContextState and useQueryActions hooks, which manage the application state and actions respectively.

**Unidirectional Data Flow**: While a single state promotes rendering consistency, it does little to make the state changes easier to reason about. To avoid having state mutations scattered all over the code, this app implements a unidirectional data flow architecture. That means that the state is treated as immutable throughout the application except for actions, which may modify it to cause re-render and updates.

**Unit-Testability**: Creating unit tests for large parts of the UI code is made easy by expressing as much of the logic as possible as side-effect-free functions. The only place where side-effects are allowed are actions.

**Loose Coupling**: An attempt was made to couple the parts that make up this app as loosely as possible. This means using pure functions whenever possible and isolating the components diligently. It does not access the OpenSearch Dashboards AppState directly but communicates only via its properties.

## Concepts
To adhere to the principles mentioned above, this app borrows some concepts from the redux architecture that forms a circular unidirectional data flow.

**State**: The `contextAppState` and `contextQueryState` are the single sources of truth and may only be modified by actions.

**Action**: Actions are functions that are called in response to user or system actions and may modify the state they are bound to via their closure. For example, the `setContextAppState` and `fetchSurroundingRows` functions in the `useContextState` and `useQueryActions` hooks, respectively.

## Implementation
The updated application leverages React hooks to manage state and actions. The useContextState hook manages the application state and provides functions to update the state, while the useQueryActions hook manages the fetching of documents and provides functions to fetch the anchor document, surrounding documents, and all documents.

The `useContextState` hook uses the useState and useEffect hooks to manage the application state and side effects. The `contextAppState` is the application state, and the `setContextAppState` function is used to update the state. The useEffect hook is used to reset the `contextQueryState` and to fetch the surrounding documents based on the `contextAppState`.

The `useQueryActions` hook uses the useState, useMemo, and useCallback hooks to manage the query state and actions. The `contextQueryState` is the query state, and various functions are provided to update the state and fetch documents. The useMemo hook is used to derive the rows from the contextQueryState, and the useCallback hook is used to create memoized versions of the functions that update the state and fetch documents.

The `useQueryActions` hook provides several functions for fetching documents:

**fetchAnchorRow**: Fetches the anchor document.

**fetchSurroundingRows**: Fetches the surrounding documents (predecessors or successors) of the anchor document.

**fetchContextRows**: Fetches both the predecessors and successors of the anchor document.

**fetchAllRows**: Fetches the anchor document and then fetches the surrounding documents.
**resetContextQueryState**: Resets the contextQueryState to its initial state.

These functions update the `contextQueryState` to reflect the loading status and the fetched documents.


## Directory Structure

**components/action_bar**: Defines the `ActionBar` component.

**api/anchor.ts**: Exports `fetchAnchor()` function that creates and executes the query for the anchor document. It also exports `updateSearchSource()` function which updates the search source with specified parameters.

**api/context.ts**: Exports `fetchSurroundingDocs()` function that fetches the surrounding documents (either successors or predecessors) of a specified anchor document. It also exports `createSearchSource()` function that creates a search source with specified index pattern and filters.

**api/utils**: Exports various functions used to create and transform
queries.

**utils/context_state**: Exports functions for fetching surrounding documents, creating a search source, and managing application and global states. Additionally, several helper functions are exported for comparing filters and states, retrieving filters from a state, and creating the initial app state. The module also defines constants for the global and app state URL keys.

**utils/use_query_actions**: Defines a React hook to manage and fetch data related to OpenSearch documents. The hook maintains a local state, contextQueryState, to track the status of fetching operations and the fetched documents. It provides several functions: `fetchAnchorRow()` to fetch the anchor document, `fetchSurroundingRows()` to fetch surrounding documents, `fetchContextRows()` to fetch both predecessors and successors, and `fetchAllRows()` to fetch the anchor and all surrounding documents. Additionally, it provides a `resetContextQueryState()` function to reset the local state to its initial value. Each fetch operation updates the contextQueryState and, in case of an error, displays a toast notification with a failure message.

**utils/use_context_query**: Defines a React hook that manages the application state and synchronization with the URL and OpenSearch Dashboards services. The `startSync` and `stopSync` functions are used to start and stop the synchronization of the application state with the URL. The `setContextAppState` function is used to update the application state and immediately reflect the changes in the URL. The hook returns the current `contextAppState` and the `setContextAppState` function, which can be used by the components that consume this hook.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Prefix all styles with "cxt" to avoid conflicts.
// Examples
// cxtChart
// cxtChart__legend
// cxtChart__legend--small
// cxtChart__legend-isLoading

@import "components/action_bar/index";
Loading

0 comments on commit bdac65c

Please sign in to comment.