From 1ba45a7c738e912dc7671079650445a69dd73e18 Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 1 Feb 2024 19:49:08 -0800 Subject: [PATCH 1/8] [Discover] Prevent wrapping of time series cells (#5779) Signed-off-by: Miki --- .../default_discover_table/table_cell.tsx | 24 ++++++++++++++----- .../default_discover_table/table_rows.tsx | 1 + 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_cell.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_cell.tsx index 16e6a0e13716..a542e70ff646 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_cell.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_cell.tsx @@ -18,6 +18,7 @@ import { DocViewFilterFn } from '../../doc_views/doc_views_types'; export interface TableCellProps { columnId: string; + isTimeField?: boolean; onFilter: DocViewFilterFn; filterable?: boolean; fieldMapping?: any; @@ -26,16 +27,14 @@ export interface TableCellProps { export const TableCell = ({ columnId, + isTimeField, onFilter, fieldMapping, sanitizedCellValue, }: TableCellProps) => { - return ( - // eslint-disable-next-line react/no-danger - + const content = ( + <> + {/* eslint-disable-next-line react/no-danger */} + + ); + + return isTimeField ? ( + + {content} + + ) : ( + +
{content}
); }; diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx index af6d52d830b0..0885d7f9f1e7 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx @@ -108,6 +108,7 @@ export const TableRow = ({ From 1095c8aadcb0bf2645c94fb96ae1c703ce92bdc2 Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 1 Feb 2024 20:20:53 -0800 Subject: [PATCH 2/8] Vertically align the text in QueryStringInputUI with other elements on the page (#5780) Signed-off-by: Miki --- .../data/public/ui/query_string_input/_query_bar.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/data/public/ui/query_string_input/_query_bar.scss b/src/plugins/data/public/ui/query_string_input/_query_bar.scss index 096c7c0ad8bc..c9eab29d9e2d 100644 --- a/src/plugins/data/public/ui/query_string_input/_query_bar.scss +++ b/src/plugins/data/public/ui/query_string_input/_query_bar.scss @@ -33,9 +33,8 @@ // Unlike most inputs within layout control groups, the text area still needs a border. // These adjusts help it sit above the control groups shadow to line up correctly. - padding: $euiSizeS; - padding-top: $euiSizeS + 3px; - transform: translateY(-1px) translateX(-1px); + padding: ($euiSizeS + 2px) $euiSizeS $euiSizeS; + transform: translateY(-2px) translateX(-1px); &:not(:focus):not(:invalid) { @include euiYScrollWithShadows; From 2db522e7e3d9bf702c36d4daa9389ad339d7f240 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 2 Feb 2024 04:13:20 -0800 Subject: [PATCH 3/8] Use `ouiCodeFont` in Discover and reduce text size (#5783) Also: * Fix react `key` errors * vertically align source cells * Clamp the height of the cells * Make sure time-series column never grows Signed-off-by: Miki --- .../core_app/assets/legacy_dark_theme.css | 2 +- .../core_app/assets/legacy_light_theme.css | 2 +- .../data_grid/data_grid_table_cell_value.tsx | 2 +- .../default_discover_table/_doc_table.scss | 7 +++++ .../default_discover_table/_table_cell.scss | 25 +++++++++++++++- .../default_discover_table/table_header.tsx | 1 + .../default_discover_table/table_rows.tsx | 29 ++++++++++++++----- 7 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/core/server/core_app/assets/legacy_dark_theme.css b/src/core/server/core_app/assets/legacy_dark_theme.css index 4ef4c726e414..b56eeed717a1 100644 --- a/src/core/server/core_app/assets/legacy_dark_theme.css +++ b/src/core/server/core_app/assets/legacy_dark_theme.css @@ -802,7 +802,7 @@ width: 100%; max-width: 100%; margin-bottom: 20px; - font-size: 14px; + font-size: 12px; } .table thead { font-size: 12px; diff --git a/src/core/server/core_app/assets/legacy_light_theme.css b/src/core/server/core_app/assets/legacy_light_theme.css index 9f9a0dc118d1..d4f6d10e7022 100644 --- a/src/core/server/core_app/assets/legacy_light_theme.css +++ b/src/core/server/core_app/assets/legacy_light_theme.css @@ -802,7 +802,7 @@ width: 100%; max-width: 100%; margin-bottom: 20px; - font-size: 14px; + font-size: 12px; } .table thead { font-size: 12px; diff --git a/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx b/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx index 10911ab96a7e..7c4201f93127 100644 --- a/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx +++ b/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx @@ -30,7 +30,7 @@ export function fetchSourceTypeDataCell( const keys = Object.keys(formattedRow); return ( - + {keys.map((key, index) => ( diff --git a/src/plugins/discover/public/application/components/default_discover_table/_doc_table.scss b/src/plugins/discover/public/application/components/default_discover_table/_doc_table.scss index 86519fb5a46c..1e780a7e4d8a 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/_doc_table.scss +++ b/src/plugins/discover/public/application/components/default_discover_table/_doc_table.scss @@ -42,6 +42,13 @@ doc-table { .osd-table, .osdDocTable { + @include ouiCodeFont; + + // To fight intruding styles that conflict with OUI's + & > tbody > tr > td { + line-height: inherit; + } + /** * Style OpenSearch document _source in table view
key:
value
* Use alpha so this will stand out against non-white backgrounds, e.g. the highlighted diff --git a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss index 65dbcd73fba9..aefd9ebbfc05 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss +++ b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss @@ -1,4 +1,4 @@ -.osdDocTable_expandedRow { +.osdDocTable__detailsParent { border-top: none !important; } @@ -31,4 +31,27 @@ &:focus &__filterButton { opacity: 1; } + + .osdDescriptionListFieldTitle { + margin: 0 4px 0 0 !important; + } + + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors + &.eui-textNoWrap { + // To make sure the time-series column never stretches + width: 1%; + } +} + +.osdDocTableCell__source { + .truncate-by-height { + transform: translateY(-1.5px); + margin-bottom: -1.5px; + } + + dd, + dl, + dt { + font-size: inherit !important; + } } diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx index 4d714228f3bc..6715910e8346 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx @@ -64,6 +64,7 @@ export function TableHeader({ return ( + @@ -71,8 +72,14 @@ export const TableRow = ({ if (fieldInfo?.type === '_source') { return ( - - {fetchSourceTypeDataCell(indexPattern, row, columnId, false)} + +
+ {fetchSourceTypeDataCell(indexPattern, row, columnId, false)} +
); } @@ -82,6 +89,7 @@ export const TableRow = ({ if (typeof formattedValue === 'undefined') { return ( @@ -95,18 +103,23 @@ export const TableRow = ({ if (!fieldInfo?.filterable) { return ( - {/* eslint-disable-next-line react/no-danger */} - +
+ {/* eslint-disable-next-line react/no-danger */} + +
); } return ( - - + + + From 21541ee36a956ecddbb8ee13dcdbb6e1d8362b89 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 2 Feb 2024 04:15:51 -0800 Subject: [PATCH 4/8] [Discover] Display filter buttons at top right of the cell (#5784) Signed-off-by: Miki --- .../default_discover_table/_table_cell.scss | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss index aefd9ebbfc05..d700e8107301 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss +++ b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss @@ -6,9 +6,6 @@ padding: 4px 0 0 !important; } -.osdDocTableCell__filter { // TODO: make them appear at top right corner -} - /** * 1. Align icon with text in cell. * 2. Use opacity to make this element accessible to screen readers and keyboard. @@ -16,9 +13,45 @@ */ .osdDocTableCell { - white-space: pre-wrap; + position: relative; + + &__filter { + position: absolute; + display: flex; + flex-grow: 0; + + // Vertically align the button group with the first line of text + // 8px is set by .table and 2em is the line-height + top: calc(2em / 2 + 8px); + transform: translateY(-50%); + + // Stick it to the right but use the padding of the container to distance it from the edge (below) + right: 0; + + // Just to have some distance from the content behind it; larger for left so we can show a gradiant + // 8px is set by .table + padding: 8px 8px 8px 16px; + + &::before { + content: ""; + position: absolute; + display: block; + right: 0; + top: 0; + height: 100%; + width: 100%; + background-image: linear-gradient(to right, transparent 0, $ouiColorEmptyShade 16px); + z-index: 1; + } + + & > * { + // So they will appear over the background in ::before + z-index: 2; + } + } - &__filterButton { + &__filterButton, + &__filter { opacity: 0; transition: opacity $euiAnimSpeedFast; @@ -28,7 +61,9 @@ } &:hover &__filterButton, - &:focus &__filterButton { + &:focus &__filterButton, + &:hover &__filter, + &:focus &__filter { opacity: 1; } From c79c106dc54586a28b844c9bedb57dcf8bac67fd Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 2 Feb 2024 04:16:46 -0800 Subject: [PATCH 5/8] [Discover] Vertically align the details toggle button (#5785) Signed-off-by: Miki --- .../components/default_discover_table/_table_cell.scss | 2 +- .../components/default_discover_table/table_rows.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss index d700e8107301..74ff79b4976b 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss +++ b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss @@ -3,7 +3,7 @@ } .osdDocTableCell__toggleDetails { - padding: 4px 0 0 !important; + padding: 7px 0 0 4px; } /** diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx index 9092ec527683..8cc38a9c9fab 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx @@ -51,7 +51,6 @@ export const TableRow = ({ iconType={isExpanded ? 'arrowDown' : 'arrowRight'} aria-label="Next" data-test-subj="docTableExpandToggleColumn" - className="osdDocTableCell__toggleDetails" /> {columnIds.map((columnId) => { From 7f67c92b7dc23bd02051ff42bf0b6e9f76c6fb48 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 2 Feb 2024 10:35:50 -0800 Subject: [PATCH 6/8] [Discover] Fix overflow of the expanded document (#5788) * Fix vertical alignment of expand details button Fix colspan of details cells Signed-off-by: Miki * Fix overflow problem of detailed doc Signed-off-by: Miki --------- Signed-off-by: Miki --- .../components/default_discover_table/_table_cell.scss | 9 +++++++-- .../components/default_discover_table/table_rows.tsx | 8 ++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss index 74ff79b4976b..c960e87a9477 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss +++ b/src/plugins/discover/public/application/components/default_discover_table/_table_cell.scss @@ -2,8 +2,13 @@ border-top: none !important; } -.osdDocTableCell__toggleDetails { - padding: 7px 0 0 4px; +// stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors +.euiFlexItem.osdDocTable__detailsIconContainer { + margin-right: 0; +} + +.osd-table td.osdDocTableCell__toggleDetails { + padding: 5px 0 0 4px; } /** diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx index 8cc38a9c9fab..9170d97921d2 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx @@ -131,9 +131,9 @@ export const TableRow = ({ const expandedTableRow = ( - - - + + + @@ -150,7 +150,7 @@ export const TableRow = ({ - + Date: Fri, 2 Feb 2024 11:03:14 -0800 Subject: [PATCH 7/8] update feedback msg (#5787) Signed-off-by: Anan Z --- .../components/top_nav/table_feedbacks_panel.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/discover/public/application/components/top_nav/table_feedbacks_panel.tsx b/src/plugins/discover/public/application/components/top_nav/table_feedbacks_panel.tsx index 7f78c1df80e1..212f1c99ca25 100644 --- a/src/plugins/discover/public/application/components/top_nav/table_feedbacks_panel.tsx +++ b/src/plugins/discover/public/application/components/top_nav/table_feedbacks_panel.tsx @@ -31,11 +31,11 @@ export const TableFeedbacksPanel = ({ onClose, onTurnOff }: TableFeedbacksPanelP

- Event tables: Documents are now expanded through a flyout. Density, column order, and - sorting controls have been improved.{' '} + Help drive future improvements by{' '} - Provide feedbacks - + providing feedback + {' '} + about your experience.

From 0901ddc40ac9e52d5f963a2b1aaf9453f7a19986 Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Fri, 2 Feb 2024 11:04:48 -0800 Subject: [PATCH 8/8] Resolve sort, default sort and short dot (#5771) Signed-off-by: Anan Z Signed-off-by: Anan Zhuang --- .../components/data_grid/data_grid_table.tsx | 47 +++++--- .../data_grid/data_grid_table_cell_value.tsx | 7 +- .../default_discover_table.tsx | 46 ++++---- .../default_discover_table/helper.tsx | 101 ++++++++++++++++++ .../default_discover_table/table_header.tsx | 72 ++++--------- .../table_header_column.tsx | 51 +++------ .../default_discover_table/table_rows.tsx | 29 +++-- .../components/doc_views/context_app.tsx | 1 + .../utils/state_management/common.test.ts | 39 ++++++- .../utils/state_management/common.ts | 10 ++ .../state_management/discover_slice.test.tsx | 52 +++++++++ .../utils/state_management/discover_slice.tsx | 14 ++- .../view_components/canvas/discover_table.tsx | 6 ++ .../search_embeddable_component.tsx | 1 + 14 files changed, 333 insertions(+), 143 deletions(-) create mode 100644 src/plugins/discover/public/application/components/default_discover_table/helper.tsx 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 f2ee6d078e2b..864a2be1077a 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 @@ -5,7 +5,7 @@ import React, { useState, useMemo, useCallback } from 'react'; import { EuiDataGrid, EuiDataGridSorting, EuiPanel } from '@elastic/eui'; -import { IndexPattern } from '../../../opensearch_dashboards_services'; +import { IndexPattern, getServices } from '../../../opensearch_dashboards_services'; import { fetchTableDataCell } from './data_grid_table_cell_value'; import { buildDataGridColumns, computeVisibleColumns } from './data_grid_table_columns'; import { DocViewInspectButton } from './data_grid_table_docview_inspect_button'; @@ -13,24 +13,30 @@ import { DataGridFlyout } from './data_grid_table_flyout'; import { DiscoverGridContextProvider } from './data_grid_table_context'; import { DocViewFilterFn, OpenSearchSearchHit } from '../../doc_views/doc_views_types'; import { usePagination } from '../utils/use_pagination'; -import { SortOrder } from '../../../saved_searches/types'; import { buildColumns } from '../../utils/columns'; import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; import { DiscoverServices } from '../../../build_services'; -import { SAMPLE_SIZE_SETTING } from '../../../../common'; +import { + DOC_HIDE_TIME_COLUMN_SETTING, + SAMPLE_SIZE_SETTING, + SORT_DEFAULT_ORDER_SETTING, +} from '../../../../common'; +import { UI_SETTINGS } from '../../../../../data/common'; import { LegacyDiscoverTable } from '../default_discover_table/default_discover_table'; import { toolbarVisibility } from './constants'; import { getDataGridTableSetting } from '../utils/local_storage'; import { Storage } from '../../../../../opensearch_dashboards_utils/public'; +import { SortOrder } from '../default_discover_table/helper'; export interface DataGridTableProps { columns: string[]; indexPattern: IndexPattern; onAddColumn: (column: string) => void; onFilter: DocViewFilterFn; + onMoveColumn: (colName: string, destination: number) => void; onRemoveColumn: (column: string) => void; onReorderColumn: (col: string, source: number, destination: number) => void; - onSort: (sort: SortOrder[]) => void; + onSort: (s: SortOrder[]) => void; rows: OpenSearchSearchHit[]; onSetColumns: (columns: string[]) => void; sort: SortOrder[]; @@ -49,6 +55,7 @@ export const DataGridTable = ({ indexPattern, onAddColumn, onFilter, + onMoveColumn, onRemoveColumn, onReorderColumn, onSetColumns, @@ -64,11 +71,17 @@ export const DataGridTable = ({ storage, showPagination, }: DataGridTableProps) => { - const { services } = useOpenSearchDashboards(); - + const services = getServices(); const [inspectedHit, setInspectedHit] = useState(); const rowCount = useMemo(() => (rows ? rows.length : 0), [rows]); - const pageSizeLimit = services.uiSettings?.get(SAMPLE_SIZE_SETTING); + const [pageSizeLimit, isShortDots, hideTimeColumn, defaultSortOrder] = useMemo(() => { + return [ + services.uiSettings.get(SAMPLE_SIZE_SETTING), + services.uiSettings.get(UI_SETTINGS.SHORT_DOTS_ENABLE), + services.uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING), + services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'), + ]; + }, [services.uiSettings]); const pagination = usePagination({ rowCount, pageSizeLimit }); let adjustedColumns = buildColumns(columns); @@ -151,34 +164,38 @@ export const DataGridTable = ({ const legacyDiscoverTable = useMemo( () => ( setInspectedHit(undefined)} sampleSize={pageSizeLimit} showPagination={showPagination} + isShortDots={isShortDots} + hideTimeColumn={hideTimeColumn} + defaultSortOrder={defaultSortOrder} /> ), [ - displayedTableColumns, adjustedColumns, rows, indexPattern, - sortingColumns, - onColumnSort, + sort, + onSort, onRemoveColumn, - onReorderColumn, + onMoveColumn, onAddColumn, onFilter, pageSizeLimit, showPagination, + defaultSortOrder, + hideTimeColumn, + isShortDots, ] ); diff --git a/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx b/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx index 7c4201f93127..3369e23a7a8a 100644 --- a/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx +++ b/src/plugins/discover/public/application/components/data_grid/data_grid_table_cell_value.tsx @@ -16,18 +16,21 @@ import { import { stringify } from '@osd/std'; import { IndexPattern } from '../../../opensearch_dashboards_services'; import { OpenSearchSearchHit } from '../../doc_views/doc_views_types'; +import { shortenDottedString } from '../../helpers'; export function fetchSourceTypeDataCell( idxPattern: IndexPattern, row: Record, columnId: string, - isDetails: boolean + isDetails: boolean, + isShortDots: boolean ) { if (isDetails) { return {stringify(row[columnId], null, 2)}; } const formattedRow = idxPattern.formatHit(row); - const keys = Object.keys(formattedRow); + const rawKeys = Object.keys(formattedRow); + const keys = isShortDots ? rawKeys.map((k) => shortenDottedString(k)) : rawKeys; return ( diff --git a/src/plugins/discover/public/application/components/default_discover_table/default_discover_table.tsx b/src/plugins/discover/public/application/components/default_discover_table/default_discover_table.tsx index 496237d7ca8d..7a3dffea94c7 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/default_discover_table.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/default_discover_table.tsx @@ -9,8 +9,6 @@ import React, { useEffect, useRef, useState } from 'react'; import { EuiButtonEmpty, EuiCallOut, - EuiDataGridColumn, - EuiDataGridSorting, EuiProgress, EuiPagination, EuiFlexGroup, @@ -21,41 +19,51 @@ import { TableHeader } from './table_header'; import { DocViewFilterFn, OpenSearchSearchHit } from '../../doc_views/doc_views_types'; import { TableRow } from './table_rows'; import { IndexPattern } from '../../../opensearch_dashboards_services'; +import { SortOrder } from './helper'; +import { getLegacyDisplayedColumns } from './helper'; export interface DefaultDiscoverTableProps { - displayedTableColumns: EuiDataGridColumn[]; columns: string[]; rows: OpenSearchSearchHit[]; indexPattern: IndexPattern; - sortOrder: Array<{ - id: string; - direction: 'asc' | 'desc'; - }>; - onChangeSortOrder: (cols: EuiDataGridSorting['columns']) => void; + sort: SortOrder[]; + onSort: (s: SortOrder[]) => void; onRemoveColumn: (column: string) => void; - onReorderColumn: (col: string, source: number, destination: number) => void; + onReorderColumn: (colName: string, destination: number) => void; onAddColumn: (column: string) => void; onFilter: DocViewFilterFn; onClose: () => void; sampleSize: number; + isShortDots: boolean; + hideTimeColumn: boolean; + defaultSortOrder: string; showPagination?: boolean; } export const LegacyDiscoverTable = ({ - displayedTableColumns, columns, rows, indexPattern, - sortOrder, - onChangeSortOrder, + sort, + onSort, onRemoveColumn, onReorderColumn, onAddColumn, onFilter, onClose, sampleSize, + isShortDots, + hideTimeColumn, + defaultSortOrder, showPagination, }: DefaultDiscoverTableProps) => { + const displayedColumns = getLegacyDisplayedColumns( + columns, + indexPattern, + hideTimeColumn, + isShortDots + ); + const displayedColumnNames = displayedColumns.map((column) => column.name); const pageSize = 50; const [renderedRowCount, setRenderedRowCount] = useState(50); // Start with 50 rows const [displayedRows, setDisplayedRows] = useState(rows.slice(0, pageSize)); @@ -137,15 +145,13 @@ export const LegacyDiscoverTable = ({ @@ -155,13 +161,13 @@ export const LegacyDiscoverTable = ({ column.id)} - columns={columns} + columns={displayedColumnNames} indexPattern={indexPattern} onRemoveColumn={onRemoveColumn} onAddColumn={onAddColumn} onFilter={onFilter} onClose={onClose} + isShortDots={isShortDots} /> ); } diff --git a/src/plugins/discover/public/application/components/default_discover_table/helper.tsx b/src/plugins/discover/public/application/components/default_discover_table/helper.tsx new file mode 100644 index 000000000000..71df56fe8383 --- /dev/null +++ b/src/plugins/discover/public/application/components/default_discover_table/helper.tsx @@ -0,0 +1,101 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IndexPattern } from '../../../opensearch_dashboards_services'; +import { shortenDottedString } from '../../helpers'; + +export type SortOrder = [string, string]; +export interface LegacyDisplayedColumn { + name: string; + displayName: string; + isSortable: boolean; + isRemoveable: boolean; + colLeftIdx: number; + colRightIdx: number; +} + +export interface ColumnProps { + name: string; + displayName: string; + isSortable: boolean; + isRemoveable: boolean; + colLeftIdx: number; + colRightIdx: number; +} + +/** + * Returns properties necessary to display the time column + * If it's an IndexPattern with timefield, the time column is + * prepended, not moveable and removeable + * @param timeFieldName + */ +export function getTimeColumn(timeFieldName: string): ColumnProps { + return { + name: timeFieldName, + displayName: 'Time', + isSortable: true, + isRemoveable: false, + colLeftIdx: -1, + colRightIdx: -1, + }; +} +/** + * A given array of column names returns an array of properties + * necessary to display the columns. If the given indexPattern + * has a timefield, a time column is prepended + * @param columns + * @param indexPattern + * @param hideTimeField + * @param isShortDots + */ +export function getLegacyDisplayedColumns( + columns: string[], + indexPattern: IndexPattern, + hideTimeField: boolean, + isShortDots: boolean +): LegacyDisplayedColumn[] { + if (!Array.isArray(columns) || typeof indexPattern !== 'object' || !indexPattern.getFieldByName) { + return []; + } + const columnProps = columns.map((column, idx) => { + const field = indexPattern.getFieldByName(column); + return { + name: column, + displayName: isShortDots ? shortenDottedString(column) : column, + isSortable: field && field.sortable ? true : false, + isRemoveable: column !== '_source' || columns.length > 1, + colLeftIdx: idx - 1 < 0 ? -1 : idx - 1, + colRightIdx: idx + 1 >= columns.length ? -1 : idx + 1, + }; + }); + return !hideTimeField && indexPattern.timeFieldName + ? [getTimeColumn(indexPattern.timeFieldName), ...columnProps] + : columnProps; +} diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx index 6715910e8346..75ae73a82434 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_header.tsx @@ -12,77 +12,47 @@ import './_table_header.scss'; import React from 'react'; -import { EuiDataGridColumn, EuiDataGridSorting } from '@elastic/eui'; import { IndexPattern } from '../../../opensearch_dashboards_services'; import { TableHeaderColumn } from './table_header_column'; +import { SortOrder, LegacyDisplayedColumn } from './helper'; +import { getDefaultSort } from '../../view_components/utils/get_default_sort'; interface Props { - displayedTableColumns: EuiDataGridColumn[]; - // columns: string[]; + displayedColumns: LegacyDisplayedColumn[]; defaultSortOrder: string; - // hideTimeColumn: boolean; indexPattern: IndexPattern; - // isShortDots: boolean; - onChangeSortOrder?: (cols: EuiDataGridSorting['columns']) => void; - onMoveColumn?: (name: string, index: number) => void; + onChangeSortOrder?: (sortOrder: SortOrder[]) => void; onRemoveColumn?: (name: string) => void; - onReorderColumn?: (col: string, source: number, destination: number) => void; - sortOrder: Array<{ - id: string; - direction: 'desc' | 'asc'; - }>; + onReorderColumn?: (colName: string, destination: number) => void; + sortOrder: SortOrder[]; } export function TableHeader({ - displayedTableColumns, + displayedColumns, defaultSortOrder, - // hideTimeColumn, indexPattern, - // isShortDots, onChangeSortOrder, onReorderColumn, onRemoveColumn, sortOrder, }: Props) { - const timeColName = indexPattern.timeFieldName; return ( ); } diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_header_column.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_header_column.tsx index b6bc25b2afa7..44eba17f1dfe 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_header_column.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_header_column.tsx @@ -13,24 +13,20 @@ import './_table_header.scss'; import React, { ReactNode } from 'react'; import { i18n } from '@osd/i18n'; -import { EuiButtonIcon, EuiDataGridSorting, EuiToolTip } from '@elastic/eui'; +import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; +import { SortOrder } from './helper'; interface Props { - currentIdx: number; colLeftIdx: number; // idx of the column to the left, -1 if moving is not possible colRightIdx: number; // idx of the column to the right, -1 if moving is not possible displayName: ReactNode; isRemoveable: boolean; isSortable?: boolean; name: string; - onChangeSortOrder?: (cols: EuiDataGridSorting['columns']) => void; - onMoveColumn?: (name: string, idx: number) => void; - onReorderColumn?: (col: string, source: number, destination: number) => void; + onChangeSortOrder?: (sortOrder: SortOrder[]) => void; + onReorderColumn?: (colName: string, destination: number) => void; onRemoveColumn?: (name: string) => void; - sortOrder: Array<{ - id: string; - direction: 'desc' | 'asc'; - }>; + sortOrder: SortOrder[]; } const sortDirectionToIcon: Record = { @@ -40,7 +36,6 @@ const sortDirectionToIcon: Record = { }; export function TableHeaderColumn({ - currentIdx, colLeftIdx, colRightIdx, displayName, @@ -52,9 +47,9 @@ export function TableHeaderColumn({ onRemoveColumn, sortOrder, }: Props) { - const currentSortWithoutColumn = sortOrder.filter((pair) => pair.id !== name); - const currentColumnSort = sortOrder.find((pair) => pair.id === name); - const currentColumnSortDirection = (currentColumnSort && currentColumnSort.direction) || ''; + const currentSortWithoutColumn = sortOrder.filter((pair) => pair[0] !== name); + const currentColumnSort = sortOrder.find((pair) => pair[0] === name); + const currentColumnSortDirection = (currentColumnSort && currentColumnSort[1]) || ''; const btnSortIcon = sortDirectionToIcon[currentColumnSortDirection]; const btnSortClassName = @@ -65,35 +60,15 @@ export function TableHeaderColumn({ const handleChangeSortOrder = () => { if (!onChangeSortOrder) return; - let currentSortOrder; - let newSortOrder: { - id: string; - direction: 'desc' | 'asc'; - }; // Cycle goes Unsorted -> Asc -> Desc -> Unsorted if (currentColumnSort === undefined) { - newSortOrder = { - id: name, - direction: 'asc', - }; - currentSortOrder = [...currentSortWithoutColumn, newSortOrder]; - onChangeSortOrder(currentSortOrder); + onChangeSortOrder([...currentSortWithoutColumn, [name, 'asc']]); } else if (currentColumnSortDirection === 'asc') { - newSortOrder = { - id: name, - direction: 'desc', - }; - currentSortOrder = [...currentSortWithoutColumn, newSortOrder]; - onChangeSortOrder(currentSortOrder); + onChangeSortOrder([...currentSortWithoutColumn, [name, 'desc']]); } else if (currentColumnSortDirection === 'desc' && currentSortWithoutColumn.length === 0) { // If we're at the end of the cycle and this is the only existing sort, we switch // back to ascending sort instead of removing it. - newSortOrder = { - id: name, - direction: 'asc', - }; - currentSortOrder = [...currentSortWithoutColumn, newSortOrder]; - onChangeSortOrder(currentSortOrder); + onChangeSortOrder([...currentSortWithoutColumn, [name, 'asc']]); } else { onChangeSortOrder(currentSortWithoutColumn); } @@ -168,7 +143,7 @@ export function TableHeaderColumn({ values: { columnName: name }, }), className: 'fa fa-angle-double-left osdDocTableHeader__move', - onClick: () => onReorderColumn && onReorderColumn(name, currentIdx, colLeftIdx), + onClick: () => onReorderColumn && onReorderColumn(name, colLeftIdx), testSubject: `docTableMoveLeftHeader-${name}`, tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnLeftButtonTooltip', { defaultMessage: 'Move column to the left', @@ -183,7 +158,7 @@ export function TableHeaderColumn({ values: { columnName: name }, }), className: 'fa fa-angle-double-right osdDocTableHeader__move', - onClick: () => onReorderColumn && onReorderColumn(name, currentIdx, colRightIdx), + onClick: () => onReorderColumn && onReorderColumn(name, colRightIdx), testSubject: `docTableMoveRightHeader-${name}`, tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnRightButtonTooltip', { defaultMessage: 'Move column to the right', diff --git a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx index 9170d97921d2..7da2865e24d9 100644 --- a/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx +++ b/src/plugins/discover/public/application/components/default_discover_table/table_rows.tsx @@ -21,24 +21,24 @@ import { fetchSourceTypeDataCell } from '../data_grid/data_grid_table_cell_value export interface TableRowProps { row: OpenSearchSearchHit; - columnIds: string[]; columns: string[]; indexPattern: IndexPattern; onRemoveColumn: (column: string) => void; onAddColumn: (column: string) => void; onFilter: DocViewFilterFn; onClose: () => void; + isShortDots: boolean; } export const TableRow = ({ row, - columnIds, columns, indexPattern, onRemoveColumn, onAddColumn, onFilter, onClose, + isShortDots, }: TableRowProps) => { const flattened = indexPattern.flattenHit(row); const [isExpanded, setIsExpanded] = useState(false); @@ -53,14 +53,14 @@ export const TableRow = ({ data-test-subj="docTableExpandToggleColumn" /> - {columnIds.map((columnId) => { - const fieldInfo = indexPattern.fields.getByName(columnId); - const fieldMapping = flattened[columnId]; + {columns.map((colName) => { + const fieldInfo = indexPattern.fields.getByName(colName); + const fieldMapping = flattened[colName]; if (typeof row === 'undefined') { return ( ); } - const formattedValue = indexPattern.formatField(row, columnId); + const formattedValue = indexPattern.formatField(row, colName); if (typeof formattedValue === 'undefined') { return (
- {displayedTableColumns.map( - (col: EuiDataGridColumn, idx: number, cols: EuiDataGridColumn[]) => { - const colLeftIdx = - !col.actions || !col.actions!.showMoveLeft || idx - 1 <= 0 || col.id === timeColName - ? -1 - : idx - 1; - const colRightIdx = - !col.actions || - !col.actions!.showMoveRight || - idx + 1 >= cols.length || - col.id === timeColName - ? -1 - : idx + 1; - - return ( - ({ id, direction })) - } - onReorderColumn={onReorderColumn} - onRemoveColumn={onRemoveColumn} - onChangeSortOrder={onChangeSortOrder} - /> - ); - } - )} + {displayedColumns.map((col) => { + return ( + + ); + })}
@@ -72,23 +72,23 @@ export const TableRow = ({ if (fieldInfo?.type === '_source') { return (
- {fetchSourceTypeDataCell(indexPattern, row, columnId, false)} + {fetchSourceTypeDataCell(indexPattern, row, colName, false, isShortDots)}
@@ -102,7 +102,7 @@ export const TableRow = ({ if (!fieldInfo?.filterable) { return ( @@ -116,11 +116,10 @@ export const TableRow = ({ return ( diff --git a/src/plugins/discover/public/application/components/doc_views/context_app.tsx b/src/plugins/discover/public/application/components/doc_views/context_app.tsx index eea981fe88d7..f2777f41076a 100644 --- a/src/plugins/discover/public/application/components/doc_views/context_app.tsx +++ b/src/plugins/discover/public/application/components/doc_views/context_app.tsx @@ -101,6 +101,7 @@ export function ContextApp({ indexPattern={indexPattern} onAddColumn={() => {}} onFilter={onAddFilter} + onMoveColumn={() => {}} onRemoveColumn={() => {}} onReorderColumn={() => {}} onSetColumns={() => {}} 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 index 64a2dba99dd4..c9c41a914c74 100644 --- a/src/plugins/discover/public/application/utils/state_management/common.test.ts +++ b/src/plugins/discover/public/application/utils/state_management/common.test.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { addColumn, removeColumn, reorderColumn } from './common'; +import { addColumn, removeColumn, reorderColumn, moveColumn } from './common'; describe('commonUtils', () => { it('should handle addColumn', () => { @@ -22,4 +22,41 @@ describe('commonUtils', () => { 'column1', ]); }); + + it('should handle moveColumn', () => { + // test moving a column within the array + expect(moveColumn(['column1', 'column2', 'column3'], 'column2', 0)).toEqual([ + 'column2', + 'column1', + 'column3', + ]); + + // test moving a column to the same index (should result in no change) + expect(moveColumn(['column1', 'column2', 'column3'], 'column2', 1)).toEqual([ + 'column1', + 'column2', + 'column3', + ]); + + // test moving a column to the end + expect(moveColumn(['column1', 'column2', 'column3'], 'column1', 2)).toEqual([ + 'column2', + 'column3', + 'column1', + ]); + + // test trying to move a column to an index out of bounds (should return original array) + expect(moveColumn(['column1', 'column2', 'column3'], 'column1', 3)).toEqual([ + 'column1', + 'column2', + 'column3', + ]); + + // test trying to move a column that doesn't exist (should return original array) + expect(moveColumn(['column1', 'column2', 'column3'], 'column4', 1)).toEqual([ + 'column1', + 'column2', + 'column3', + ]); + }); }); diff --git a/src/plugins/discover/public/application/utils/state_management/common.ts b/src/plugins/discover/public/application/utils/state_management/common.ts index 800753fb4a36..1acba05ecb75 100644 --- a/src/plugins/discover/public/application/utils/state_management/common.ts +++ b/src/plugins/discover/public/application/utils/state_management/common.ts @@ -21,3 +21,13 @@ export const reorderColumn = (columns: string[], source: number, destination: nu newColumns.splice(destination, 0, removed); return newColumns; }; + +export function moveColumn(columns: string[], columnName: string, newIndex: number) { + if (newIndex < 0 || newIndex >= columns.length || !columns.includes(columnName)) { + return columns; + } + const modifiedColumns = [...columns]; + modifiedColumns.splice(modifiedColumns.indexOf(columnName), 1); // remove at old index + modifiedColumns.splice(newIndex, 0, columnName); // insert before new index + return modifiedColumns; +} 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 cbfc9c3769b0..ba94236e1492 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 @@ -82,4 +82,56 @@ describe('discoverSlice', () => { const result = discoverSlice.reducer(initialState, action); expect(result.sort).toEqual([['field2', 'desc']]); }); + + it('should handle moveColumn', () => { + initialState = { + columns: ['column1', 'column2', 'column3'], + sort: [], + }; + const action = { + type: 'discover/moveColumn', + payload: { columnName: 'column2', destination: 0 }, + }; + const result = discoverSlice.reducer(initialState, action); + expect(result.columns).toEqual(['column2', 'column1', 'column3']); + }); + + it('should maintain columns order when moving a column to its current position', () => { + initialState = { + columns: ['column1', 'column2', 'column3'], + sort: [], + }; + const action = { + type: 'discover/moveColumn', + payload: { columnName: 'column2', destination: 1 }, + }; + const result = discoverSlice.reducer(initialState, action); + expect(result.columns).toEqual(['column1', 'column2', 'column3']); + }); + + it('should handle moveColumn when destination is out of range', () => { + initialState = { + columns: ['column1', 'column2', 'column3'], + sort: [], + }; + const action = { + type: 'discover/moveColumn', + payload: { columnName: 'column1', destination: 5 }, + }; + const result = discoverSlice.reducer(initialState, action); + expect(result.columns).toEqual(['column1', 'column2', 'column3']); + }); + + it('should not change columns if column to move does not exist', () => { + initialState = { + columns: ['column1', 'column2', 'column3'], + sort: [], + }; + const action = { + type: 'discover/moveColumn', + payload: { columnName: 'nonExistingColumn', destination: 0 }, + }; + const result = discoverSlice.reducer(initialState, action); + expect(result.columns).toEqual(['column1', 'column2', 'column3']); + }); }); 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 f90d400ff3d5..c493086c4d45 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 @@ -42,7 +42,7 @@ export interface DiscoverState { * dirty flag to indicate if the saved search has been modified * since the last save */ - isDirty: boolean; + isDirty?: boolean; } export interface DiscoverRootState extends RootState { @@ -128,6 +128,17 @@ export const discoverSlice = createSlice({ isDirty: true, }; }, + moveColumn(state, action: PayloadAction<{ columnName: string; destination: number }>) { + const columns = utils.moveColumn( + state.columns, + action.payload.columnName, + action.payload.destination + ); + return { + ...state, + columns, + }; + }, setColumns(state, action: PayloadAction<{ columns: string[] }>) { return { ...state, @@ -167,6 +178,7 @@ export const { addColumn, removeColumn, reorderColumn, + moveColumn, setColumns, setSort, setInterval, 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 e42585b068fb..7f3bdfb0b924 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 @@ -10,6 +10,7 @@ import { DataGridTable } from '../../components/data_grid/data_grid_table'; import { useDiscoverContext } from '../context'; import { addColumn, + moveColumn, removeColumn, reorderColumn, setColumns, @@ -65,6 +66,10 @@ export const DiscoverTable = ({ rows }: Props) => { dispatch(reorderColumn({ source: source - 1, destination: destination - 1 })); }; + const onMoveColumn = (colName: string, destination: number) => { + dispatch(moveColumn({ columnName: colName, destination })); + }; + const onSetColumns = (cols: string[]) => dispatch(setColumns({ columns: cols })); const onSetSort = (s: SortOrder[]) => { dispatch(setSort(s)); @@ -106,6 +111,7 @@ export const DiscoverTable = ({ rows }: Props) => { indexPattern={indexPattern} onAddColumn={onAddColumn} onFilter={onAddFilter as DocViewFilterFn} + onMoveColumn={onMoveColumn} onRemoveColumn={onRemoveColumn} onReorderColumn={onReorderColumn} onSetColumns={onSetColumns} diff --git a/src/plugins/discover/public/embeddable/search_embeddable_component.tsx b/src/plugins/discover/public/embeddable/search_embeddable_component.tsx index 4a6078be745b..16e91abdf173 100644 --- a/src/plugins/discover/public/embeddable/search_embeddable_component.tsx +++ b/src/plugins/discover/public/embeddable/search_embeddable_component.tsx @@ -33,6 +33,7 @@ export function SearchEmbeddableComponent({ searchProps }: SearchEmbeddableProps indexPattern: searchProps.indexPattern, onAddColumn: searchProps.onAddColumn, onFilter: searchProps.onFilter, + onMoveColumn: searchProps.onMoveColumn, onRemoveColumn: searchProps.onRemoveColumn, onReorderColumn: searchProps.onReorderColumn, onSort: searchProps.onSort,