diff --git a/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx b/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx index 02df3aaa814c..89d2198ada8d 100644 --- a/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx +++ b/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx @@ -16,6 +16,7 @@ import { DocViewFilterFn } 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 { SurroundingDocumentsFlyout } from '../context/surrounding_documents_flyout'; export interface DataGridTableProps { columns: string[]; @@ -23,12 +24,13 @@ export interface DataGridTableProps { onAddColumn: (column: string) => void; onFilter: DocViewFilterFn; onRemoveColumn: (column: string) => void; - onSort: (sort: string[][]) => void; + onSort: (sort: Array<[string, string]>) => void; rows: OpenSearchSearchHit[]; onSetColumns: (columns: string[]) => void; sort: Array<[string, string]>; displayTimeColumn: boolean; services: DiscoverServices; + isToolbarVisible?: boolean; } export const DataGridTable = ({ @@ -43,6 +45,7 @@ export const DataGridTable = ({ rows, displayTimeColumn, services, + isToolbarVisible = true, }: DataGridTableProps) => { const [expandedHit, setExpandedHit] = useState(); const rowCount = useMemo(() => (rows ? rows.length : 0), [rows]); @@ -70,8 +73,8 @@ export const DataGridTable = ({ const dataGridTableColumnsVisibility = useMemo( () => ({ visibleColumns: computeVisibleColumns(columns, indexPattern, displayTimeColumn) as string[], - setVisibleColumns: (newColumns: string[]) => { - onSetColumns(newColumns); + setVisibleColumns: (cols: string[]) => { + onSetColumns(cols); }, }), [columns, indexPattern, displayTimeColumn, onSetColumns] @@ -116,7 +119,7 @@ export const DataGridTable = ({ renderCellValue={renderCellValue} rowCount={rowCount} sorting={sorting} - toolbarVisibility={toolbarVisibility} + toolbarVisibility={isToolbarVisible ? toolbarVisibility : false} /> diff --git a/src/plugins/discover/public/application/utils/state_management/common.test.ts b/src/plugins/discover/public/application/utils/state_management/common.test.ts new file mode 100644 index 000000000000..c1190f891648 --- /dev/null +++ b/src/plugins/discover/public/application/utils/state_management/common.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { addColumn, removeColumn, reorderColumn, setColumns } from './common'; + +describe('commonUtils', () => { + it('should handle addColumn', () => { + expect(addColumn(['column1'], { column: 'column2' })).toEqual(['column1', 'column2']); + expect(addColumn(['column1'], { column: 'column2', index: 0 })).toEqual(['column2', 'column1']); + }); + + it('should handle removeColumn', () => { + expect(removeColumn(['column1', 'column2'], 'column1')).toEqual(['column2']); + }); + + it('should handle reorderColumn', () => { + expect(reorderColumn(['column1', 'column2', 'column3'], 0, 2)).toEqual([ + 'column2', + 'column3', + 'column1', + ]); + }); + + it('should handle setColumns', () => { + expect(setColumns('timeField', ['timeField', 'column1', 'column2'])).toEqual([ + 'column1', + 'column2', + ]); + expect(setColumns(undefined, ['column1', 'column2'])).toEqual(['column1', 'column2']); + }); +}); diff --git a/src/plugins/discover/public/application/utils/state_management/common.ts b/src/plugins/discover/public/application/utils/state_management/common.ts new file mode 100644 index 000000000000..566ee6e468ff --- /dev/null +++ b/src/plugins/discover/public/application/utils/state_management/common.ts @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const addColumn = (columns: string[], action: { column: string; index?: number }) => { + const { column, index } = action; + const newColumns = [...(columns || [])]; + if (index !== undefined) newColumns.splice(index, 0, column); + else newColumns.push(column); + return newColumns; +}; + +export const removeColumn = (columns: string[], actionColumn: string) => { + return (columns || []).filter((column) => column !== actionColumn); +}; + +export const reorderColumn = (columns: string[], source: number, destination: number) => { + const newColumns = [...(columns || [])]; + const [removed] = newColumns.splice(source, 1); + newColumns.splice(destination, 0, removed); + return newColumns; +}; + +export const setColumns = (timeField: string | undefined, columns: string[]) => { + const newColumns = timeField && timeField === columns[0] ? columns.slice(1) : columns; + return newColumns; +}; diff --git a/src/plugins/discover/public/application/utils/state_management/discover_slice.test.tsx b/src/plugins/discover/public/application/utils/state_management/discover_slice.test.tsx index 71e848bac15e..7934db6483cf 100644 --- a/src/plugins/discover/public/application/utils/state_management/discover_slice.test.tsx +++ b/src/plugins/discover/public/application/utils/state_management/discover_slice.test.tsx @@ -15,52 +15,70 @@ describe('discoverSlice', () => { }; }); - it('should handle setState', () => { + it('should handle setDiscoverState', () => { const newState = { columns: ['column1', 'column2'], sort: [['field1', 'asc']], }; - const action = { type: 'discover/setState', payload: newState }; + const action = { type: 'discover/setDiscoverState', payload: newState }; const result = discoverSlice.reducer(initialState, action); expect(result).toEqual(newState); }); - it('should handle addColumn', () => { - const action1 = { type: 'discover/addColumn', payload: { column: 'column1' } }; + it('should handle addDiscoverColumn', () => { + const action1 = { type: 'discover/addDiscoverColumn', payload: { column: 'column1' } }; const result1 = discoverSlice.reducer(initialState, action1); expect(result1.columns).toEqual(['column1']); - - const action2 = { type: 'discover/addColumn', payload: { column: 'column2', index: 0 } }; - const result2 = discoverSlice.reducer(result1, action2); - expect(result2.columns).toEqual(['column2', 'column1']); }); - it('should handle removeColumn', () => { + it('should handle removeDiscoverColumn', () => { initialState = { columns: ['column1', 'column2'], - sort: [], + sort: [['column1', 'asc']], }; - const action = { type: 'discover/removeColumn', payload: 'column1' }; + const action = { type: 'discover/removeDiscoverColumn', payload: 'column1' }; const result = discoverSlice.reducer(initialState, action); expect(result.columns).toEqual(['column2']); + expect(result.sort).toEqual([]); }); - it('should handle reorderColumn', () => { + it('should handle reorderDiscoverColumn', () => { initialState = { columns: ['column1', 'column2', 'column3'], sort: [], }; - const action = { type: 'discover/reorderColumn', payload: { source: 0, destination: 2 } }; + const action = { + type: 'discover/reorderDiscoverColumn', + payload: { source: 0, destination: 2 }, + }; const result = discoverSlice.reducer(initialState, action); expect(result.columns).toEqual(['column2', 'column3', 'column1']); }); - it('should handle updateState', () => { + it('should handle setDiscoverColumns', () => { + const action = { + type: 'discover/setDiscoverColumns', + payload: { timeField: 'timeField', columns: ['timeField', 'column1', 'column2'] }, + }; + const result = discoverSlice.reducer(initialState, action); + expect(result.columns).toEqual(['column1', 'column2']); + }); + + it('should handle setDiscoverSort', () => { + const action = { type: 'discover/setDiscoverSort', payload: [['field1', 'asc']] }; + const result = discoverSlice.reducer(initialState, action); + expect(result.sort).toEqual([['field1', 'asc']]); + }); + + it('should handle updateDiscoverState', () => { initialState = { columns: ['column1', 'column2'], sort: [['field1', 'asc']], }; - const action = { type: 'discover/updateState', payload: { sort: [['field2', 'desc']] } }; + const action = { + type: 'discover/updateDiscoverState', + payload: { sort: [['field2', 'desc']] }, + }; const result = discoverSlice.reducer(initialState, action); expect(result.sort).toEqual([['field2', 'desc']]); }); diff --git a/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx b/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx index e8d384e66174..af46d735e46a 100644 --- a/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx +++ b/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx @@ -6,8 +6,8 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { Filter, Query } from '../../../../../data/public'; import { DiscoverServices } from '../../../build_services'; -import { RootState } from '../../../../../data_explorer/public'; import { buildColumns } from '../columns'; +import { addColumn, removeColumn, reorderColumn, setColumns } from './common'; export interface DiscoverState { /** @@ -36,16 +36,14 @@ export interface DiscoverState { savedQuery?: string; } -export interface DiscoverRootState extends RootState { - discover: DiscoverState; -} - const initialState: DiscoverState = { columns: ['_source'], sort: [], }; -export const getPreloadedState = async ({ data }: DiscoverServices): Promise => { +export const getPreloadedDiscoverState = async ({ + data, +}: DiscoverServices): Promise => { return { ...initialState, }; @@ -55,34 +53,51 @@ export const discoverSlice = createSlice({ name: 'discover', initialState, reducers: { - setState(state, action: PayloadAction) { + setDiscoverState(state, action: PayloadAction) { return action.payload; }, - addColumn(state, action: PayloadAction<{ column: string; index?: number }>) { - const { column, index } = action.payload; - const columns = [...(state.columns || [])]; - if (index !== undefined) columns.splice(index, 0, column); - else columns.push(column); + addDiscoverColumn(state, action: PayloadAction<{ column: string; index?: number }>) { + const columns = addColumn(state.columns || [], action.payload); return { ...state, columns: buildColumns(columns) }; }, - removeColumn(state, action: PayloadAction) { - const columns = (state.columns || []).filter((column) => column !== action.payload); + removeDiscoverColumn(state, action: PayloadAction) { + const columns = removeColumn(state.columns, action.payload); + const sort = + state.sort && state.sort.length ? state.sort.filter((s) => s[0] !== action.payload) : []; return { ...state, columns: buildColumns(columns), + sort, }; }, - reorderColumn(state, action: PayloadAction<{ source: number; destination: number }>) { - const { source, destination } = action.payload; - const columns = [...(state.columns || [])]; - const [removed] = columns.splice(source, 1); - columns.splice(destination, 0, removed); + reorderDiscoverColumn(state, action: PayloadAction<{ source: number; destination: number }>) { + const columns = reorderColumn( + state.columns, + action.payload.source, + action.payload.destination + ); return { ...state, columns, }; }, - updateState(state, action: PayloadAction>) { + setDiscoverColumns( + state, + action: PayloadAction<{ timeField: string | undefined; columns: string[] }> + ) { + const columns = setColumns(action.payload.timeField, action.payload.columns); + return { + ...state, + columns, + }; + }, + setDiscoverSort(state, action: PayloadAction>) { + return { + ...state, + sort: action.payload, + }; + }, + updateDiscoverState(state, action: PayloadAction>) { return { ...state, ...action.payload, @@ -93,10 +108,12 @@ export const discoverSlice = createSlice({ // Exposing the state functions as generics export const { - addColumn, - removeColumn, - reorderColumn, - setState, - updateState, + addDiscoverColumn, + removeDiscoverColumn, + reorderDiscoverColumn, + setDiscoverColumns, + setDiscoverSort, + setDiscoverState, + updateDiscoverState, } = discoverSlice.actions; export const { reducer } = discoverSlice; diff --git a/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx b/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx index e92fe96b7d3d..22316cf7f073 100644 --- a/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/discover_table.tsx @@ -3,14 +3,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { History } from 'history'; import { DiscoverViewServices } from '../../../build_services'; import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; import { DataGridTable } from '../../components/data_grid/data_grid_table'; import { useDiscoverContext } from '../context'; -import { addColumn, removeColumn, useDispatch, useSelector } from '../../utils/state_management'; +import { + addDiscoverColumn, + removeDiscoverColumn, + setDiscoverColumns, + setDiscoverSort, + useDispatch, + useSelector, +} from '../../utils/state_management'; import { SearchData } from '../utils/use_search'; +import { IndexPatternField, opensearchFilters } from '../../../../../data/public'; +import { DocViewFilterFn } from '../../doc_views/doc_views_types'; interface Props { history: History; @@ -18,14 +27,33 @@ interface Props { export const DiscoverTable = ({ history }: Props) => { const { services } = useOpenSearchDashboards(); + const { filterManager } = services.data.query; const { data$, indexPattern } = useDiscoverContext(); const [fetchState, setFetchState] = useState({ status: data$.getValue().status, rows: [], }); - const { columns } = useSelector((state) => state.discover); + const { columns, sort } = useSelector((state) => state.discover); const dispatch = useDispatch(); + const onAddColumn = (col: string) => dispatch(addDiscoverColumn({ column: col })); + const onRemoveColumn = (col: string) => dispatch(removeDiscoverColumn(col)); + const onSetColumns = (cols: string[]) => + dispatch(setDiscoverColumns({ timefield: indexPattern.timeFieldName, columns: cols })); + const onSetSort = (s: Array<[string, string]>) => dispatch(setDiscoverSort(s)); + const onAddFilter = useCallback( + (field: IndexPatternField, values: string, operation: '+' | '-') => { + const newFilters = opensearchFilters.generateFilters( + filterManager, + field, + values, + operation, + indexPattern.id + ); + return filterManager.addFilters(newFilters); + }, + [filterManager, indexPattern] + ); const { rows } = fetchState || {}; @@ -54,18 +82,12 @@ export const DiscoverTable = ({ history }: Props) => { - dispatch( - addColumn({ - column, - }) - ) - } - onFilter={() => {}} - onRemoveColumn={(column) => dispatch(removeColumn(column))} - onSetColumns={() => {}} - onSort={() => {}} - sort={[]} + onAddColumn={onAddColumn} + onFilter={onAddFilter as DocViewFilterFn} + onRemoveColumn={onRemoveColumn} + onSetColumns={onSetColumns} + onSort={onSetSort} + sort={sort} rows={rows} displayTimeColumn={true} services={services} diff --git a/src/plugins/discover/public/application/view_components/panel/index.tsx b/src/plugins/discover/public/application/view_components/panel/index.tsx index a9e29a34e435..998585d55ce9 100644 --- a/src/plugins/discover/public/application/view_components/panel/index.tsx +++ b/src/plugins/discover/public/application/view_components/panel/index.tsx @@ -6,9 +6,9 @@ import React, { useEffect, useState } from 'react'; import { ViewProps } from '../../../../../data_explorer/public'; import { - addColumn, - removeColumn, - reorderColumn, + addDiscoverColumn, + removeDiscoverColumn, + reorderDiscoverColumn, useDispatch, useSelector, } from '../../utils/state_management'; @@ -42,18 +42,18 @@ export default function DiscoverPanel(props: ViewProps) { hits={fetchState.rows || []} onAddField={(fieldName, index) => { dispatch( - addColumn({ + addDiscoverColumn({ column: fieldName, index, }) ); }} onRemoveField={(fieldName) => { - dispatch(removeColumn(fieldName)); + dispatch(removeDiscoverColumn(fieldName)); }} onReorderFields={(source, destination) => { dispatch( - reorderColumn({ + reorderDiscoverColumn({ source, destination, }) diff --git a/src/plugins/discover/public/plugin.ts b/src/plugins/discover/public/plugin.ts index 8a581a3d246f..2713398327e6 100644 --- a/src/plugins/discover/public/plugin.ts +++ b/src/plugins/discover/public/plugin.ts @@ -65,7 +65,7 @@ import { registerFeature } from './register_feature'; import { DiscoverState, discoverSlice, - getPreloadedState, + getPreloadedDiscoverState, } from './application/utils/state_management/discover_slice'; import { migrateUrlState } from './migrate_state'; @@ -328,7 +328,7 @@ export class DiscoverPlugin defaults: async () => { this.initializeServices?.(); const services = getServices(); - return await getPreloadedState(services); + return await getPreloadedDiscoverState(services); }, slice: discoverSlice, },