Skip to content

Commit

Permalink
[Data Explorer][Discover 2.0] Implement column actions (#4756)
Browse files Browse the repository at this point in the history
* [Data Explorer][Discover 2.0] Emplement column actions

Signed-off-by: ananzh <[email protected]>

* Update discover_slice.tsx

Signed-off-by: Ashwin P Chandran <[email protected]>

---------

Signed-off-by: ananzh <[email protected]>
Signed-off-by: Ashwin P Chandran <[email protected]>
Co-authored-by: Ashwin P Chandran <[email protected]>
Co-authored-by: Ashwin P Chandran <[email protected]>
  • Loading branch information
3 people authored Aug 17, 2023
1 parent 5c26614 commit 9a46a7c
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,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 = ({
Expand All @@ -43,6 +44,7 @@ export const DataGridTable = ({
rows,
displayTimeColumn,
services,
isToolbarVisible = true,
}: DataGridTableProps) => {
const [expandedHit, setExpandedHit] = useState<OpenSearchSearchHit | undefined>();
const rowCount = useMemo(() => (rows ? rows.length : 0), [rows]);
Expand Down Expand Up @@ -70,8 +72,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]
Expand Down Expand Up @@ -116,7 +118,7 @@ export const DataGridTable = ({
renderCellValue={renderCellValue}
rowCount={rowCount}
sorting={sorting}
toolbarVisibility={toolbarVisibility}
toolbarVisibility={isToolbarVisible ? toolbarVisibility : false}
/>
</EuiPanel>
</EuiPanel>
Expand Down
Original file line number Diff line number Diff line change
@@ -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']);
});
});
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,38 +29,56 @@ describe('discoverSlice', () => {
const action1 = { type: 'discover/addColumn', 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', () => {
initialState = {
columns: ['column1', 'column2'],
sort: [],
sort: [['column1', 'asc']],
};
const action = { type: 'discover/removeColumn', payload: 'column1' };
const result = discoverSlice.reducer(initialState, action);
expect(result.columns).toEqual(['column2']);
expect(result.sort).toEqual([]);
});

it('should handle reorderColumn', () => {
initialState = {
columns: ['column1', 'column2', 'column3'],
sort: [],
};
const action = { type: 'discover/reorderColumn', payload: { source: 0, destination: 2 } };
const action = {
type: 'discover/reorderColumn',
payload: { source: 0, destination: 2 },
};
const result = discoverSlice.reducer(initialState, action);
expect(result.columns).toEqual(['column2', 'column3', 'column1']);
});

it('should handle setColumns', () => {
const action = {
type: 'discover/setColumns',
payload: { timeField: 'timeField', columns: ['timeField', 'column1', 'column2'] },
};
const result = discoverSlice.reducer(initialState, action);
expect(result.columns).toEqual(['column1', 'column2']);
});

it('should handle setSort', () => {
const action = { type: 'discover/setSort', payload: [['field1', 'asc']] };
const result = discoverSlice.reducer(initialState, action);
expect(result.sort).toEqual([['field1', 'asc']]);
});

it('should handle updateState', () => {
initialState = {
columns: ['column1', 'column2'],
sort: [['field1', 'asc']],
};
const action = { type: 'discover/updateState', payload: { sort: [['field2', 'desc']] } };
const action = {
type: 'discover/updateState',
payload: { sort: [['field2', 'desc']] },
};
const result = discoverSlice.reducer(initialState, action);
expect(result.sort).toEqual([['field2', 'desc']]);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Filter, Query } from '../../../../../data/public';
import { DiscoverServices } from '../../../build_services';
import { RootState, DefaultViewState } from '../../../../../data_explorer/public';
import { buildColumns } from '../columns';
import * as utils from './common';

export interface DiscoverState {
/**
Expand Down Expand Up @@ -95,31 +96,45 @@ export const discoverSlice = createSlice({
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);
return { ...state, columns: buildColumns(columns), isDirty: true };
const columns = utils.addColumn(state.columns || [], action.payload);
return { ...state, columns: buildColumns(columns) };
},
removeColumn(state, action: PayloadAction<string>) {
const columns = (state.columns || []).filter((column) => column !== action.payload);
const columns = utils.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,
isDirty: true,
};
},
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);
const columns = utils.reorderColumn(
state.columns,
action.payload.source,
action.payload.destination
);
return {
...state,
columns,
isDirty: true,
};
},
setColumns(state, action: PayloadAction<{ timeField: string | undefined; columns: string[] }>) {
const columns = utils.setColumns(action.payload.timeField, action.payload.columns);
return {
...state,
columns,
};
},
setSort(state, action: PayloadAction<Array<[string, string]>>) {
return {
...state,
sort: action.payload,
};
},
updateState(state, action: PayloadAction<Partial<DiscoverState>>) {
return {
...state,
Expand All @@ -141,6 +156,8 @@ export const {
addColumn,
removeColumn,
reorderColumn,
setColumns,
setSort,
setState,
updateState,
setSavedSearchId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,57 @@
* 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 {
addColumn,
removeColumn,
setColumns,
setSort,
useDispatch,
useSelector,
} from '../../utils/state_management';
import { ResultStatus, SearchData } from '../utils/use_search';
import { IndexPatternField, opensearchFilters } from '../../../../../data/public';
import { DocViewFilterFn } from '../../doc_views/doc_views_types';

interface Props {
history: History;
}

export const DiscoverTable = ({ history }: Props) => {
const { services } = useOpenSearchDashboards<DiscoverViewServices>();
const { filterManager } = services.data.query;
const { data$, indexPattern } = useDiscoverContext();
const [fetchState, setFetchState] = useState<SearchData>({
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(addColumn({ column: col }));
const onRemoveColumn = (col: string) => dispatch(removeColumn(col));
const onSetColumns = (cols: string[]) =>
dispatch(setColumns({ timefield: indexPattern.timeFieldName, columns: cols }));
const onSetSort = (s: Array<[string, string]>) => dispatch(setSort(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 || {};

Expand Down Expand Up @@ -55,18 +83,12 @@ export const DiscoverTable = ({ history }: Props) => {
<DataGridTable
columns={columns}
indexPattern={indexPattern}
onAddColumn={(column) =>
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}
Expand Down

0 comments on commit 9a46a7c

Please sign in to comment.