From caf0d04f7e6391606f508929e48ac6f40e6dcc37 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Thu, 19 Sep 2024 14:50:03 -0500 Subject: [PATCH 01/17] chore: strengthen context types with default adapter type --- .../common/types/expression_functions.ts | 5 ++++- .../common/types/expression_functions.ts | 5 ++++- .../common/types/expression_functions.ts | 5 ++++- .../common/types/expression_functions.ts | 5 ++++- .../common/types/expression_functions.ts | 14 ++++++++++---- .../common/types/expression_functions.ts | 8 ++++++-- .../expression_xy/common/utils/log_datatables.ts | 10 +++++++--- .../expressions/common/util/tables_adapter.ts | 1 + .../lens/common/expressions/datatable/types.ts | 10 ++++++++-- .../lens/choropleth_chart/expression_function.ts | 9 +++++++-- 10 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts index 1ef7a0446af1e..44a213961290a 100644 --- a/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/types/expression_functions.ts @@ -11,6 +11,8 @@ import { $Values } from '@kbn/utility-types'; import type { PaletteOutput, CustomPaletteParams } from '@kbn/coloring'; import { Datatable, + DefaultInspectorAdapters, + ExecutionContext, ExpressionFunctionDefinition, ExpressionValueRender, } from '@kbn/expressions-plugin/common'; @@ -86,7 +88,8 @@ export type GaugeExpressionFunctionDefinition = ExpressionFunctionDefinition< typeof EXPRESSION_GAUGE_NAME, GaugeInput, GaugeArguments, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; export interface Accessors { diff --git a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts index 0055672600406..f63a0a56b63ac 100644 --- a/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_heatmap/common/types/expression_functions.ts @@ -11,6 +11,8 @@ import { Position } from '@elastic/charts'; import type { PaletteOutput } from '@kbn/coloring'; import { Datatable, + DefaultInspectorAdapters, + ExecutionContext, ExpressionFunctionDefinition, ExpressionValueRender, } from '@kbn/expressions-plugin/common'; @@ -114,7 +116,8 @@ export type HeatmapExpressionFunctionDefinition = ExpressionFunctionDefinition< typeof EXPRESSION_HEATMAP_NAME, HeatmapInput, HeatmapArguments, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; export type HeatmapLegendExpressionFunctionDefinition = ExpressionFunctionDefinition< diff --git a/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts index 051fc7d3319d5..e1dd3251e5373 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts @@ -10,6 +10,8 @@ import type { PaletteOutput } from '@kbn/coloring'; import { Datatable, + DefaultInspectorAdapters, + ExecutionContext, ExpressionFunctionDefinition, ExpressionValueRender, Style, @@ -47,5 +49,6 @@ export type MetricVisExpressionFunctionDefinition = ExpressionFunctionDefinition typeof EXPRESSION_METRIC_NAME, MetricInput, MetricArguments, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; diff --git a/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts index 13b1ff35197c7..4db6f4b948ecd 100644 --- a/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_metric/common/types/expression_functions.ts @@ -12,6 +12,8 @@ import { LayoutDirection, MetricStyle, MetricWTrend } from '@elastic/charts'; import { $Values } from '@kbn/utility-types'; import { Datatable, + DefaultInspectorAdapters, + ExecutionContext, ExpressionFunctionDefinition, ExpressionValueRender, } from '@kbn/expressions-plugin/common'; @@ -64,7 +66,8 @@ export type MetricVisExpressionFunctionDefinition = ExpressionFunctionDefinition typeof EXPRESSION_METRIC_NAME, MetricInput, MetricArguments, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; export interface TrendlineArguments { diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_functions.ts index 5aecb2cad4272..0d402b29d08e7 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/types/expression_functions.ts @@ -14,6 +14,8 @@ import { Datatable, ExpressionValueRender, ExpressionValueBoxed, + DefaultInspectorAdapters, + ExecutionContext, } from '@kbn/expressions-plugin/common'; import { PARTITION_LABELS_VALUE, @@ -66,28 +68,32 @@ export type PieVisExpressionFunctionDefinition = ExpressionFunctionDefinition< typeof PIE_VIS_EXPRESSION_NAME, Datatable, PieVisConfig, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; export type TreemapVisExpressionFunctionDefinition = ExpressionFunctionDefinition< typeof TREEMAP_VIS_EXPRESSION_NAME, Datatable, TreemapVisConfig, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; export type MosaicVisExpressionFunctionDefinition = ExpressionFunctionDefinition< typeof MOSAIC_VIS_EXPRESSION_NAME, Datatable, MosaicVisConfig, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; export type WaffleVisExpressionFunctionDefinition = ExpressionFunctionDefinition< typeof WAFFLE_VIS_EXPRESSION_NAME, Datatable, WaffleVisConfig, - ExpressionValueRender + ExpressionValueRender, + ExecutionContext >; export enum ChartTypes { diff --git a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts index 005cdae55862d..94e294e51a02b 100644 --- a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts @@ -13,6 +13,8 @@ import type { PaletteOutput } from '@kbn/coloring'; import type { Datatable, DatatableColumnMeta, + DefaultInspectorAdapters, + ExecutionContext, ExpressionFunctionDefinition, } from '@kbn/expressions-plugin/common'; import { @@ -449,13 +451,15 @@ export type XyVisFn = ExpressionFunctionDefinition< typeof XY_VIS, Datatable, XYArgs, - Promise + Promise, + ExecutionContext >; export type LayeredXyVisFn = ExpressionFunctionDefinition< typeof LAYERED_XY_VIS, Datatable, LayeredXYArgs, - Promise + Promise, + ExecutionContext >; export type ExtendedDataLayerFn = ExpressionFunctionDefinition< diff --git a/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts b/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts index 80028ccf36aaf..afaf46b29da0a 100644 --- a/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts +++ b/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts @@ -8,7 +8,11 @@ */ import { QueryPointEventAnnotationOutput } from '@kbn/event-annotation-plugin/common'; -import { Datatable, ExecutionContext } from '@kbn/expressions-plugin/common'; +import { + Datatable, + DefaultInspectorAdapters, + ExecutionContext, +} from '@kbn/expressions-plugin/common'; import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common'; import { Dimension, prepareLogTable } from '@kbn/visualizations-plugin/common/utils'; import { LayerTypes, REFERENCE_LINE } from '../constants'; @@ -23,7 +27,7 @@ import { export const logDatatables = ( layers: CommonXYLayerConfig[], - handlers: ExecutionContext, + handlers: ExecutionContext, splitColumnAccessor?: string | ExpressionValueVisDimension, splitRowAccessor?: string | ExpressionValueVisDimension, annotations?: ExpressionAnnotationResult @@ -88,7 +92,7 @@ const getLogAnnotationTable = (data: Datatable, layer: AnnotationLayerConfigResu export const logDatatable = ( data: Datatable, layers: CommonXYLayerConfig[], - handlers: ExecutionContext, + handlers: ExecutionContext, splitColumnAccessor?: string | ExpressionValueVisDimension, splitRowAccessor?: string | ExpressionValueVisDimension ) => { diff --git a/src/plugins/expressions/common/util/tables_adapter.ts b/src/plugins/expressions/common/util/tables_adapter.ts index 38d510b8835b1..4715f87336f7d 100644 --- a/src/plugins/expressions/common/util/tables_adapter.ts +++ b/src/plugins/expressions/common/util/tables_adapter.ts @@ -12,6 +12,7 @@ import type { Datatable } from '../expression_types/specs'; export class TablesAdapter extends EventEmitter { private _tables: { [key: string]: Datatable } = {}; + public allowCsvExport: boolean = false; public logDatatable(name: string, datatable: Datatable): void { this._tables[name] = datatable; diff --git a/x-pack/plugins/lens/common/expressions/datatable/types.ts b/x-pack/plugins/lens/common/expressions/datatable/types.ts index 7f03a1f4fb19b..befcf1d213002 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/types.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/types.ts @@ -5,7 +5,12 @@ * 2.0. */ -import type { Datatable, ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common'; +import type { + Datatable, + DefaultInspectorAdapters, + ExecutionContext, + ExpressionFunctionDefinition, +} from '@kbn/expressions-plugin/common'; import type { DatatableArgs } from './datatable'; export interface DatatableProps { @@ -25,5 +30,6 @@ export type DatatableExpressionFunction = ExpressionFunctionDefinition< 'lens_datatable', Datatable, DatatableArgs, - Promise + Promise, + ExecutionContext >; diff --git a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts index 989cc06c5d53b..df8bb1134e7ed 100644 --- a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts +++ b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts @@ -5,7 +5,11 @@ * 2.0. */ -import type { ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common'; +import type { + DefaultInspectorAdapters, + ExecutionContext, + ExpressionFunctionDefinition, +} from '@kbn/expressions-plugin/common'; import { Datatable } from '@kbn/expressions-plugin/common'; import { i18n } from '@kbn/i18n'; import { prepareLogTable } from '@kbn/visualizations-plugin/common/utils'; @@ -22,7 +26,8 @@ export const getExpressionFunction = (): ExpressionFunctionDefinition< 'lens_choropleth_chart', Datatable, Omit, - ChoroplethChartRender + ChoroplethChartRender, + ExecutionContext > => ({ name: 'lens_choropleth_chart', type: 'render', From 64aaadc3732725d015fb5e293896f5fb6896f8dc Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Thu, 19 Sep 2024 15:06:11 -0500 Subject: [PATCH 02/17] fix: table inspect flyout export data - Add transposed table to list of tables - Fix table select dropdown styles --- .../components/data_table_selector.tsx | 60 ++++++++++--------- .../expressions/common/util/tables_adapter.ts | 9 +-- .../expressions/datatable/datatable_fn.ts | 4 ++ 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx index 5906baca70cc8..b9a0563da0aeb 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx @@ -85,35 +85,37 @@ export class TableSelector extends Component - - - - - } - isOpen={this.state.isPopoverOpen} - closePopover={this.closePopover} - panelPaddingSize="none" - anchorPosition="downLeft" - repositionOnScroll - > - - + +
+ + + + } + isOpen={this.state.isPopoverOpen} + closePopover={this.closePopover} + panelPaddingSize="none" + anchorPosition="downLeft" + repositionOnScroll + > + + +
); diff --git a/src/plugins/expressions/common/util/tables_adapter.ts b/src/plugins/expressions/common/util/tables_adapter.ts index 4715f87336f7d..0cfe77a86489b 100644 --- a/src/plugins/expressions/common/util/tables_adapter.ts +++ b/src/plugins/expressions/common/util/tables_adapter.ts @@ -11,20 +11,21 @@ import { EventEmitter } from 'events'; import type { Datatable } from '../expression_types/specs'; export class TablesAdapter extends EventEmitter { - private _tables: { [key: string]: Datatable } = {}; + #tables: { [key: string]: Datatable } = {}; + public allowCsvExport: boolean = false; public logDatatable(name: string, datatable: Datatable): void { - this._tables[name] = datatable; + this.#tables[name] = datatable; this.emit('change', this.tables); } public reset() { - this._tables = {}; + this.#tables = {}; this.emit('change', this.tables); } public get tables() { - return this._tables; + return this.#tables; } } diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts index b528bde76e220..32ff96e4f135a 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -54,6 +54,10 @@ export const datatableFn = untransposedData = cloneDeep(table); // transposes table and args inplace transposeTable(args, table, formatters); + + if (context?.inspectorAdapters?.tables) { + context.inspectorAdapters.tables.logDatatable('transpose', table); + } } const columnsWithSummary = args.columns.filter((c) => c.summaryRow); From 3d1d55a3643e2a88295062b8c1ba2478dcc76a26 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Fri, 20 Sep 2024 16:00:21 -0500 Subject: [PATCH 03/17] feat: support transposed columns in table - export transpose datatable from share - support sorting transposed columns - sort transposed columns by args column order (zippered) - removed hidden columns from share output - sort rows when column sorting is present - push empty value to bottom --- .../data/common/exports/export_csv.test.ts | 2 +- .../data/common/exports/export_csv.tsx | 73 +++++++++++++++---- .../expressions/datatable/datatable_fn.ts | 12 ++- .../datatable/transpose_helpers.ts | 8 +- .../csv_download_provider.tsx | 30 +++++--- .../lens/public/app_plugin/lens_top_nav.tsx | 14 +++- x-pack/plugins/lens/public/types.ts | 9 ++- .../datatable/visualization.tsx | 30 ++++++-- 8 files changed, 139 insertions(+), 39 deletions(-) diff --git a/src/plugins/data/common/exports/export_csv.test.ts b/src/plugins/data/common/exports/export_csv.test.ts index 261d2725f7789..9bfc1e69a9c28 100644 --- a/src/plugins/data/common/exports/export_csv.test.ts +++ b/src/plugins/data/common/exports/export_csv.test.ts @@ -103,7 +103,7 @@ describe('CSV exporter', () => { expect( datatableToCSV(datatable, { ...getDefaultOptions(), - columnsSorting: ['col2', 'col1'], + sortedColumns: ['col2', 'col1'], }) ).toMatch('columnTwo,columnOne\r\n"Formatted_5","Formatted_value"\r\n'); }); diff --git a/src/plugins/data/common/exports/export_csv.tsx b/src/plugins/data/common/exports/export_csv.tsx index 1c150354721e1..0547cd8ec36ac 100644 --- a/src/plugins/data/common/exports/export_csv.tsx +++ b/src/plugins/data/common/exports/export_csv.tsx @@ -11,6 +11,7 @@ import { Datatable } from '@kbn/expressions-plugin/common'; import { FormatFactory } from '@kbn/field-formats-plugin/common'; +import { EuiDataGridColumnSortingConfig } from '@elastic/eui'; import { createEscapeValue } from './escape_value'; export const LINE_FEED_CHARACTER = '\r\n'; @@ -22,12 +23,21 @@ interface CSVOptions { escapeFormulaValues: boolean; formatFactory: FormatFactory; raw?: boolean; - columnsSorting?: string[]; + sortedColumns?: string[]; + columnSorting?: EuiDataGridColumnSortingConfig[]; } export function datatableToCSV( { columns, rows }: Datatable, - { csvSeparator, quoteValues, formatFactory, raw, escapeFormulaValues, columnsSorting }: CSVOptions + { + csvSeparator, + quoteValues, + formatFactory, + raw, + escapeFormulaValues, + sortedColumns, + columnSorting, + }: CSVOptions ) { const escapeValues = createEscapeValue({ separator: csvSeparator, @@ -35,21 +45,32 @@ export function datatableToCSV( escapeFormulaValues, }); - const sortedIds = columnsSorting || columns.map((col) => col.id); + const sortedIds = sortedColumns + ? columns + .map((c) => { + // need to find original id for transposed column + const sortIndex = sortedColumns.findIndex((id) => c.id.endsWith(id)); + return { + id: c.id, + sortIndex, + isTransposed: (sortedColumns[sortIndex] ?? '') !== c.id, + }; + }) + .filter(({ sortIndex }) => sortIndex >= 0) + // keep original zipped order between multiple transposed columns + .sort((a, b) => (a.isTransposed && b.isTransposed ? 0 : a.sortIndex - b.sortIndex)) + .map(({ id }) => id) + : columns.map(({ id }) => id); - // Build an index lookup table - const columnIndexLookup = sortedIds.reduce((memo, id, index) => { - memo[id] = index; - return memo; - }, {} as Record); + const columnIndexLookup = new Map(sortedIds.map((id, i) => [id, i])); - // Build the header row by its names const header: string[] = []; const sortedColumnIds: string[] = []; const formatters: Record> = {}; for (const column of columns) { - const columnIndex = columnIndexLookup[column.id]; + const columnIndex = columnIndexLookup.get(column.id) ?? -1; + if (columnIndex < 0) continue; // hidden or not found header[columnIndex] = escapeValues(column.name); sortedColumnIds[columnIndex] = column.id; @@ -61,14 +82,36 @@ export function datatableToCSV( } // Convert the array of row objects to an array of row arrays - const csvRows = rows.map((row) => { - return sortedColumnIds.map((id) => - escapeValues(raw ? row[id] : formatters[id].convert(row[id])) - ); - }); + const csvRows = rows + .map((row) => { + return sortedColumnIds.map((id) => + escapeValues(raw ? row[id] : formatters[id].convert(row[id])) + ); + }) + .sort(rowSortPredicate(sortedColumnIds, columnSorting)); return ( [header, ...csvRows].map((row) => row.join(csvSeparator)).join(LINE_FEED_CHARACTER) + LINE_FEED_CHARACTER ); // Add \r\n after last line } + +function rowSortPredicate( + sortedColumnIds: string[], + columnSorting?: EuiDataGridColumnSortingConfig[] +) { + if (!columnSorting) return () => 0; + + const columnIdMap = new Map(columnSorting.map(({ id }) => [id, sortedColumnIds.indexOf(id)])); + return (rowA: string[], rowB: string[]) => { + return columnSorting.reduce((acc, { id, direction }) => { + const i = columnIdMap.get(id) ?? -1; + if (i < 0) return acc; + + const a = rowA[i]; + const b = rowB[i]; + const emptyValueSort = a === '' ? 1 : b === '' ? -1 : 0; // always put empty values at bottom + return acc || emptyValueSort || a.localeCompare(b) * (direction === 'asc' ? 1 : -1); + }, 0); + }; +} diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts index 32ff96e4f135a..e70cd4ac133c8 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -14,6 +14,14 @@ import { transposeTable } from './transpose_helpers'; import { computeSummaryRowForColumn } from './summary'; import type { DatatableExpressionFunction } from './types'; +/** + * Available datatables logged to inspector + */ +export const DatatableInspectorTables = { + Default: 'default', + Transpose: 'transpose', +}; + export const datatableFn = ( getFormatFactory: (context: ExecutionContext) => FormatFactory | Promise @@ -36,7 +44,7 @@ export const datatableFn = true ); - context.inspectorAdapters.tables.logDatatable('default', logTable); + context.inspectorAdapters.tables.logDatatable(DatatableInspectorTables.Default, logTable); } let untransposedData: Datatable | undefined; @@ -56,7 +64,7 @@ export const datatableFn = transposeTable(args, table, formatters); if (context?.inspectorAdapters?.tables) { - context.inspectorAdapters.tables.logDatatable('transpose', table); + context.inspectorAdapters.tables.logDatatable(DatatableInspectorTables.Transpose, table); } } diff --git a/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts b/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts index 7f7e4d467f250..b639a52ee1b2b 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts @@ -52,8 +52,7 @@ export function transposeTable( ) { args.columns .filter((columnArgs) => columnArgs.isTransposed) - // start with the inner nested transposed column and work up to preserve column grouping - .reverse() + .reverse() // start with the inner nested transposed column and work up to preserve column grouping .forEach(({ columnId: transposedColumnId }) => { const datatableColumnIndex = firstTable.columns.findIndex((c) => c.id === transposedColumnId); const datatableColumn = firstTable.columns[datatableColumnIndex]; @@ -86,6 +85,11 @@ export function transposeTable( transposedColumnId, metricsColumnArgs ); + + const colOrderMap = new Map(args.columns.map((c, i) => [c.columnId, i])); + firstTable.columns.sort((a, b) => { + return (colOrderMap.get(a.id) ?? 0) - (colOrderMap.get(b.id) ?? 0); + }); }); } diff --git a/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx b/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx index e986080c94c93..e8a26750febf6 100644 --- a/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx +++ b/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx @@ -12,9 +12,18 @@ import { downloadMultipleAs, ShareContext, ShareMenuProvider } from '@kbn/share- import { exporters } from '@kbn/data-plugin/public'; import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiDataGridColumnSortingConfig } from '@elastic/eui'; import { FormatFactory } from '../../../common/types'; import { TableInspectorAdapter } from '../../editor_frame_service/types'; +export interface CSVSharingData { + title: string; + activeData: TableInspectorAdapter; + csvEnabled: boolean; + sortedColumns?: string[]; + columnSorting?: EuiDataGridColumnSortingConfig[]; +} + declare global { interface Window { /** @@ -30,13 +39,15 @@ async function downloadCSVs({ title, formatFactory, uiSettings, - columnsSorting, + sortedColumns, + columnSorting, }: { title: string; activeData: TableInspectorAdapter; formatFactory: FormatFactory; uiSettings: IUiSettingsClient; - columnsSorting?: string[]; + sortedColumns?: string[]; + columnSorting?: EuiDataGridColumnSortingConfig[]; }) { if (!activeData) { if (window.ELASTIC_LENS_CSV_DOWNLOAD_DEBUG) { @@ -57,7 +68,8 @@ async function downloadCSVs({ quoteValues: uiSettings.get('csv:quoteValues', true), formatFactory, escapeFormulaValues: false, - columnsSorting, + columnSorting, + sortedColumns, }), type: exporters.CSV_MIME_TYPE, }; @@ -109,12 +121,9 @@ export const downloadCsvShareProvider = ({ return []; } - const { title, activeData, csvEnabled, columnsSorting } = sharingData as { - title: string; - activeData: TableInspectorAdapter; - csvEnabled: boolean; - columnsSorting?: string[]; - }; + // TODO fix sharingData types + const { title, activeData, csvEnabled, sortedColumns, columnSorting } = + sharingData as unknown as CSVSharingData; const panelTitle = i18n.translate( 'xpack.lens.reporting.shareContextMenu.csvReportsButtonLabel', @@ -138,7 +147,8 @@ export const downloadCsvShareProvider = ({ formatFactory: formatFactoryFn(), activeData, uiSettings, - columnsSorting, + sortedColumns, + columnSorting, }); return [ diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index da99d693539b8..6d4ecd64ae61c 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -598,11 +598,21 @@ export const LensTopNavMenu = ({ isCurrentStateDirty ); + const datasourceLayers = getDatasourceLayers( + datasourceStates, + datasourceMap, + dataViews.indexPatterns + ); + const sharingData = { activeData, - columnsSorting: visualizationMap[visualization.activeId].getSortedColumns?.( + sortedColumns: visualizationMap[visualization.activeId].getSortedColumns?.( + visualization.state, + datasourceLayers + ), + columnSorting: visualizationMap[visualization.activeId].getColumnSorting?.( visualization.state, - getDatasourceLayers(datasourceStates, datasourceMap, dataViews.indexPatterns) + datasourceLayers ), csvEnabled, reportingDisabled: !csvEnabled, diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index f4063747e9b77..ee4bb0c1098f7 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -38,7 +38,7 @@ import type { FieldSpec, DataViewSpec, DataView } from '@kbn/data-views-plugin/c import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { FieldFormatParams } from '@kbn/field-formats-plugin/common'; import type { SearchResponseWarning } from '@kbn/search-response-warnings'; -import type { EuiButtonIconProps } from '@elastic/eui'; +import type { EuiButtonIconProps, EuiDataGridColumnSortingConfig } from '@elastic/eui'; import { estypes } from '@elastic/elasticsearch'; import React from 'react'; import { CellValueContext } from '@kbn/embeddable-plugin/public'; @@ -1354,6 +1354,13 @@ export interface Visualization string[]; + /** + * A visualization can share how rows are sorted per column + */ + getColumnSorting?: ( + state: T, + datasourceLayers?: DatasourceLayers + ) => EuiDataGridColumnSortingConfig[]; /** * returns array of telemetry events for the visualization on save */ diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index 0187776985a30..743fdc355ab26 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -265,7 +265,7 @@ export const getDatatableVisualization = ({ getConfiguration({ state, frame }) { const isDarkMode = kibanaTheme.getTheme().darkMode; const { sortedColumns, datasource } = - getDataSourceAndSortedColumns(state, frame.datasourceLayers) || {}; + getDatasourceAndSortedColumns(state, frame.datasourceLayers) || {}; const columnMap: Record = {}; state.columns.forEach((column) => { @@ -497,7 +497,7 @@ export const getDatatableVisualization = ({ datasourceExpressionsByLayers = {} ): Ast | null { const { sortedColumns, datasource } = - getDataSourceAndSortedColumns(state, datasourceLayers) || {}; + getDatasourceAndSortedColumns(state, datasourceLayers) || {}; const isTextBasedLanguage = datasource?.isTextBasedLanguage(); if ( @@ -731,10 +731,22 @@ export const getDatatableVisualization = ({ }, getSortedColumns(state, datasourceLayers) { - const { sortedColumns } = getDataSourceAndSortedColumns(state, datasourceLayers || {}) || {}; + const { sortedColumns } = + getDatasourceAndSortedColumns(state, datasourceLayers || {}, true) || {}; return sortedColumns; }, + getColumnSorting(state) { + if (!state.sorting?.columnId || state.sorting.direction === 'none') return []; + + return [ + { + id: state.sorting.columnId, + direction: state.sorting.direction, + }, + ]; + }, + getVisualizationInfo(state) { const visibleMetricColumns = state.columns.filter( (c) => !c.hidden && c.colorMode && c.colorMode !== 'none' @@ -782,15 +794,21 @@ export const getDatatableVisualization = ({ }, }); -function getDataSourceAndSortedColumns( +function getDatasourceAndSortedColumns( state: DatatableVisualizationState, - datasourceLayers: DatasourceLayers + datasourceLayers: DatasourceLayers, + excludeHidden = false ) { + const columnMap = new Map(state.columns.map((c) => [c.columnId, c])); const datasource = datasourceLayers[state.layerId]; const originalOrder = datasource?.getTableSpec().map(({ columnId }) => columnId); // When we add a column it could be empty, and therefore have no order const sortedColumns = Array.from( new Set(originalOrder?.concat(state.columns.map(({ columnId }) => columnId))) - ); + ).flatMap((id) => { + const col = columnMap.get(id); + if (excludeHidden && col?.hidden) return []; + return [id]; + }); return { datasource, sortedColumns }; } From 515878702c3e0bb474cba22b6a8a61f779aa0ead Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Mon, 23 Sep 2024 11:54:06 -0500 Subject: [PATCH 04/17] improve inspect and export flow - Set transposed table as default selection in inspector - Export only transposed table on share - Remove unused prop-types --- .../components/data_table_selector.tsx | 9 +-------- .../table_inspector_view/components/data_view.tsx | 15 +++------------ .../expressions/common/util/tables_adapter.ts | 6 ++++-- .../common/expressions/datatable/datatable_fn.ts | 1 + .../csv_download_provider.tsx | 12 ++++++++++-- .../lens/public/app_plugin/lens_top_nav.tsx | 12 +++++++----- x-pack/plugins/lens/public/types.ts | 4 ++++ .../visualizations/datatable/visualization.tsx | 5 +++++ 8 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx index b9a0563da0aeb..566ea90c6727e 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_table_selector.tsx @@ -9,7 +9,6 @@ import React, { Component } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import PropTypes from 'prop-types'; import { EuiButtonEmpty, EuiContextMenuPanel, @@ -27,16 +26,10 @@ interface TableSelectorState { interface TableSelectorProps { tables: Datatable[]; selectedTable: Datatable; - onTableChanged: Function; + onTableChanged: (table: Datatable) => void; } export class TableSelector extends Component { - static propTypes = { - tables: PropTypes.array.isRequired, - selectedTable: PropTypes.object.isRequired, - onTableChanged: PropTypes.func, - }; - state = { isPopoverOpen: false, }; diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx index 365d53f1371b7..f67cd5293c139 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx @@ -8,7 +8,6 @@ */ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui'; @@ -35,15 +34,6 @@ interface DataViewComponentProps extends InspectorViewProps { } class DataViewComponent extends Component { - static propTypes = { - adapters: PropTypes.object.isRequired, - title: PropTypes.string.isRequired, - uiSettings: PropTypes.object, - uiActions: PropTypes.object.isRequired, - fieldFormats: PropTypes.object.isRequired, - isFilterable: PropTypes.func.isRequired, - }; - state = {} as DataViewComponentState; static getDerivedStateFromProps( @@ -54,9 +44,10 @@ class DataViewComponent extends Component tablesToShare.includes(id)) + .map(([, table]) => table); + const datatables = seletedDatatables.length > 0 ? seletedDatatables : Object.values(activeData); + const content = datatables.reduce>( (memo, datatable, i) => { // skip empty datatables @@ -122,7 +129,7 @@ export const downloadCsvShareProvider = ({ } // TODO fix sharingData types - const { title, activeData, csvEnabled, sortedColumns, columnSorting } = + const { title, activeData, csvEnabled, sortedColumns, columnSorting, tablesToShare } = sharingData as unknown as CSVSharingData; const panelTitle = i18n.translate( @@ -147,6 +154,7 @@ export const downloadCsvShareProvider = ({ formatFactory: formatFactoryFn(), activeData, uiSettings, + tablesToShare, sortedColumns, columnSorting, }); diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index 6d4ecd64ae61c..22d4a2a82e5c7 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -576,6 +576,8 @@ export const LensTopNavMenu = ({ return; } + const activeVisualization = visualizationMap[visualization.activeId]; + const { shareableUrl, savedObjectURL, @@ -606,14 +608,15 @@ export const LensTopNavMenu = ({ const sharingData = { activeData, - sortedColumns: visualizationMap[visualization.activeId].getSortedColumns?.( + sortedColumns: activeVisualization.getSortedColumns?.( visualization.state, datasourceLayers ), - columnSorting: visualizationMap[visualization.activeId].getColumnSorting?.( + columnSorting: activeVisualization.getColumnSorting?.( visualization.state, datasourceLayers ), + tablesToShare: activeVisualization.getTablesToShare?.(), csvEnabled, reportingDisabled: !csvEnabled, title: title || defaultLensTitle, @@ -623,9 +626,8 @@ export const LensTopNavMenu = ({ }, layout: { dimensions: - visualizationMap[visualization.activeId].getReportingLayout?.( - visualization.state - ) ?? DEFAULT_LENS_LAYOUT_DIMENSIONS, + activeVisualization.getReportingLayout?.(visualization.state) ?? + DEFAULT_LENS_LAYOUT_DIMENSIONS, }, }; diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index ee4bb0c1098f7..922e1a17cb707 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -1361,6 +1361,10 @@ export interface Visualization EuiDataGridColumnSortingConfig[]; + /** + * Table ids to export via csv, corresponding to the tables in inspector adapter + */ + getTablesToShare?: () => string[]; /** * returns array of telemetry events for the visualization on save */ diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index 743fdc355ab26..4f55cf86485c1 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -51,6 +51,7 @@ import { shouldColorByTerms, } from '../../shared_components'; import { getColorMappingTelemetryEvents } from '../../lens_ui_telemetry/color_telemetry_helpers'; +import { DatatableInspectorTables } from '../../../common/expressions/datatable/datatable_fn'; export interface DatatableVisualizationState { columns: ColumnState[]; layerId: string; @@ -747,6 +748,10 @@ export const getDatatableVisualization = ({ ]; }, + getTablesToShare() { + return [DatatableInspectorTables.Transpose]; + }, + getVisualizationInfo(state) { const visibleMetricColumns = state.columns.filter( (c) => !c.hidden && c.colorMode && c.colorMode !== 'none' From de71e9f1dce42bde0bc0b6224dd432bd5a3f03f4 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Mon, 23 Sep 2024 14:02:13 -0500 Subject: [PATCH 05/17] fix: filter out ghost columns in inspect created from formula metrics --- .../lens/common/expressions/datatable/datatable_fn.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts index 2bc1c05597db3..52e18bb6cda6e 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -64,7 +64,11 @@ export const datatableFn = transposeTable(args, table, formatters); if (context?.inspectorAdapters?.tables) { - context.inspectorAdapters.tables.logDatatable(DatatableInspectorTables.Transpose, table); + const exposedColumns = new Set(args.columns.map((c) => c.columnId)); + context.inspectorAdapters.tables.logDatatable(DatatableInspectorTables.Transpose, { + ...table, + columns: table.columns.filter((c) => exposedColumns.has(c.id)), // remove ghost formula columns + }); context.inspectorAdapters.tables.initialSelectedTable = DatatableInspectorTables.Transpose; } } From 131766611c68d9b83b35cccf3dd18f1575296f56 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Sun, 13 Oct 2024 12:48:58 -0500 Subject: [PATCH 06/17] Move transpose helpers into shared kbn package --- package.json | 1 + packages/kbn-transpose-helpers/README.md | 3 ++ .../kbn-transpose-helpers/index.test.ts | 14 ++++--- .../kbn-transpose-helpers/index.ts | 41 ++++++++++--------- packages/kbn-transpose-helpers/jest.config.js | 14 +++++++ packages/kbn-transpose-helpers/kibana.jsonc | 5 +++ packages/kbn-transpose-helpers/package.json | 6 +++ packages/kbn-transpose-helpers/tsconfig.json | 19 +++++++++ .../public/components/helpers.ts | 7 +--- tsconfig.base.json | 2 + .../expressions/datatable/datatable_fn.ts | 4 +- .../common/expressions/datatable/index.ts | 1 - .../common/expressions/datatable/summary.ts | 2 +- .../common/expressions/datatable/utils.ts | 2 +- .../public/datasources/form_based/utils.tsx | 2 +- .../shared_components/coloring/utils.ts | 7 +--- .../datatable/components/cell_value.test.tsx | 2 +- .../datatable/components/dimension_editor.tsx | 4 +- .../datatable/components/table_actions.ts | 2 +- .../datatable/components/table_basic.test.tsx | 2 +- .../datatable/components/table_basic.tsx | 6 +-- .../datatable/visualization.tsx | 4 +- yarn.lock | 4 ++ 23 files changed, 103 insertions(+), 51 deletions(-) create mode 100644 packages/kbn-transpose-helpers/README.md rename x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts => packages/kbn-transpose-helpers/index.test.ts (95%) rename x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts => packages/kbn-transpose-helpers/index.ts (89%) create mode 100644 packages/kbn-transpose-helpers/jest.config.js create mode 100644 packages/kbn-transpose-helpers/kibana.jsonc create mode 100644 packages/kbn-transpose-helpers/package.json create mode 100644 packages/kbn-transpose-helpers/tsconfig.json diff --git a/package.json b/package.json index f6412a3da925a..4390f8a2c95ab 100644 --- a/package.json +++ b/package.json @@ -943,6 +943,7 @@ "@kbn/tinymath": "link:packages/kbn-tinymath", "@kbn/transform-plugin": "link:x-pack/plugins/transform", "@kbn/translations-plugin": "link:x-pack/plugins/translations", + "@kbn/transpose-helpers": "link:packages/kbn-transpose-helpers", "@kbn/triggers-actions-ui-example-plugin": "link:x-pack/examples/triggers_actions_ui_example", "@kbn/triggers-actions-ui-plugin": "link:x-pack/plugins/triggers_actions_ui", "@kbn/triggers-actions-ui-types": "link:packages/kbn-triggers-actions-ui-types", diff --git a/packages/kbn-transpose-helpers/README.md b/packages/kbn-transpose-helpers/README.md new file mode 100644 index 0000000000000..10c6ca3668dbb --- /dev/null +++ b/packages/kbn-transpose-helpers/README.md @@ -0,0 +1,3 @@ +# @kbn/transpose-helpers + +Util functions used convert raw columns into transposed columns. diff --git a/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts b/packages/kbn-transpose-helpers/index.test.ts similarity index 95% rename from x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts rename to packages/kbn-transpose-helpers/index.test.ts index 35a96a5fd1524..62b5ddecfde70 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts +++ b/packages/kbn-transpose-helpers/index.test.ts @@ -1,17 +1,19 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import type { FieldFormat } from '@kbn/field-formats-plugin/common'; import type { Datatable } from '@kbn/expressions-plugin/common'; -import { DatatableArgs } from './datatable'; +import { DatatableArgs } from '@kbn/lens-plugin/common/expressions'; -import { transposeTable } from './transpose_helpers'; +import { transposeTable } from '.'; -describe('transpose_helpers', () => { +describe('transpose helpers', () => { function buildTable(): Datatable { // 3 buckets, 2 metrics // first bucket goes A/B/C diff --git a/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts b/packages/kbn-transpose-helpers/index.ts similarity index 89% rename from x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts rename to packages/kbn-transpose-helpers/index.ts index b639a52ee1b2b..198c23ea5e121 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts +++ b/packages/kbn-transpose-helpers/index.ts @@ -1,18 +1,31 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". */ import type { Datatable, DatatableColumn, DatatableRow } from '@kbn/expressions-plugin/common'; import type { FieldFormat } from '@kbn/field-formats-plugin/common'; -import type { DatatableArgs } from './datatable'; -import type { DatatableColumnConfig, DatatableColumnArgs } from './datatable_column'; +import { + DatatableArgs, + DatatableColumnArgs, + DatatableColumnConfig, +} from '@kbn/lens-plugin/common/expressions'; -const TRANSPOSE_SEPARATOR = '---'; +/** + * Used to delimitate felids of a transposed column id + */ +export const TRANSPOSE_SEPARATOR = '---'; -const TRANSPOSE_VISUAL_SEPARATOR = '›'; +/** + * Visual deliminator between felids of a transposed column id + * + * Meant to align with the `MULTI_FIELD_KEY_SEPARATOR` from the data plugin + */ +export const TRANSPOSE_VISUAL_SEPARATOR = '›'; export function getTransposeId(value: string, columnId: string) { return `${value}${TRANSPOSE_SEPARATOR}${columnId}`; @@ -34,16 +47,12 @@ export function getOriginalId(id: string) { * Transposes the columns of the given table as defined in the arguments. * This function modifies the passed in args and firstTable objects. * This process consists out of three parts: + * * * Calculating the new column arguments * * Calculating the new datatable columns * * Calculating the new rows * - * If the table is tranposed by multiple columns, this process is repeated on top of the previous transformation. - * - * @internal - * @param args Arguments for the table visualization - * @param firstTable datatable object containing the actual data - * @param formatters Formatters for all columns to transpose columns by actual display values + * If the table is transposed by multiple columns, this process is repeated on top of the previous transformation. */ export function transposeTable( args: DatatableArgs, @@ -135,9 +144,6 @@ function updateColumnArgs( /** * Finds all unique values in a column in order of first occurence - * @param table Table to search through - * @param formatter formatter for the column - * @param columnId column */ function getUniqueValues(table: Datatable, formatter: FieldFormat, columnId: string) { const values = new Map(); @@ -153,9 +159,6 @@ function getUniqueValues(table: Datatable, formatter: FieldFormat, columnId: str /** * Calculate transposed column objects of the datatable object and puts them into the datatable. * Returns args for additional columns grouped by metric - * @param metricColumns - * @param firstTable - * @param uniqueValues */ function transposeColumns( args: DatatableArgs, diff --git a/packages/kbn-transpose-helpers/jest.config.js b/packages/kbn-transpose-helpers/jest.config.js new file mode 100644 index 0000000000000..2502e9598e081 --- /dev/null +++ b/packages/kbn-transpose-helpers/jest.config.js @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-transpose-helpers'], +}; diff --git a/packages/kbn-transpose-helpers/kibana.jsonc b/packages/kbn-transpose-helpers/kibana.jsonc new file mode 100644 index 0000000000000..f0d71b07fea3a --- /dev/null +++ b/packages/kbn-transpose-helpers/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/transpose-helpers", + "owner": "@elastic/kibana-visualizations" +} diff --git a/packages/kbn-transpose-helpers/package.json b/packages/kbn-transpose-helpers/package.json new file mode 100644 index 0000000000000..80f9a981a4650 --- /dev/null +++ b/packages/kbn-transpose-helpers/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/transpose-helpers", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" +} \ No newline at end of file diff --git a/packages/kbn-transpose-helpers/tsconfig.json b/packages/kbn-transpose-helpers/tsconfig.json new file mode 100644 index 0000000000000..dad708677fd87 --- /dev/null +++ b/packages/kbn-transpose-helpers/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts index 0e115a770a040..ac8af6c4af2c3 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts @@ -18,6 +18,7 @@ import { DEFAULT_MAX_STOP, DEFAULT_MIN_STOP, } from '@kbn/coloring'; +import { getOriginalId } from '@kbn/transpose-helpers'; import type { Datatable, DatatableColumn } from '@kbn/expressions-plugin/public'; import { FormatFactory, IFieldFormat } from '@kbn/field-formats-plugin/common'; @@ -94,11 +95,7 @@ export function getNumericValue(rowValue: number | number[] | undefined) { return rowValue; } -export const findMinMaxByColumnId = ( - columnIds: string[], - table: Datatable | undefined, - getOriginalId: (id: string) => string = getId -) => { +export const findMinMaxByColumnId = (columnIds: string[], table: Datatable | undefined) => { const minMax: Record = {}; if (table != null) { diff --git a/tsconfig.base.json b/tsconfig.base.json index 12df74345a444..3158a164c408e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1876,6 +1876,8 @@ "@kbn/transform-plugin/*": ["x-pack/plugins/transform/*"], "@kbn/translations-plugin": ["x-pack/plugins/translations"], "@kbn/translations-plugin/*": ["x-pack/plugins/translations/*"], + "@kbn/transpose-helpers": ["packages/kbn-transpose-helpers"], + "@kbn/transpose-helpers/*": ["packages/kbn-transpose-helpers/*"], "@kbn/triggers-actions-ui-example-plugin": ["x-pack/examples/triggers_actions_ui_example"], "@kbn/triggers-actions-ui-example-plugin/*": ["x-pack/examples/triggers_actions_ui_example/*"], "@kbn/triggers-actions-ui-plugin": ["x-pack/plugins/triggers_actions_ui"], diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts index 52e18bb6cda6e..72b8150cf8d14 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -7,10 +7,10 @@ import { cloneDeep } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { transposeTable } from '@kbn/transpose-helpers'; import { prepareLogTable } from '@kbn/visualizations-plugin/common/utils'; import type { Datatable, ExecutionContext } from '@kbn/expressions-plugin/common'; import { FormatFactory } from '../../types'; -import { transposeTable } from './transpose_helpers'; import { computeSummaryRowForColumn } from './summary'; import type { DatatableExpressionFunction } from './types'; @@ -60,7 +60,7 @@ export const datatableFn = if (hasTransposedColumns) { // store original shape of data separately untransposedData = cloneDeep(table); - // transposes table and args inplace + // transposes table and args in-place transposeTable(args, table, formatters); if (context?.inspectorAdapters?.tables) { diff --git a/x-pack/plugins/lens/common/expressions/datatable/index.ts b/x-pack/plugins/lens/common/expressions/datatable/index.ts index 4b27aa90d5190..7003fd8d486b8 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/index.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/index.ts @@ -7,6 +7,5 @@ export * from './datatable_column'; export * from './datatable'; -export { isTransposeId, getOriginalId } from './transpose_helpers'; export type { DatatableProps, DatatableExpressionFunction } from './types'; diff --git a/x-pack/plugins/lens/common/expressions/datatable/summary.ts b/x-pack/plugins/lens/common/expressions/datatable/summary.ts index f4ae186fc1d2f..497d0724c9b8d 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/summary.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/summary.ts @@ -8,8 +8,8 @@ import { i18n } from '@kbn/i18n'; import type { FieldFormat } from '@kbn/field-formats-plugin/common'; import type { Datatable } from '@kbn/expressions-plugin/common'; +import { getOriginalId } from '@kbn/transpose-helpers'; import { DatatableColumnArgs } from './datatable_column'; -import { getOriginalId } from './transpose_helpers'; import { isNumericFieldForDatatable } from './utils'; type SummaryRowType = Extract; diff --git a/x-pack/plugins/lens/common/expressions/datatable/utils.ts b/x-pack/plugins/lens/common/expressions/datatable/utils.ts index bc617d931f500..4bbd73e794621 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/utils.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/utils.ts @@ -6,7 +6,7 @@ */ import { type Datatable, type DatatableColumnMeta } from '@kbn/expressions-plugin/common'; -import { getOriginalId } from './transpose_helpers'; +import { getOriginalId } from '@kbn/transpose-helpers'; /** * Returns true for numerical fields diff --git a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx index d9216f2a56d85..8178f48f5a50e 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx @@ -25,6 +25,7 @@ import { import { estypes } from '@elastic/elasticsearch'; import { isQueryValid } from '@kbn/visualization-ui-components'; +import { getOriginalId } from '@kbn/transpose-helpers'; import type { DateRange } from '../../../common/types'; import type { FramePublicAPI, @@ -60,7 +61,6 @@ import { hasField } from './pure_utils'; import { mergeLayer } from './state_helpers'; import { supportsRarityRanking } from './operations/definitions/terms'; import { DEFAULT_MAX_DOC_COUNT } from './operations/definitions/terms/constants'; -import { getOriginalId } from '../../../common/expressions/datatable/transpose_helpers'; import { ReducedSamplingSectionEntries } from './info_badges'; import { IgnoredGlobalFiltersEntries } from '../../shared_components/ignore_global_filter'; import { diff --git a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts index c58fec1ddb03e..09424ebb795d1 100644 --- a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts +++ b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts @@ -21,6 +21,7 @@ import { getColorsFromMapping, DEFAULT_FALLBACK_PALETTE, } from '@kbn/coloring'; +import { getOriginalId } from '@kbn/transpose-helpers'; import { Datatable, DatatableColumnType } from '@kbn/expressions-plugin/common'; import { DataType } from '../../types'; @@ -90,11 +91,7 @@ export function applyPaletteParams> return displayStops; } -export const findMinMaxByColumnId = ( - columnIds: string[], - table: Datatable | undefined, - getOriginalId: (id: string) => string = (id: string) => id -) => { +export const findMinMaxByColumnId = (columnIds: string[], table: Datatable | undefined) => { const minMaxMap = new Map(); if (table != null) { diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx index e9f3caba9ec05..f55a424c78282 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx @@ -8,12 +8,12 @@ import React from 'react'; import { DataContext } from './table_basic'; import { createGridCell } from './cell_value'; +import { getTransposeId } from '@kbn/transpose-helpers'; import type { FieldFormat } from '@kbn/field-formats-plugin/common'; import { Datatable } from '@kbn/expressions-plugin/public'; import { DatatableArgs } from '../../../../common/expressions'; import { DataContextType } from './types'; import { render, screen } from '@testing-library/react'; -import { getTransposeId } from '../../../../common/expressions/datatable/transpose_helpers'; describe('datatable cell renderer', () => { const innerCellColorFnMock = jest.fn().mockReturnValue('blue'); diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx index 99fe3cc1c164e..ec23952f29009 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx @@ -11,6 +11,7 @@ import { EuiFormRow, EuiSwitch, EuiButtonGroup, htmlIdGenerator } from '@elastic import { PaletteRegistry, getFallbackDataBounds } from '@kbn/coloring'; import { getColorCategories } from '@kbn/chart-expressions-common'; import { useDebouncedValue } from '@kbn/visualization-utils'; +import { getOriginalId } from '@kbn/transpose-helpers'; import type { VisualizationDimensionEditorProps } from '../../../types'; import type { DatatableVisualizationState } from '../visualization'; @@ -20,7 +21,6 @@ import { findMinMaxByColumnId, shouldColorByTerms, } from '../../../shared_components'; -import { getOriginalId } from '../../../../common/expressions/datatable/transpose_helpers'; import './dimension_editor.scss'; import { CollapseSetting } from '../../../shared_components/collapse_setting'; @@ -94,7 +94,7 @@ export function TableDimensionEditor(props: TableDimensionEditorProps) { ? currentData?.columns.filter(({ id }) => getOriginalId(id) === accessor).map(({ id }) => id) || [] : [accessor]; - const minMaxByColumnId = findMinMaxByColumnId(columnsToCheck, currentData, getOriginalId); + const minMaxByColumnId = findMinMaxByColumnId(columnsToCheck, currentData); const currentMinMax = minMaxByColumnId.get(accessor) ?? getFallbackDataBounds(); const activePalette = column?.palette ?? { diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts b/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts index e53713069fb8f..41d5096baf526 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts @@ -18,9 +18,9 @@ import type { import { ClickTriggerEvent } from '@kbn/charts-plugin/public'; import { getSortingCriteria } from '@kbn/sort-predicates'; import { i18n } from '@kbn/i18n'; +import { getOriginalId } from '@kbn/transpose-helpers'; import type { LensResizeAction, LensSortAction, LensToggleAction } from './types'; import type { DatatableColumnConfig, LensGridDirection } from '../../../../common/expressions'; -import { getOriginalId } from '../../../../common/expressions/datatable/transpose_helpers'; import type { FormatFactory } from '../../../../common/types'; import { buildColumnsMetaLookup } from './helpers'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx index 2358b9ec5b563..faf535819120a 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx @@ -20,9 +20,9 @@ import type { DatatableProps } from '../../../../common/expressions'; import { LENS_EDIT_PAGESIZE_ACTION } from './constants'; import { DatatableRenderProps } from './types'; import { PaletteOutput } from '@kbn/coloring'; +import { getTransposeId } from '@kbn/transpose-helpers'; import { CustomPaletteState } from '@kbn/charts-plugin/common'; import { getCellColorFn } from '../../../shared_components/coloring/get_cell_color_fn'; -import { getTransposeId } from '../../../../common/expressions/datatable/transpose_helpers'; jest.mock('../../../shared_components/coloring/get_cell_color_fn', () => { const mod = jest.requireActual('../../../shared_components/coloring/get_cell_color_fn'); diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx index 55e198b943e81..9f820ecdc79b0 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx @@ -32,10 +32,11 @@ import { ClickTriggerEvent } from '@kbn/charts-plugin/public'; import { IconChartDatatable } from '@kbn/chart-icons'; import useObservable from 'react-use/lib/useObservable'; import { getColorCategories } from '@kbn/chart-expressions-common'; +import { getOriginalId, isTransposeId } from '@kbn/transpose-helpers'; import type { LensTableRowContextMenuEvent } from '../../../types'; import type { FormatFactory } from '../../../../common/types'; import { RowHeightMode } from '../../../../common/types'; -import { getOriginalId, isTransposeId, LensGridDirection } from '../../../../common/expressions'; +import { LensGridDirection } from '../../../../common/expressions'; import { VisualizationContainer } from '../../../visualization_container'; import { findMinMaxByColumnId, shouldColorByTerms } from '../../../shared_components'; import type { @@ -288,8 +289,7 @@ export const DatatableComponent = (props: DatatableRenderProps) => { columnConfig.columns .filter(({ columnId }) => isNumericMap.get(columnId)) .map(({ columnId }) => columnId), - props.data, - getOriginalId + props.data ); }, [props.data, isNumericMap, columnConfig]); diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index ced8c750730d7..42ac3dab8acd7 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -12,6 +12,7 @@ import { PaletteRegistry, CUSTOM_PALETTE, PaletteOutput, CustomPaletteParams } f import { ThemeServiceStart } from '@kbn/core/public'; import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public'; import { IconChartDatatable } from '@kbn/chart-icons'; +import { getOriginalId } from '@kbn/transpose-helpers'; import { LayerTypes } from '@kbn/expression-xy-plugin/public'; import { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugin/common'; import useObservable from 'react-use/lib/useObservable'; @@ -35,7 +36,6 @@ import { type CollapseExpressionFunction, type DatatableColumnFn, type DatatableExpressionFunction, - getOriginalId, } from '../../../common/expressions'; import { DataTableToolbar } from './components/toolbar'; import { @@ -147,7 +147,7 @@ export const getDatatableVisualization = ({ .filter(({ id }) => getOriginalId(id) === accessor) .map(({ id }) => id) || [] : [accessor]; - const minMaxByColumnId = findMinMaxByColumnId(columnsToCheck, currentData, getOriginalId); + const minMaxByColumnId = findMinMaxByColumnId(columnsToCheck, currentData); const dataBounds = minMaxByColumnId.get(accessor); if (palette && !showColorByTerms && !palette?.canDynamicColoring && dataBounds) { const newPalette: PaletteOutput = { diff --git a/yarn.lock b/yarn.lock index e7042d208b96d..279da6cd63081 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7047,6 +7047,10 @@ version "0.0.0" uid "" +"@kbn/transpose-helpers@link:packages/kbn-transpose-helpers": + version "0.0.0" + uid "" + "@kbn/triggers-actions-ui-example-plugin@link:x-pack/examples/triggers_actions_ui_example": version "0.0.0" uid "" From dfc222168209df1b7acb6d9ebeabc49e7d4def21 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Sun, 13 Oct 2024 15:11:02 -0500 Subject: [PATCH 07/17] cleanup columns sorting logic - used sorted column order from state - use column order from transposed table via activeData - remove transpose logic from csv export logic - use prepareLogTable to strip out ghost columns ids from formulas --- .../data/common/exports/export_csv.tsx | 22 +++---------- .../expressions/datatable/datatable_fn.ts | 22 ++++++++++--- .../lens/public/app_plugin/lens_top_nav.tsx | 3 +- x-pack/plugins/lens/public/types.ts | 11 +++++-- .../datatable/visualization.tsx | 33 ++++++++++--------- 5 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/plugins/data/common/exports/export_csv.tsx b/src/plugins/data/common/exports/export_csv.tsx index 0547cd8ec36ac..368a2f89f23bb 100644 --- a/src/plugins/data/common/exports/export_csv.tsx +++ b/src/plugins/data/common/exports/export_csv.tsx @@ -23,6 +23,10 @@ interface CSVOptions { escapeFormulaValues: boolean; formatFactory: FormatFactory; raw?: boolean; + /** Order of exported columns. Should use transposed column ids if available. + * + * Defaults to order of columns in state + */ sortedColumns?: string[]; columnSorting?: EuiDataGridColumnSortingConfig[]; } @@ -45,23 +49,7 @@ export function datatableToCSV( escapeFormulaValues, }); - const sortedIds = sortedColumns - ? columns - .map((c) => { - // need to find original id for transposed column - const sortIndex = sortedColumns.findIndex((id) => c.id.endsWith(id)); - return { - id: c.id, - sortIndex, - isTransposed: (sortedColumns[sortIndex] ?? '') !== c.id, - }; - }) - .filter(({ sortIndex }) => sortIndex >= 0) - // keep original zipped order between multiple transposed columns - .sort((a, b) => (a.isTransposed && b.isTransposed ? 0 : a.sortIndex - b.sortIndex)) - .map(({ id }) => id) - : columns.map(({ id }) => id); - + const sortedIds = sortedColumns || columns.map((col) => col.id); const columnIndexLookup = new Map(sortedIds.map((id, i) => [id, i])); const header: string[] = []; diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts index 72b8150cf8d14..67bea7ece66f8 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -64,11 +64,23 @@ export const datatableFn = transposeTable(args, table, formatters); if (context?.inspectorAdapters?.tables) { - const exposedColumns = new Set(args.columns.map((c) => c.columnId)); - context.inspectorAdapters.tables.logDatatable(DatatableInspectorTables.Transpose, { - ...table, - columns: table.columns.filter((c) => exposedColumns.has(c.id)), // remove ghost formula columns - }); + const logTransposedTable = prepareLogTable( + table, + [ + [ + args.columns.map((column) => column.columnId), + i18n.translate('xpack.lens.datatable.column.help', { + defaultMessage: 'Datatable column', + }), + ], + ], + true + ); + + context.inspectorAdapters.tables.logDatatable( + DatatableInspectorTables.Transpose, + logTransposedTable + ); context.inspectorAdapters.tables.initialSelectedTable = DatatableInspectorTables.Transpose; } } diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index 22d4a2a82e5c7..0fad28c66c4f6 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -610,7 +610,8 @@ export const LensTopNavMenu = ({ activeData, sortedColumns: activeVisualization.getSortedColumns?.( visualization.state, - datasourceLayers + datasourceLayers, + activeData ), columnSorting: activeVisualization.getColumnSorting?.( visualization.state, diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 922e1a17cb707..5b46bfa52a31d 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -64,6 +64,7 @@ import type { LensInspector } from './lens_inspector_service'; import type { DataViewsState } from './state_management/types'; import type { IndexPatternServiceAPI } from './data_views_service/service'; import type { Document } from './persistence/saved_object_store'; +import { TableInspectorAdapter } from './editor_frame_service/types'; export type StartServices = Pick< CoreStart, @@ -1351,11 +1352,15 @@ export interface Visualization { height: number; width: number }; /** - * A visualization can share how columns are visually sorted + * Set the order of columns when exporting to csv */ - getSortedColumns?: (state: T, datasourceLayers?: DatasourceLayers) => string[]; + getSortedColumns?: ( + state: T, + datasourceLayers?: DatasourceLayers, + activeData?: TableInspectorAdapter + ) => string[]; /** - * A visualization can share how rows are sorted per column + * Set the row ordering of columns when exporting to csv */ getColumnSorting?: ( state: T, diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index 42ac3dab8acd7..9db4cd6aaba23 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -265,8 +265,10 @@ export const getDatatableVisualization = ({ **/ getConfiguration({ state, frame }) { const isDarkMode = kibanaTheme.getTheme().darkMode; - const { sortedColumns, datasource } = - getDatasourceAndSortedColumns(state, frame.datasourceLayers) || {}; + const { sortedColumns, datasource } = getDatasourceAndSortedColumns( + state, + frame.datasourceLayers + ); const columnMap: Record = {}; state.columns.forEach((column) => { @@ -497,8 +499,7 @@ export const getDatatableVisualization = ({ { title, description } = {}, datasourceExpressionsByLayers = {} ): Ast | null { - const { sortedColumns, datasource } = - getDatasourceAndSortedColumns(state, datasourceLayers) || {}; + const { sortedColumns, datasource } = getDatasourceAndSortedColumns(state, datasourceLayers); const isTextBasedLanguage = datasource?.isTextBasedLanguage(); if ( @@ -731,10 +732,15 @@ export const getDatatableVisualization = ({ return suggestion; }, - getSortedColumns(state, datasourceLayers) { - const { sortedColumns } = - getDatasourceAndSortedColumns(state, datasourceLayers || {}, true) || {}; - return sortedColumns; + getSortedColumns(state, datasourceLayers = {}, activeData) { + const columnMap = new Map(state.columns.map((c) => [c.columnId, c])); + const { columns } = + activeData?.[DatatableInspectorTables.Transpose] ?? + activeData?.[DatatableInspectorTables.Default] ?? + {}; + const columnIds = columns?.map(({ id }) => id) ?? [...columnMap.keys()]; + + return columnIds.filter((id) => !columnMap.get(getOriginalId(id))?.hidden); }, getColumnSorting(state) { @@ -801,19 +807,14 @@ export const getDatatableVisualization = ({ function getDatasourceAndSortedColumns( state: DatatableVisualizationState, - datasourceLayers: DatasourceLayers, - excludeHidden = false + datasourceLayers: DatasourceLayers ) { - const columnMap = new Map(state.columns.map((c) => [c.columnId, c])); const datasource = datasourceLayers[state.layerId]; const originalOrder = datasource?.getTableSpec().map(({ columnId }) => columnId); // When we add a column it could be empty, and therefore have no order const sortedColumns = Array.from( new Set(originalOrder?.concat(state.columns.map(({ columnId }) => columnId))) - ).flatMap((id) => { - const col = columnMap.get(id); - if (excludeHidden && col?.hidden) return []; - return [id]; - }); + ); + return { datasource, sortedColumns }; } From 44baf770e2d1e31ee54df6c5fd07448839f5b8ac Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Mon, 14 Oct 2024 17:40:24 -0500 Subject: [PATCH 08/17] cleanup csv sorting logic, now we directly pass all tables to be exported to the csv export utility - move column & row sorting into vis definition - use `@kbn/sort-predicates` to sort rows - remove sorted columns logic - remove column sorting logic --- .../data/common/exports/export_csv.tsx | 69 ++++--------------- .../csv_download_provider.tsx | 45 ++++-------- .../lens/public/app_plugin/lens_top_nav.tsx | 16 ++--- x-pack/plugins/lens/public/types.ts | 19 ++--- .../datatable/components/table_actions.ts | 6 +- .../public/visualizations/datatable/index.ts | 1 + .../datatable/visualization.tsx | 50 +++++++++----- 7 files changed, 73 insertions(+), 133 deletions(-) diff --git a/src/plugins/data/common/exports/export_csv.tsx b/src/plugins/data/common/exports/export_csv.tsx index 368a2f89f23bb..477ff2a36641e 100644 --- a/src/plugins/data/common/exports/export_csv.tsx +++ b/src/plugins/data/common/exports/export_csv.tsx @@ -7,11 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -// Inspired by the inspector CSV exporter - import { Datatable } from '@kbn/expressions-plugin/common'; import { FormatFactory } from '@kbn/field-formats-plugin/common'; -import { EuiDataGridColumnSortingConfig } from '@elastic/eui'; import { createEscapeValue } from './escape_value'; export const LINE_FEED_CHARACTER = '\r\n'; @@ -23,25 +20,11 @@ interface CSVOptions { escapeFormulaValues: boolean; formatFactory: FormatFactory; raw?: boolean; - /** Order of exported columns. Should use transposed column ids if available. - * - * Defaults to order of columns in state - */ - sortedColumns?: string[]; - columnSorting?: EuiDataGridColumnSortingConfig[]; } export function datatableToCSV( { columns, rows }: Datatable, - { - csvSeparator, - quoteValues, - formatFactory, - raw, - escapeFormulaValues, - sortedColumns, - columnSorting, - }: CSVOptions + { csvSeparator, quoteValues, formatFactory, raw, escapeFormulaValues }: CSVOptions ) { const escapeValues = createEscapeValue({ separator: csvSeparator, @@ -49,57 +32,29 @@ export function datatableToCSV( escapeFormulaValues, }); - const sortedIds = sortedColumns || columns.map((col) => col.id); - const columnIndexLookup = new Map(sortedIds.map((id, i) => [id, i])); - const header: string[] = []; const sortedColumnIds: string[] = []; const formatters: Record> = {}; - for (const column of columns) { - const columnIndex = columnIndexLookup.get(column.id) ?? -1; - if (columnIndex < 0) continue; // hidden or not found - - header[columnIndex] = escapeValues(column.name); - sortedColumnIds[columnIndex] = column.id; + columns.forEach((column, i) => { + header[i] = escapeValues(column.name); + sortedColumnIds[i] = column.id; formatters[column.id] = formatFactory(column.meta?.params); - } + }); if (header.length === 0) { return ''; } // Convert the array of row objects to an array of row arrays - const csvRows = rows - .map((row) => { - return sortedColumnIds.map((id) => - escapeValues(raw ? row[id] : formatters[id].convert(row[id])) - ); - }) - .sort(rowSortPredicate(sortedColumnIds, columnSorting)); + const csvRows = rows.map((row) => { + return sortedColumnIds.map((id) => + escapeValues(raw ? row[id] : formatters[id].convert(row[id])) + ); + }); return ( [header, ...csvRows].map((row) => row.join(csvSeparator)).join(LINE_FEED_CHARACTER) + - LINE_FEED_CHARACTER - ); // Add \r\n after last line -} - -function rowSortPredicate( - sortedColumnIds: string[], - columnSorting?: EuiDataGridColumnSortingConfig[] -) { - if (!columnSorting) return () => 0; - - const columnIdMap = new Map(columnSorting.map(({ id }) => [id, sortedColumnIds.indexOf(id)])); - return (rowA: string[], rowB: string[]) => { - return columnSorting.reduce((acc, { id, direction }) => { - const i = columnIdMap.get(id) ?? -1; - if (i < 0) return acc; - - const a = rowA[i]; - const b = rowB[i]; - const emptyValueSort = a === '' ? 1 : b === '' ? -1 : 0; // always put empty values at bottom - return acc || emptyValueSort || a.localeCompare(b) * (direction === 'asc' ? 1 : -1); - }, 0); - }; + LINE_FEED_CHARACTER // Add \r\n after last line + ); } diff --git a/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx b/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx index 77d77deaa9738..657c75acd58ea 100644 --- a/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx +++ b/x-pack/plugins/lens/public/app_plugin/csv_download_provider/csv_download_provider.tsx @@ -12,17 +12,13 @@ import { downloadMultipleAs, ShareContext, ShareMenuProvider } from '@kbn/share- import { exporters } from '@kbn/data-plugin/public'; import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiDataGridColumnSortingConfig } from '@elastic/eui'; +import type { Datatable } from '@kbn/expressions-plugin/common'; import { FormatFactory } from '../../../common/types'; -import { TableInspectorAdapter } from '../../editor_frame_service/types'; export interface CSVSharingData { title: string; - activeData: TableInspectorAdapter; + datatables: Datatable[]; csvEnabled: boolean; - tablesToShare?: string[]; - sortedColumns?: string[]; - columnSorting?: EuiDataGridColumnSortingConfig[]; } declare global { @@ -36,32 +32,20 @@ declare global { } async function downloadCSVs({ - activeData, title, + datatables, formatFactory, uiSettings, - tablesToShare = [], - sortedColumns, - columnSorting, }: { - title: string; - activeData: TableInspectorAdapter; formatFactory: FormatFactory; uiSettings: IUiSettingsClient; - tablesToShare?: string[]; - sortedColumns?: string[]; - columnSorting?: EuiDataGridColumnSortingConfig[]; -}) { - if (!activeData) { +} & Pick) { + if (datatables.length === 0) { if (window.ELASTIC_LENS_CSV_DOWNLOAD_DEBUG) { window.ELASTIC_LENS_CSV_CONTENT = undefined; } return; } - const seletedDatatables = Object.entries(activeData) - .filter(([id]) => tablesToShare.includes(id)) - .map(([, table]) => table); - const datatables = seletedDatatables.length > 0 ? seletedDatatables : Object.values(activeData); const content = datatables.reduce>( (memo, datatable, i) => { @@ -75,8 +59,6 @@ async function downloadCSVs({ quoteValues: uiSettings.get('csv:quoteValues', true), formatFactory, escapeFormulaValues: false, - columnSorting, - sortedColumns, }), type: exporters.CSV_MIME_TYPE, }; @@ -85,18 +67,19 @@ async function downloadCSVs({ }, {} ); + if (window.ELASTIC_LENS_CSV_DOWNLOAD_DEBUG) { window.ELASTIC_LENS_CSV_CONTENT = content; } + if (content) { downloadMultipleAs(content); } } -function getWarnings(activeData: TableInspectorAdapter) { +function getWarnings(datatables: Datatable[]) { const messages: string[] = []; - if (activeData) { - const datatables = Object.values(activeData); + if (datatables.length > 0) { const formulaDetected = datatables.some((datatable) => { return tableHasFormulas(datatable.columns, datatable.rows); }); @@ -129,8 +112,7 @@ export const downloadCsvShareProvider = ({ } // TODO fix sharingData types - const { title, activeData, csvEnabled, sortedColumns, columnSorting, tablesToShare } = - sharingData as unknown as CSVSharingData; + const { title, datatables, csvEnabled } = sharingData as unknown as CSVSharingData; const panelTitle = i18n.translate( 'xpack.lens.reporting.shareContextMenu.csvReportsButtonLabel', @@ -152,11 +134,8 @@ export const downloadCsvShareProvider = ({ downloadCSVs({ title, formatFactory: formatFactoryFn(), - activeData, + datatables, uiSettings, - tablesToShare, - sortedColumns, - columnSorting, }); return [ @@ -182,7 +161,7 @@ export const downloadCsvShareProvider = ({ } : { isDisabled: !csvEnabled, - warnings: getWarnings(activeData), + warnings: getWarnings(datatables), helpText: ( 0 ? exportDatatables : Object.values(activeData ?? {}); + const sharingData = { + datatables, csvEnabled, reportingDisabled: !csvEnabled, title: title || defaultLensTitle, diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 5b46bfa52a31d..41df522c36087 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -38,7 +38,7 @@ import type { FieldSpec, DataViewSpec, DataView } from '@kbn/data-views-plugin/c import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { FieldFormatParams } from '@kbn/field-formats-plugin/common'; import type { SearchResponseWarning } from '@kbn/search-response-warnings'; -import type { EuiButtonIconProps, EuiDataGridColumnSortingConfig } from '@elastic/eui'; +import type { EuiButtonIconProps } from '@elastic/eui'; import { estypes } from '@elastic/elasticsearch'; import React from 'react'; import { CellValueContext } from '@kbn/embeddable-plugin/public'; @@ -1352,24 +1352,13 @@ export interface Visualization { height: number; width: number }; /** - * Set the order of columns when exporting to csv + * Get all datatables to be exported as csv */ - getSortedColumns?: ( + getExportDatatables?: ( state: T, datasourceLayers?: DatasourceLayers, activeData?: TableInspectorAdapter - ) => string[]; - /** - * Set the row ordering of columns when exporting to csv - */ - getColumnSorting?: ( - state: T, - datasourceLayers?: DatasourceLayers - ) => EuiDataGridColumnSortingConfig[]; - /** - * Table ids to export via csv, corresponding to the tables in inspector adapter - */ - getTablesToShare?: () => string[]; + ) => Datatable[]; /** * returns array of telemetry events for the visualization on save */ diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts b/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts index 41d5096baf526..4fbcafa92f21d 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts @@ -168,6 +168,10 @@ function isRange(meta: { params?: { id?: string } } | undefined) { return meta?.params?.id === 'range'; } +export function getSimpleColumnType(meta?: DatatableColumnMeta) { + return isRange(meta) ? 'range' : meta?.type; +} + function getColumnType({ columnConfig, columnId, @@ -185,7 +189,7 @@ function getColumnType({ >; }) { const sortingHint = columnConfig.columns.find((col) => col.columnId === columnId)?.sortingHint; - return sortingHint ?? (isRange(lookup[columnId]?.meta) ? 'range' : lookup[columnId]?.meta?.type); + return sortingHint ?? getSimpleColumnType(lookup[columnId]?.meta); } export const buildSchemaDetectors = ( diff --git a/x-pack/plugins/lens/public/visualizations/datatable/index.ts b/x-pack/plugins/lens/public/visualizations/datatable/index.ts index 93e5e38e03c3c..6261b8c3dde45 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/index.ts +++ b/x-pack/plugins/lens/public/visualizations/datatable/index.ts @@ -48,6 +48,7 @@ export class DatatableVisualization { return getDatatableVisualization({ paletteService: palettes, kibanaTheme: core.theme, + formatFactory, }); }); } diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index 9db4cd6aaba23..b8241ca36d07b 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -16,6 +16,7 @@ import { getOriginalId } from '@kbn/transpose-helpers'; import { LayerTypes } from '@kbn/expression-xy-plugin/public'; import { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugin/common'; import useObservable from 'react-use/lib/useObservable'; +import { getSortingCriteria } from '@kbn/sort-predicates'; import type { FormBasedPersistedState } from '../../datasources/form_based/types'; import type { SuggestionRequest, @@ -26,7 +27,7 @@ import type { } from '../../types'; import { TableDimensionDataExtraEditor, TableDimensionEditor } from './components/dimension_editor'; import { TableDimensionEditorAdditionalSection } from './components/dimension_editor_addtional_section'; -import type { LayerType } from '../../../common/types'; +import type { FormatFactory, LayerType } from '../../../common/types'; import { RowHeightMode } from '../../../common/types'; import { getDefaultSummaryLabel } from '../../../common/expressions/datatable/summary'; import { @@ -52,6 +53,7 @@ import { } from '../../shared_components'; import { getColorMappingTelemetryEvents } from '../../lens_ui_telemetry/color_telemetry_helpers'; import { DatatableInspectorTables } from '../../../common/expressions/datatable/datatable_fn'; +import { getSimpleColumnType } from './components/table_actions'; export interface DatatableVisualizationState { columns: ColumnState[]; layerId: string; @@ -71,9 +73,11 @@ const visualizationLabel = i18n.translate('xpack.lens.datatable.label', { export const getDatatableVisualization = ({ paletteService, kibanaTheme, + formatFactory, }: { paletteService: PaletteRegistry; kibanaTheme: ThemeServiceStart; + formatFactory: FormatFactory; }): Visualization => ({ id: 'lnsDatatable', @@ -732,32 +736,42 @@ export const getDatatableVisualization = ({ return suggestion; }, - getSortedColumns(state, datasourceLayers = {}, activeData) { + getExportDatatables(state, datasourceLayers = {}, activeData) { const columnMap = new Map(state.columns.map((c) => [c.columnId, c])); - const { columns } = + const datatable = activeData?.[DatatableInspectorTables.Transpose] ?? - activeData?.[DatatableInspectorTables.Default] ?? - {}; - const columnIds = columns?.map(({ id }) => id) ?? [...columnMap.keys()]; - - return columnIds.filter((id) => !columnMap.get(getOriginalId(id))?.hidden); - }, - - getColumnSorting(state) { - if (!state.sorting?.columnId || state.sorting.direction === 'none') return []; + activeData?.[DatatableInspectorTables.Default]; + if (!datatable) return []; + + const columns = datatable.columns.filter(({ id }) => !columnMap.get(getOriginalId(id))?.hidden); + let rows = datatable.rows; + + const sortColumn = + state.sorting?.columnId && columns.find(({ id }) => id === state.sorting?.columnId); + const sortDirection = state.sorting?.direction; + + if (sortColumn && sortDirection && sortDirection !== 'none') { + const datasource = datasourceLayers[state.layerId]; + const schemaType = + datasource?.getOperationForColumnId?.(sortColumn.id)?.sortingHint ?? + getSimpleColumnType(sortColumn.meta); + const sortingCriteria = getSortingCriteria( + schemaType, + sortColumn.id, + formatFactory(sortColumn.meta?.params) + ); + rows = [...rows].sort((rA, rB) => sortingCriteria(rA, rB, sortDirection)); + } return [ { - id: state.sorting.columnId, - direction: state.sorting.direction, + ...datatable, + columns, + rows, }, ]; }, - getTablesToShare() { - return [DatatableInspectorTables.Transpose]; - }, - getVisualizationInfo(state) { const visibleMetricColumns = state.columns.filter( (c) => !c.hidden && c.colorMode && c.colorMode !== 'none' From 11f8cb2b519d4e2566932eb661d100894529e43b Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 14 Oct 2024 23:05:56 +0000 Subject: [PATCH 09/17] [CI] Auto-commit changed files from 'node scripts/lint_packages --fix' --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bf39e9ea13567..64ea028a26520 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -941,6 +941,7 @@ packages/kbn-tinymath @elastic/kibana-visualizations packages/kbn-tooling-log @elastic/kibana-operations x-pack/plugins/transform @elastic/ml-ui x-pack/plugins/translations @elastic/kibana-localization +packages/kbn-transpose-helpers @elastic/kibana-visualizations x-pack/examples/triggers_actions_ui_example @elastic/response-ops x-pack/plugins/triggers_actions_ui @elastic/response-ops packages/kbn-triggers-actions-ui-types @elastic/response-ops From 15eaf73ed0cf0635b85a098098d84f0d0e49e8d4 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 14 Oct 2024 23:06:34 +0000 Subject: [PATCH 10/17] [CI] Auto-commit changed files from 'node scripts/notice' --- packages/kbn-transpose-helpers/tsconfig.json | 8 ++++++-- .../chart_expressions/expression_heatmap/tsconfig.json | 1 + x-pack/plugins/lens/tsconfig.json | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/kbn-transpose-helpers/tsconfig.json b/packages/kbn-transpose-helpers/tsconfig.json index dad708677fd87..6230fe5d39c68 100644 --- a/packages/kbn-transpose-helpers/tsconfig.json +++ b/packages/kbn-transpose-helpers/tsconfig.json @@ -10,10 +10,14 @@ }, "include": [ "**/*.ts", - "**/*.tsx", + "**/*.tsx", ], "exclude": [ "target/**/*" ], - "kbn_references": [] + "kbn_references": [ + "@kbn/field-formats-plugin", + "@kbn/expressions-plugin", + "@kbn/lens-plugin", + ] } diff --git a/src/plugins/chart_expressions/expression_heatmap/tsconfig.json b/src/plugins/chart_expressions/expression_heatmap/tsconfig.json index 175a6eaf19f48..bca2563b6712b 100644 --- a/src/plugins/chart_expressions/expression_heatmap/tsconfig.json +++ b/src/plugins/chart_expressions/expression_heatmap/tsconfig.json @@ -28,6 +28,7 @@ "@kbn/chart-expressions-common", "@kbn/visualization-utils", "@kbn/react-kibana-context-render", + "@kbn/transpose-helpers", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index 32de68cc7ef45..53ce88b3e5db7 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -113,6 +113,7 @@ "@kbn/react-kibana-mount", "@kbn/es-types", "@kbn/esql-datagrid", + "@kbn/transpose-helpers", ], "exclude": ["target/**/*"] } From d8abdf6adadaabe7d3048487aabb9ab7232cddb5 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Sun, 20 Oct 2024 18:09:23 -0500 Subject: [PATCH 11/17] fix quick check issues - remove circular dep issue with transpose-helpers pkg - split transpose logic to share only id util functions - move transpose table logic back to plugin - rename pkg to utils instead of helpers - fixup failing tests from transpose sorting changes --- .github/CODEOWNERS | 8 ++-- package.json | 2 +- packages/kbn-transpose-helpers/README.md | 3 -- packages/kbn-transpose-utils/README.md | 3 ++ packages/kbn-transpose-utils/index.test.ts | 35 +++++++++++++++ packages/kbn-transpose-utils/index.ts | 36 +++++++++++++++ .../jest.config.js | 2 +- .../kibana.jsonc | 2 +- .../package.json | 4 +- .../tsconfig.json | 6 +-- .../public/components/helpers.ts | 2 +- .../expression_heatmap/tsconfig.json | 2 +- tsconfig.base.json | 4 +- .../expressions/datatable/datatable_fn.ts | 2 +- .../common/expressions/datatable/summary.ts | 2 +- .../datatable/transpose_helpers.test.ts | 39 ++++++++-------- .../datatable/transpose_helpers.ts | 44 +++---------------- .../common/expressions/datatable/utils.ts | 2 +- .../public/datasources/form_based/utils.tsx | 2 +- .../shared_components/coloring/utils.ts | 2 +- .../datatable/components/cell_value.test.tsx | 2 +- .../datatable/components/dimension_editor.tsx | 2 +- .../datatable/components/table_actions.ts | 2 +- .../datatable/components/table_basic.test.tsx | 2 +- .../datatable/components/table_basic.tsx | 2 +- .../datatable/visualization.tsx | 2 +- x-pack/plugins/lens/tsconfig.json | 2 +- yarn.lock | 2 +- 28 files changed, 125 insertions(+), 93 deletions(-) delete mode 100644 packages/kbn-transpose-helpers/README.md create mode 100644 packages/kbn-transpose-utils/README.md create mode 100644 packages/kbn-transpose-utils/index.test.ts create mode 100644 packages/kbn-transpose-utils/index.ts rename packages/{kbn-transpose-helpers => kbn-transpose-utils}/jest.config.js (90%) rename packages/{kbn-transpose-helpers => kbn-transpose-utils}/kibana.jsonc (68%) rename packages/{kbn-transpose-helpers => kbn-transpose-utils}/package.json (74%) rename packages/{kbn-transpose-helpers => kbn-transpose-utils}/tsconfig.json (69%) rename packages/kbn-transpose-helpers/index.test.ts => x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts (95%) rename packages/kbn-transpose-helpers/index.ts => x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts (85%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 64ea028a26520..41d12e81b35b2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -926,9 +926,9 @@ packages/kbn-test-eui-helpers @elastic/kibana-visualizations x-pack/test/licensing_plugin/plugins/test_feature_usage @elastic/kibana-security packages/kbn-test-jest-helpers @elastic/kibana-operations @elastic/appex-qa packages/kbn-test-subj-selector @elastic/kibana-operations @elastic/appex-qa -x-pack/test_serverless -test -x-pack/test +x-pack/test_serverless +test +x-pack/test x-pack/performance @elastic/appex-qa x-pack/examples/testing_embedded_lens @elastic/kibana-visualizations x-pack/examples/third_party_lens_navigation_prompt @elastic/kibana-visualizations @@ -941,7 +941,7 @@ packages/kbn-tinymath @elastic/kibana-visualizations packages/kbn-tooling-log @elastic/kibana-operations x-pack/plugins/transform @elastic/ml-ui x-pack/plugins/translations @elastic/kibana-localization -packages/kbn-transpose-helpers @elastic/kibana-visualizations +packages/kbn-transpose-utils @elastic/kibana-visualizations x-pack/examples/triggers_actions_ui_example @elastic/response-ops x-pack/plugins/triggers_actions_ui @elastic/response-ops packages/kbn-triggers-actions-ui-types @elastic/response-ops diff --git a/package.json b/package.json index 2f2dcb7824319..794cc4b0c128d 100644 --- a/package.json +++ b/package.json @@ -943,7 +943,7 @@ "@kbn/tinymath": "link:packages/kbn-tinymath", "@kbn/transform-plugin": "link:x-pack/plugins/transform", "@kbn/translations-plugin": "link:x-pack/plugins/translations", - "@kbn/transpose-helpers": "link:packages/kbn-transpose-helpers", + "@kbn/transpose-utils": "link:packages/kbn-transpose-utils", "@kbn/triggers-actions-ui-example-plugin": "link:x-pack/examples/triggers_actions_ui_example", "@kbn/triggers-actions-ui-plugin": "link:x-pack/plugins/triggers_actions_ui", "@kbn/triggers-actions-ui-types": "link:packages/kbn-triggers-actions-ui-types", diff --git a/packages/kbn-transpose-helpers/README.md b/packages/kbn-transpose-helpers/README.md deleted file mode 100644 index 10c6ca3668dbb..0000000000000 --- a/packages/kbn-transpose-helpers/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @kbn/transpose-helpers - -Util functions used convert raw columns into transposed columns. diff --git a/packages/kbn-transpose-utils/README.md b/packages/kbn-transpose-utils/README.md new file mode 100644 index 0000000000000..4c038b7f379f0 --- /dev/null +++ b/packages/kbn-transpose-utils/README.md @@ -0,0 +1,3 @@ +# @kbn/transpose-utils + +Utility functions used to identify and convert transposed column ids. diff --git a/packages/kbn-transpose-utils/index.test.ts b/packages/kbn-transpose-utils/index.test.ts new file mode 100644 index 0000000000000..4ddf5e7131258 --- /dev/null +++ b/packages/kbn-transpose-utils/index.test.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { getOriginalId, getTransposeId, isTransposeId } from '.'; + +describe('transpose utils', () => { + it('should covert value and id to transposed id', () => { + expect(getTransposeId('test', 'column-1')).toBe('test---column-1'); + }); + + it('should know if id is transposed', () => { + const testId = getTransposeId('test', 'column-1'); + expect(isTransposeId(testId)).toBe(true); + }); + + it('should know if id is not transposed', () => { + expect(isTransposeId('test')).toBe(false); + }); + + it('should return id for transposed id', () => { + const testId = getTransposeId('test', 'column-1'); + + expect(getOriginalId(testId)).toBe('column-1'); + }); + + it('should return id for non-transposed id', () => { + expect(getOriginalId('test')).toBe('test'); + }); +}); diff --git a/packages/kbn-transpose-utils/index.ts b/packages/kbn-transpose-utils/index.ts new file mode 100644 index 0000000000000..cd29e14a58227 --- /dev/null +++ b/packages/kbn-transpose-utils/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +/** + * Used to delimitate felids of a transposed column id + */ +export const TRANSPOSE_SEPARATOR = '---'; + +/** + * Visual deliminator between felids of a transposed column id + * + * Meant to align with the `MULTI_FIELD_KEY_SEPARATOR` from the data plugin + */ +export const TRANSPOSE_VISUAL_SEPARATOR = '›'; + +export function getTransposeId(value: string, columnId: string) { + return `${value}${TRANSPOSE_SEPARATOR}${columnId}`; +} + +export function isTransposeId(id: string): boolean { + return id.split(TRANSPOSE_SEPARATOR).length > 1; +} + +export function getOriginalId(id: string) { + if (id.includes(TRANSPOSE_SEPARATOR)) { + const idParts = id.split(TRANSPOSE_SEPARATOR); + return idParts[idParts.length - 1]; + } + return id; +} diff --git a/packages/kbn-transpose-helpers/jest.config.js b/packages/kbn-transpose-utils/jest.config.js similarity index 90% rename from packages/kbn-transpose-helpers/jest.config.js rename to packages/kbn-transpose-utils/jest.config.js index 2502e9598e081..1109bd9db4edb 100644 --- a/packages/kbn-transpose-helpers/jest.config.js +++ b/packages/kbn-transpose-utils/jest.config.js @@ -10,5 +10,5 @@ module.exports = { preset: '@kbn/test', rootDir: '../..', - roots: ['/packages/kbn-transpose-helpers'], + roots: ['/packages/kbn-transpose-utils'], }; diff --git a/packages/kbn-transpose-helpers/kibana.jsonc b/packages/kbn-transpose-utils/kibana.jsonc similarity index 68% rename from packages/kbn-transpose-helpers/kibana.jsonc rename to packages/kbn-transpose-utils/kibana.jsonc index f0d71b07fea3a..d891291d0720a 100644 --- a/packages/kbn-transpose-helpers/kibana.jsonc +++ b/packages/kbn-transpose-utils/kibana.jsonc @@ -1,5 +1,5 @@ { "type": "shared-common", - "id": "@kbn/transpose-helpers", + "id": "@kbn/transpose-utils", "owner": "@elastic/kibana-visualizations" } diff --git a/packages/kbn-transpose-helpers/package.json b/packages/kbn-transpose-utils/package.json similarity index 74% rename from packages/kbn-transpose-helpers/package.json rename to packages/kbn-transpose-utils/package.json index 80f9a981a4650..ccb9600c56184 100644 --- a/packages/kbn-transpose-helpers/package.json +++ b/packages/kbn-transpose-utils/package.json @@ -1,6 +1,6 @@ { - "name": "@kbn/transpose-helpers", + "name": "@kbn/transpose-utils", "private": true, "version": "1.0.0", "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" -} \ No newline at end of file +} diff --git a/packages/kbn-transpose-helpers/tsconfig.json b/packages/kbn-transpose-utils/tsconfig.json similarity index 69% rename from packages/kbn-transpose-helpers/tsconfig.json rename to packages/kbn-transpose-utils/tsconfig.json index 6230fe5d39c68..87f865132f4b4 100644 --- a/packages/kbn-transpose-helpers/tsconfig.json +++ b/packages/kbn-transpose-utils/tsconfig.json @@ -15,9 +15,5 @@ "exclude": [ "target/**/*" ], - "kbn_references": [ - "@kbn/field-formats-plugin", - "@kbn/expressions-plugin", - "@kbn/lens-plugin", - ] + "kbn_references": [] } diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts index ac8af6c4af2c3..fdad47519c1c5 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts @@ -18,7 +18,7 @@ import { DEFAULT_MAX_STOP, DEFAULT_MIN_STOP, } from '@kbn/coloring'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; import type { Datatable, DatatableColumn } from '@kbn/expressions-plugin/public'; import { FormatFactory, IFieldFormat } from '@kbn/field-formats-plugin/common'; diff --git a/src/plugins/chart_expressions/expression_heatmap/tsconfig.json b/src/plugins/chart_expressions/expression_heatmap/tsconfig.json index bca2563b6712b..552d9c2c9819e 100644 --- a/src/plugins/chart_expressions/expression_heatmap/tsconfig.json +++ b/src/plugins/chart_expressions/expression_heatmap/tsconfig.json @@ -28,7 +28,7 @@ "@kbn/chart-expressions-common", "@kbn/visualization-utils", "@kbn/react-kibana-context-render", - "@kbn/transpose-helpers", + "@kbn/transpose-utils", ], "exclude": [ "target/**/*", diff --git a/tsconfig.base.json b/tsconfig.base.json index 3158a164c408e..d1876d106b7b4 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1876,8 +1876,8 @@ "@kbn/transform-plugin/*": ["x-pack/plugins/transform/*"], "@kbn/translations-plugin": ["x-pack/plugins/translations"], "@kbn/translations-plugin/*": ["x-pack/plugins/translations/*"], - "@kbn/transpose-helpers": ["packages/kbn-transpose-helpers"], - "@kbn/transpose-helpers/*": ["packages/kbn-transpose-helpers/*"], + "@kbn/transpose-utils": ["packages/kbn-transpose-utils"], + "@kbn/transpose-utils/*": ["packages/kbn-transpose-utils/*"], "@kbn/triggers-actions-ui-example-plugin": ["x-pack/examples/triggers_actions_ui_example"], "@kbn/triggers-actions-ui-example-plugin/*": ["x-pack/examples/triggers_actions_ui_example/*"], "@kbn/triggers-actions-ui-plugin": ["x-pack/plugins/triggers_actions_ui"], diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts index 67bea7ece66f8..31d53f6e78f2e 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -7,12 +7,12 @@ import { cloneDeep } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { transposeTable } from '@kbn/transpose-helpers'; import { prepareLogTable } from '@kbn/visualizations-plugin/common/utils'; import type { Datatable, ExecutionContext } from '@kbn/expressions-plugin/common'; import { FormatFactory } from '../../types'; import { computeSummaryRowForColumn } from './summary'; import type { DatatableExpressionFunction } from './types'; +import { transposeTable } from './transpose_helpers'; /** * Available datatables logged to inspector diff --git a/x-pack/plugins/lens/common/expressions/datatable/summary.ts b/x-pack/plugins/lens/common/expressions/datatable/summary.ts index 497d0724c9b8d..6837c05244469 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/summary.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/summary.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import type { FieldFormat } from '@kbn/field-formats-plugin/common'; import type { Datatable } from '@kbn/expressions-plugin/common'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; import { DatatableColumnArgs } from './datatable_column'; import { isNumericFieldForDatatable } from './utils'; diff --git a/packages/kbn-transpose-helpers/index.test.ts b/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts similarity index 95% rename from packages/kbn-transpose-helpers/index.test.ts rename to x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts index 62b5ddecfde70..114548c0daa74 100644 --- a/packages/kbn-transpose-helpers/index.test.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.test.ts @@ -1,17 +1,14 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import type { FieldFormat } from '@kbn/field-formats-plugin/common'; import type { Datatable } from '@kbn/expressions-plugin/common'; -import { DatatableArgs } from '@kbn/lens-plugin/common/expressions'; - -import { transposeTable } from '.'; +import { DatatableArgs } from '..'; +import { transposeTable } from './transpose_helpers'; describe('transpose helpers', () => { function buildTable(): Datatable { @@ -122,10 +119,10 @@ describe('transpose helpers', () => { 'bucket2', 'bucket3', 'A---metric1', - 'B---metric1', - 'C---metric1', 'A---metric2', + 'B---metric1', 'B---metric2', + 'C---metric1', 'C---metric2', ]); @@ -181,22 +178,22 @@ describe('transpose helpers', () => { expect(table.columns.map((c) => c.id)).toEqual([ 'bucket3', 'A---D---metric1', - 'B---D---metric1', - 'C---D---metric1', + 'A---D---metric2', 'A---E---metric1', - 'B---E---metric1', - 'C---E---metric1', + 'A---E---metric2', 'A---F---metric1', - 'B---F---metric1', - 'C---F---metric1', - 'A---D---metric2', + 'A---F---metric2', + 'B---D---metric1', 'B---D---metric2', - 'C---D---metric2', - 'A---E---metric2', + 'B---E---metric1', 'B---E---metric2', - 'C---E---metric2', - 'A---F---metric2', + 'B---F---metric1', 'B---F---metric2', + 'C---D---metric1', + 'C---D---metric2', + 'C---E---metric1', + 'C---E---metric2', + 'C---F---metric1', 'C---F---metric2', ]); diff --git a/packages/kbn-transpose-helpers/index.ts b/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts similarity index 85% rename from packages/kbn-transpose-helpers/index.ts rename to x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts index 198c23ea5e121..529a622099cca 100644 --- a/packages/kbn-transpose-helpers/index.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/transpose_helpers.ts @@ -1,47 +1,15 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import type { Datatable, DatatableColumn, DatatableRow } from '@kbn/expressions-plugin/common'; import type { FieldFormat } from '@kbn/field-formats-plugin/common'; -import { - DatatableArgs, - DatatableColumnArgs, - DatatableColumnConfig, -} from '@kbn/lens-plugin/common/expressions'; - -/** - * Used to delimitate felids of a transposed column id - */ -export const TRANSPOSE_SEPARATOR = '---'; - -/** - * Visual deliminator between felids of a transposed column id - * - * Meant to align with the `MULTI_FIELD_KEY_SEPARATOR` from the data plugin - */ -export const TRANSPOSE_VISUAL_SEPARATOR = '›'; - -export function getTransposeId(value: string, columnId: string) { - return `${value}${TRANSPOSE_SEPARATOR}${columnId}`; -} - -export function isTransposeId(id: string): boolean { - return id.split(TRANSPOSE_SEPARATOR).length > 1; -} - -export function getOriginalId(id: string) { - if (id.includes(TRANSPOSE_SEPARATOR)) { - const idParts = id.split(TRANSPOSE_SEPARATOR); - return idParts[idParts.length - 1]; - } - return id; -} +import { TRANSPOSE_VISUAL_SEPARATOR, getTransposeId } from '@kbn/transpose-utils'; +import { DatatableArgs } from './datatable'; +import type { DatatableColumnConfig, DatatableColumnArgs } from './datatable_column'; /** * Transposes the columns of the given table as defined in the arguments. diff --git a/x-pack/plugins/lens/common/expressions/datatable/utils.ts b/x-pack/plugins/lens/common/expressions/datatable/utils.ts index 4bbd73e794621..483f42424c144 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/utils.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/utils.ts @@ -6,7 +6,7 @@ */ import { type Datatable, type DatatableColumnMeta } from '@kbn/expressions-plugin/common'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; /** * Returns true for numerical fields diff --git a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx index 8178f48f5a50e..fb280530ade58 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx @@ -25,7 +25,7 @@ import { import { estypes } from '@elastic/elasticsearch'; import { isQueryValid } from '@kbn/visualization-ui-components'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; import type { DateRange } from '../../../common/types'; import type { FramePublicAPI, diff --git a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts index 09424ebb795d1..ae797c1daa6c6 100644 --- a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts +++ b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts @@ -21,7 +21,7 @@ import { getColorsFromMapping, DEFAULT_FALLBACK_PALETTE, } from '@kbn/coloring'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; import { Datatable, DatatableColumnType } from '@kbn/expressions-plugin/common'; import { DataType } from '../../types'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx index f55a424c78282..74cadb9d9a4a9 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/cell_value.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { DataContext } from './table_basic'; import { createGridCell } from './cell_value'; -import { getTransposeId } from '@kbn/transpose-helpers'; +import { getTransposeId } from '@kbn/transpose-utils'; import type { FieldFormat } from '@kbn/field-formats-plugin/common'; import { Datatable } from '@kbn/expressions-plugin/public'; import { DatatableArgs } from '../../../../common/expressions'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx index ec23952f29009..65968a5170107 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx @@ -11,7 +11,7 @@ import { EuiFormRow, EuiSwitch, EuiButtonGroup, htmlIdGenerator } from '@elastic import { PaletteRegistry, getFallbackDataBounds } from '@kbn/coloring'; import { getColorCategories } from '@kbn/chart-expressions-common'; import { useDebouncedValue } from '@kbn/visualization-utils'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; import type { VisualizationDimensionEditorProps } from '../../../types'; import type { DatatableVisualizationState } from '../visualization'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts b/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts index 4fbcafa92f21d..c3f34171eaf60 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_actions.ts @@ -18,7 +18,7 @@ import type { import { ClickTriggerEvent } from '@kbn/charts-plugin/public'; import { getSortingCriteria } from '@kbn/sort-predicates'; import { i18n } from '@kbn/i18n'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; import type { LensResizeAction, LensSortAction, LensToggleAction } from './types'; import type { DatatableColumnConfig, LensGridDirection } from '../../../../common/expressions'; import type { FormatFactory } from '../../../../common/types'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx index faf535819120a..14b3796fbd145 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.test.tsx @@ -20,7 +20,7 @@ import type { DatatableProps } from '../../../../common/expressions'; import { LENS_EDIT_PAGESIZE_ACTION } from './constants'; import { DatatableRenderProps } from './types'; import { PaletteOutput } from '@kbn/coloring'; -import { getTransposeId } from '@kbn/transpose-helpers'; +import { getTransposeId } from '@kbn/transpose-utils'; import { CustomPaletteState } from '@kbn/charts-plugin/common'; import { getCellColorFn } from '../../../shared_components/coloring/get_cell_color_fn'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx index 9f820ecdc79b0..ec672d20f55da 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx @@ -32,7 +32,7 @@ import { ClickTriggerEvent } from '@kbn/charts-plugin/public'; import { IconChartDatatable } from '@kbn/chart-icons'; import useObservable from 'react-use/lib/useObservable'; import { getColorCategories } from '@kbn/chart-expressions-common'; -import { getOriginalId, isTransposeId } from '@kbn/transpose-helpers'; +import { getOriginalId, isTransposeId } from '@kbn/transpose-utils'; import type { LensTableRowContextMenuEvent } from '../../../types'; import type { FormatFactory } from '../../../../common/types'; import { RowHeightMode } from '../../../../common/types'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index b8241ca36d07b..55dea2be2e370 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -12,7 +12,7 @@ import { PaletteRegistry, CUSTOM_PALETTE, PaletteOutput, CustomPaletteParams } f import { ThemeServiceStart } from '@kbn/core/public'; import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public'; import { IconChartDatatable } from '@kbn/chart-icons'; -import { getOriginalId } from '@kbn/transpose-helpers'; +import { getOriginalId } from '@kbn/transpose-utils'; import { LayerTypes } from '@kbn/expression-xy-plugin/public'; import { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugin/common'; import useObservable from 'react-use/lib/useObservable'; diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index 53ce88b3e5db7..db249f19f3614 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -113,7 +113,7 @@ "@kbn/react-kibana-mount", "@kbn/es-types", "@kbn/esql-datagrid", - "@kbn/transpose-helpers", + "@kbn/transpose-utils", ], "exclude": ["target/**/*"] } diff --git a/yarn.lock b/yarn.lock index 9131ba06df9ba..b9b37e531eb4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7047,7 +7047,7 @@ version "0.0.0" uid "" -"@kbn/transpose-helpers@link:packages/kbn-transpose-helpers": +"@kbn/transpose-utils@link:packages/kbn-transpose-utils": version "0.0.0" uid "" From 609dc1cf974242ba3f36632d1ebc3508208c87ee Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Sun, 20 Oct 2024 18:09:43 -0500 Subject: [PATCH 12/17] update jest tests with new changes --- .../data/common/exports/export_csv.test.ts | 10 ----- .../__snapshots__/data_view.test.tsx.snap | 41 ++++++++++--------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/plugins/data/common/exports/export_csv.test.ts b/src/plugins/data/common/exports/export_csv.test.ts index 9bfc1e69a9c28..435d38c2090ab 100644 --- a/src/plugins/data/common/exports/export_csv.test.ts +++ b/src/plugins/data/common/exports/export_csv.test.ts @@ -97,14 +97,4 @@ describe('CSV exporter', () => { }) ).toMatch('columnOne\r\n"a,b"\r\n'); }); - - test('should respect the sorted columns order when passed', () => { - const datatable = getDataTable({ multipleColumns: true }); - expect( - datatableToCSV(datatable, { - ...getDefaultOptions(), - sortedColumns: ['col2', 'col1'], - }) - ).toMatch('columnTwo,columnOne\r\n"Formatted_5","Formatted_value"\r\n'); - }); }); diff --git a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap index 5eb947fe1d12d..cf3ce3254b271 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap +++ b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap @@ -156,7 +156,8 @@ exports[`Inspector Data View component should render loading state 1`] = ` "_events": Object {}, "_eventsCount": 0, "_maxListeners": undefined, - "_tables": Object {}, + "allowCsvExport": false, + "initialSelectedTable": undefined, Symbol(shapeMode): false, Symbol(kCapture): false, }, @@ -430,29 +431,31 @@ Array [
-
- + +
From 1e9f9b57937680cea9cafd6d138db162fcc6364e Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:36:35 +0000 Subject: [PATCH 13/17] [CI] Auto-commit changed files from 'node scripts/build_plugin_list_docs' --- .github/CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2c1628ff3a9fe..bc7da88e54074 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -929,9 +929,9 @@ packages/kbn-test-eui-helpers @elastic/kibana-visualizations x-pack/test/licensing_plugin/plugins/test_feature_usage @elastic/kibana-security packages/kbn-test-jest-helpers @elastic/kibana-operations @elastic/appex-qa packages/kbn-test-subj-selector @elastic/kibana-operations @elastic/appex-qa -x-pack/test_serverless -test -x-pack/test +x-pack/test_serverless +test +x-pack/test x-pack/performance @elastic/appex-qa x-pack/examples/testing_embedded_lens @elastic/kibana-visualizations x-pack/examples/third_party_lens_navigation_prompt @elastic/kibana-visualizations From 25a6eb03db975fc60463d4645ef1b5e150768a61 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Mon, 21 Oct 2024 09:27:35 -0500 Subject: [PATCH 14/17] fix jest type errors --- .../public/components/helpers.ts | 4 --- .../expression_functions/xy_vis.test.ts | 34 +++++++++++-------- src/plugins/expressions/common/mocks.ts | 14 +++++--- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts index fdad47519c1c5..c9ba0c760dba9 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/helpers.ts @@ -84,10 +84,6 @@ export function applyPaletteParams> return displayStops; } -function getId(id: string) { - return id; -} - export function getNumericValue(rowValue: number | number[] | undefined) { if (rowValue == null || Array.isArray(rowValue)) { return; diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts index 3fefc8d36ca0d..5ae737d9e99ab 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts @@ -11,8 +11,12 @@ import { xyVisFunction } from '.'; import { createMockExecutionContext } from '@kbn/expressions-plugin/common/mocks'; import { sampleArgs, sampleLayer } from '../__mocks__'; import { XY_VIS } from '../constants'; +import { createDefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; describe('xyVis', () => { + const getExecutionContext = () => + createMockExecutionContext({}, createDefaultInspectorAdapters()); + test('it renders with the specified data and args', async () => { const { data, args } = sampleArgs(); const { layers, ...rest } = args; @@ -20,7 +24,7 @@ describe('xyVis', () => { const result = await xyVisFunction.fn( data, { ...rest, ...restLayerArgs, referenceLines: [] }, - createMockExecutionContext() + getExecutionContext() ); expect(result).toEqual({ @@ -59,7 +63,7 @@ describe('xyVis', () => { markSizeRatio: 0, referenceLines: [], }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); @@ -72,7 +76,7 @@ describe('xyVis', () => { markSizeRatio: 101, referenceLines: [], }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -90,7 +94,7 @@ describe('xyVis', () => { minTimeBarInterval: '1q', referenceLines: [], }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -108,7 +112,7 @@ describe('xyVis', () => { minTimeBarInterval: '1h', referenceLines: [], }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -126,7 +130,7 @@ describe('xyVis', () => { addTimeMarker: true, referenceLines: [], }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -147,7 +151,7 @@ describe('xyVis', () => { splitRowAccessor, }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -168,7 +172,7 @@ describe('xyVis', () => { splitColumnAccessor, }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -188,7 +192,7 @@ describe('xyVis', () => { markSizeRatio: 5, }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -211,7 +215,7 @@ describe('xyVis', () => { seriesType: 'bar', showLines: true, }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -238,7 +242,7 @@ describe('xyVis', () => { extent: { type: 'axisExtentConfig', mode: 'dataBounds' }, }, }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -268,7 +272,7 @@ describe('xyVis', () => { }, }, }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -293,7 +297,7 @@ describe('xyVis', () => { extent: { type: 'axisExtentConfig', mode: 'dataBounds' }, }, }, - createMockExecutionContext() + getExecutionContext() ) ).rejects.toThrowErrorMatchingSnapshot(); }); @@ -320,7 +324,7 @@ describe('xyVis', () => { }, }, }, - createMockExecutionContext() + getExecutionContext() ); expect(result).toEqual({ @@ -370,7 +374,7 @@ describe('xyVis', () => { }, }; const context = { - ...createMockExecutionContext(), + ...getExecutionContext(), variables: { overrides, }, diff --git a/src/plugins/expressions/common/mocks.ts b/src/plugins/expressions/common/mocks.ts index b87cc177ed297..a40a301e47de1 100644 --- a/src/plugins/expressions/common/mocks.ts +++ b/src/plugins/expressions/common/mocks.ts @@ -7,11 +7,16 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { Adapters } from '@kbn/inspector-plugin/common'; import { ExecutionContext } from './execution/types'; -export const createMockExecutionContext = ( - extraContext: ExtraContext = {} as ExtraContext -): ExecutionContext & ExtraContext => { +export const createMockExecutionContext = < + ExtraContext extends object = object, + ExtraAdapters extends Adapters = Adapters +>( + extraContext: ExtraContext = {} as ExtraContext, + extraAdapters: ExtraAdapters +): ExecutionContext & ExtraContext => { const executionContext = { getSearchContext: jest.fn(), getSearchSessionId: jest.fn(), @@ -28,9 +33,10 @@ export const createMockExecutionContext = inspectorAdapters: { requests: {}, data: {}, + ...extraAdapters, }, allowCache: false, - } as unknown as ExecutionContext; + } as unknown as ExecutionContext; return { ...executionContext, From 5c3ccd84461a2b19d115fe7bc4d725df8888bd94 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Mon, 21 Oct 2024 22:45:20 -0500 Subject: [PATCH 15/17] fix activeData error caused by conditional `onActiveDataChange` transform in `workpace_panel` --- .../shared/edit_on_the_fly/lens_configuration_flyout.tsx | 2 +- .../visualizations/datatable/components/dimension_editor.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx index fd0407513f869..ef452f20fdf7d 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx @@ -117,7 +117,7 @@ export function LensEditConfigurationFlyout({ useEffect(() => { const s = output$?.subscribe(() => { const activeData: Record = {}; - const adaptersTables = previousAdapters.current?.tables?.tables as Record; + const adaptersTables = previousAdapters.current?.tables?.tables; const [table] = Object.values(adaptersTables || {}); if (table) { // there are cases where a query can return a big amount of columns diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx index 65968a5170107..9fb71142d2402 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor.tsx @@ -31,6 +31,7 @@ import { getFieldMetaFromDatatable, isNumericField, } from '../../../../common/expressions/datatable/utils'; +import { DatatableInspectorTables } from '../../../../common/expressions/datatable/datatable_fn'; const idPrefix = htmlIdGenerator()(); @@ -78,7 +79,8 @@ export function TableDimensionEditor(props: TableDimensionEditorProps) { if (!column) return null; if (column.isTransposed) return null; - const currentData = frame.activeData?.[localState.layerId]; + const currentData = + frame.activeData?.[localState.layerId] ?? frame.activeData?.[DatatableInspectorTables.Default]; const datasource = frame.datasourceLayers?.[localState.layerId]; const { isBucketed } = datasource?.getOperationForColumnId(accessor) ?? {}; const meta = getFieldMetaFromDatatable(currentData, accessor); From ac0ff49a3c524376c7c08614fdda99120397a034 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Tue, 22 Oct 2024 18:18:47 -0500 Subject: [PATCH 16/17] fix jest tests and fn tests --- src/plugins/expressions/common/mocks.ts | 2 +- .../components/dimension_editor_addtional_section.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/expressions/common/mocks.ts b/src/plugins/expressions/common/mocks.ts index a40a301e47de1..2b7c19d10bc90 100644 --- a/src/plugins/expressions/common/mocks.ts +++ b/src/plugins/expressions/common/mocks.ts @@ -15,7 +15,7 @@ export const createMockExecutionContext = < ExtraAdapters extends Adapters = Adapters >( extraContext: ExtraContext = {} as ExtraContext, - extraAdapters: ExtraAdapters + extraAdapters: ExtraAdapters = {} as ExtraAdapters ): ExecutionContext & ExtraContext => { const executionContext = { getSearchContext: jest.fn(), diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor_addtional_section.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor_addtional_section.tsx index 92268d052cd44..93c14230f63d9 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor_addtional_section.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/dimension_editor_addtional_section.tsx @@ -22,6 +22,7 @@ import { getSummaryRowOptions, } from '../../../../common/expressions/datatable/summary'; import { isNumericFieldForDatatable } from '../../../../common/expressions/datatable/utils'; +import { DatatableInspectorTables } from '../../../../common/expressions/datatable/datatable_fn'; import './dimension_editor.scss'; @@ -73,7 +74,8 @@ export function TableDimensionEditorAdditionalSection( if (!column) return null; if (column.isTransposed) return null; - const currentData = frame.activeData?.[state.layerId]; + const currentData = + frame.activeData?.[state.layerId] ?? frame.activeData?.[DatatableInspectorTables.Default]; const isNumeric = isNumericFieldForDatatable(currentData, accessor); // when switching from one operation to another, make sure to keep the configuration consistent From 4592f102bbcc49570a878b252a74b89c4fe9a950 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Wed, 23 Oct 2024 20:27:33 -0500 Subject: [PATCH 17/17] fix type error in unit test --- .../lens/public/visualizations/datatable/visualization.test.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx index c6670d933e729..9a94e458c667c 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx @@ -28,6 +28,7 @@ import { DatatableExpressionFunction, } from '../../../common/expressions'; import { getColorStops } from '../../shared_components/coloring'; +import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; jest.mock('../../shared_components/coloring', () => { return { @@ -46,6 +47,7 @@ function mockFrame(): FramePublicAPI { const mockServices = { paletteService: chartPluginMock.createPaletteRegistry(), kibanaTheme: themeServiceMock.createStartContract(), + formatFactory: fieldFormatsServiceMock.createStartContract().deserialize, }; const datatableVisualization = getDatatableVisualization(mockServices);