From 1fac2189f83421fa8227b99495d953164a5816f9 Mon Sep 17 00:00:00 2001 From: Paul Sebastian Date: Thu, 19 Oct 2023 14:19:17 -0700 Subject: [PATCH 1/5] change data grid to separate sort/page query to not interfere with other components Signed-off-by: Paul Sebastian --- .../explorer/events_views/data_grid.tsx | 87 +++++++++++-------- .../event_analytics/utils/utils.tsx | 8 +- 2 files changed, 59 insertions(+), 36 deletions(-) diff --git a/public/components/event_analytics/explorer/events_views/data_grid.tsx b/public/components/event_analytics/explorer/events_views/data_grid.tsx index b84e4bc64..56c9d5af9 100644 --- a/public/components/event_analytics/explorer/events_views/data_grid.tsx +++ b/public/components/event_analytics/explorer/events_views/data_grid.tsx @@ -57,11 +57,11 @@ export function DataGrid(props: DataGridProps) { startTime, endTime, } = props; - const { getEvents } = useFetchEvents({ + const { fetchEvents } = useFetchEvents({ pplService, requestParams, }); - const storedSelectedColumns = + const selectedColumns = explorerFields.selectedFields.length > 0 ? explorerFields.selectedFields : DEFAULT_EMPTY_EXPLORER_FIELDS; @@ -70,44 +70,63 @@ export function DataGrid(props: DataGridProps) { const sortingFields: MutableRefObject = useRef([]); const pageFields = useRef([0, 100]); + const [data, setData] = useState(rows); + // setSort and setPage are used to change the query and send a direct request to get data const setSort = (sort: EuiDataGridSorting['columns']) => { sortingFields.current = sort; - redoQuery(startTime, endTime, rawQuery, timeStampField, sortingFields, pageFields, getEvents); + + redoQuery( + startTime, + endTime, + rawQuery, + timeStampField, + sortingFields, + pageFields, + fetchEvents, + setData + ); }; const setPage = (page: number[]) => { pageFields.current = page; - redoQuery(startTime, endTime, rawQuery, timeStampField, sortingFields, pageFields, getEvents); + const res = redoQuery( + startTime, + endTime, + rawQuery, + timeStampField, + sortingFields, + pageFields, + fetchEvents, + setData + ); + console.log(res); }; // creates the header for each column listing what that column is const dataGridColumns = useMemo(() => { - if (storedSelectedColumns.length > 0) { - const columns: EuiDataGridColumn[] = []; - storedSelectedColumns.map(({ name, type }) => { - if (name === 'timestamp') { - columns.push(DEFAULT_TIMESTAMP_COLUMN); - } else if (name === '_source') { - columns.push(DEFAULT_SOURCE_COLUMN); - } else { - columns.push({ - id: name, - display: name, - isSortable: true, // TODO: add functionality here based on type - }); - } - }); - return columns; - } - return []; - }, [storedSelectedColumns]); + const columns: EuiDataGridColumn[] = []; + selectedColumns.map(({ name, type }) => { + if (name === 'timestamp') { + columns.push(DEFAULT_TIMESTAMP_COLUMN); + } else if (name === '_source') { + columns.push(DEFAULT_SOURCE_COLUMN); + } else { + columns.push({ + id: name, + display: name, + isSortable: true, // TODO: add functionality here based on type + }); + } + }); + return columns; + }, [explorerFields]); // used for which columns are visible and their order const dataGridColumnVisibility = useMemo(() => { - if (storedSelectedColumns.length > 0) { + if (selectedColumns.length > 0) { const columns: string[] = []; - storedSelectedColumns.map(({ name }) => { + selectedColumns.map(({ name }) => { columns.push(name); }); return { @@ -119,7 +138,7 @@ export function DataGrid(props: DataGridProps) { } // default shown fields throw new Error('explorer data grid stored columns empty'); - }, [storedSelectedColumns]); + }, [explorerFields]); // sets the very first column, which is the button used for the flyout of each row const dataGridLeadingColumns = useMemo(() => { @@ -159,17 +178,17 @@ export function DataGrid(props: DataGridProps) { const dataGridCellRender = useCallback( ({ rowIndex, columnId }: { rowIndex: number; columnId: string }) => { const trueIndex = rowIndex % pageFields.current[1]; - if (trueIndex < rows.length) { + if (trueIndex < data.length) { if (columnId === '_source') { return ( - {Object.keys(rows[trueIndex]).map((key) => ( + {Object.keys(data[trueIndex]).map((key) => ( {key} - {rows[trueIndex][key]} + {data[trueIndex][key]} ))} @@ -177,13 +196,13 @@ export function DataGrid(props: DataGridProps) { ); } if (columnId === 'timestamp') { - return `${moment(rows[trueIndex][columnId]).format(DATE_DISPLAY_FORMAT)}`; + return `${moment(data[trueIndex][columnId]).format(DATE_DISPLAY_FORMAT)}`; } - return `${rows[trueIndex][columnId]}`; + return `${data[trueIndex][columnId]}`; } return null; }, - [rows, pageFields, explorerFields] + [data, rows, pageFields, explorerFields] ); // ** Pagination config @@ -212,10 +231,10 @@ export function DataGrid(props: DataGridProps) { () => ({ defaultHeight: { // if source is listed as a column, add extra space - lineCount: storedSelectedColumns.some((obj) => obj.name === '_source') ? 3 : 1, + lineCount: selectedColumns.some((obj) => obj.name === '_source') ? 3 : 1, }, }), - [storedSelectedColumns] + [explorerFields] ); // TODO: memoize the expensive table below diff --git a/public/components/event_analytics/utils/utils.tsx b/public/components/event_analytics/utils/utils.tsx index d680860e1..996a656b6 100644 --- a/public/components/event_analytics/utils/utils.tsx +++ b/public/components/event_analytics/utils/utils.tsx @@ -413,7 +413,8 @@ export const redoQuery = ( timeStampField: string, sortingFields: MutableRefObject, pageFields: MutableRefObject, - getEvents: any + fetchEvents: any, + setData: React.Dispatch> ) => { let finalQuery = ''; @@ -436,5 +437,8 @@ export const redoQuery = ( finalQuery = finalQuery + ` | head ${pageFields.current[1]} from ${pageFields.current[0] * pageFields.current[1]}`; - getEvents(finalQuery); + + fetchEvents({ query: finalQuery }, 'jdbc', (res: any) => { + setData(res.jsonData); + }); }; From 0aa37f07eb4fce66e56f757bc76c66b04fa7b2e0 Mon Sep 17 00:00:00 2001 From: Paul Sebastian Date: Thu, 19 Oct 2023 16:44:15 -0700 Subject: [PATCH 2/5] basic drag and drop added Signed-off-by: Paul Sebastian --- .../explorer/sidebar/sidebar.tsx | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/public/components/event_analytics/explorer/sidebar/sidebar.tsx b/public/components/event_analytics/explorer/sidebar/sidebar.tsx index a9b2a3eed..687815f6e 100644 --- a/public/components/event_analytics/explorer/sidebar/sidebar.tsx +++ b/public/components/event_analytics/explorer/sidebar/sidebar.tsx @@ -14,7 +14,7 @@ import { } from '@elastic/eui'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { isEmpty } from 'lodash'; -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { batch, useDispatch } from 'react-redux'; import { AVAILABLE_FIELDS, SELECTED_FIELDS } from '../../../../../common/constants/explorer'; import { ExplorerFields, IExplorerFields, IField } from '../../../../../common/types/explorer'; @@ -54,6 +54,18 @@ export const Sidebar = (props: ISidebarProps) => { const [showFields, setShowFields] = useState(false); const [searchTerm, setSearchTerm] = useState(''); + // list of every single field object + const [allFields, setAllFields] = useState([]); + + // method to return the type of a field from its name + const getFieldTypes = (newFieldName: string) => { + let fieldType: string = ''; + allFields.map((field) => { + if (field.name === newFieldName) fieldType = field.type; + }); + return fieldType; + }; + /** * Toggle fields between selected and unselected sets * @param fieldState all fields in store @@ -117,8 +129,35 @@ export const Sidebar = (props: ISidebarProps) => { [explorerFields, tabId] ); - const onDragEnd = ({}) => { - console.log('source, destination'); + // this useEffect will set allFields when the page is rendered + useEffect(() => { + if ( + explorerFields.availableFields.length > 0 && + explorerFields.selectedFields.length === 0 && + allFields.length === 0 + ) { + setAllFields(explorerFields.availableFields); + } + }, [explorerFields.availableFields]); + + const onDragEnd = ({ + destination, + source, + draggableId, + }: { + destination: any; + source: any; + draggableId: string; + }) => { + // check if the destination and source are the same area + if (destination.droppableId !== source.droppableId) { + // if dropped into the selected fields: add, if dropped into available: remove + if (destination.droppableId === 'SELECTED FIELDS') { + handleAddField({ name: draggableId, type: getFieldTypes(draggableId) }); + } else if (destination.droppableId === 'AVAILABLE FIELDS') { + handleRemoveField({ name: draggableId, type: getFieldTypes(draggableId) }); + } + } }; return ( From 088318e93e6b58b181fe724fae84f27330c50d24 Mon Sep 17 00:00:00 2001 From: Paul Sebastian Date: Fri, 20 Oct 2023 09:18:20 -0700 Subject: [PATCH 3/5] viz config changes Signed-off-by: Paul Sebastian --- common/constants/shared.ts | 1 + .../event_analytics/explorer/explorer.scss | 2 +- .../event_analytics/explorer/explorer.tsx | 2 +- .../config_panel/config_panel.scss | 9 ++ .../data_config_panel_fields.tsx | 117 ++++++++++-------- .../data_configurations_panel.scss | 46 +++++++ .../data_configurations_panel.tsx | 104 +++++++++------- .../explorer/visualizations/index.tsx | 11 +- public/components/metrics/index.scss | 2 +- .../visualizations/visualization.tsx | 2 +- 10 files changed, 184 insertions(+), 112 deletions(-) diff --git a/common/constants/shared.ts b/common/constants/shared.ts index cc7a5147b..be63484ce 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -240,6 +240,7 @@ export const WAITING_TIME_ON_USER_ACTIONS = 300; export const VISUALIZATION_ERROR = { NO_DATA: 'No data found.', INVALID_DATA: 'Invalid visualization data', + NO_SERIES: 'Add a field to start', }; export const S3_DATASOURCE_TYPE = 'S3_DATASOURCE'; diff --git a/public/components/event_analytics/explorer/explorer.scss b/public/components/event_analytics/explorer/explorer.scss index 70a79a3a5..63dfc2b08 100644 --- a/public/components/event_analytics/explorer/explorer.scss +++ b/public/components/event_analytics/explorer/explorer.scss @@ -15,7 +15,7 @@ } .mainContentTabs .euiResizableContainer { - height: calc(100vh - 298px); + height: calc(100vh - 194px); } .explorer-loading-spinner { diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 71d517778..6c683fbf6 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -569,7 +569,7 @@ export const Explorer = ({ explorerFields={explorerFields} timeStampField={queryRef.current![SELECTED_TIMESTAMP]} rawQuery={appBasedRef.current || queryRef.current![RAW_QUERY]} - totalHits={explorerData?.datarows?.length || 0} + totalHits={_.sum(countDistribution.data['count()'])} requestParams={requestParams} startTime={appLogEvents ? startTime : dateRange[0]} endTime={appLogEvents ? endTime : dateRange[1]} diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss b/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss index 7025380fc..f24c6782c 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss +++ b/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss @@ -168,6 +168,15 @@ $vis-editor-sidebar-min-width: 350px; align-items: center; } +.panelItem_box { + color: #5A6875; + display: grid; + grid-gap: 4px; + padding: 8px 8px 8px 8px; + background-color: #D6D9DD; + border-radius: 4px; +} + .field_text { text-overflow: ellipsis; overflow: hidden; diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_config_panel_fields.tsx b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_config_panel_fields.tsx index 4c7f666c5..669a314c8 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_config_panel_fields.tsx +++ b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_config_panel_fields.tsx @@ -12,6 +12,8 @@ import { EuiText, EuiTitle, EuiToolTip, + EuiFormRow, + EuiFormLabel, } from '@elastic/eui'; import { isArray, isEmpty, lowerCase } from 'lodash'; import { @@ -60,7 +62,7 @@ export const DataConfigPanelFields = ({ const { time_field: timeField, unit, interval } = dimensionSpan; - const tooltipIcon = ; + const tooltipIcon = ; const crossIcon = (index: number, configName: string) => ( -
- -

{sectionName}

-
- {infoToolTip(tooltipIcon, DATA_CONFIG_HINTS_INFO[`${sectionName}`])} -
- - {sectionName === GROUPBY && dimensionSpan && !isEmpty(timeField) && ( - - - handleServiceEdit(list.length - 1, GROUPBY, true)} - data-test-subj="viz-config-add-btn" - > - {`${SPAN}(${timeField[0]?.name}, ${interval} ${unit[0]?.value})`} - - - {crossIcon(-1, SPAN)} - - )} - - {isArray(list) && - list.map((obj: ConfigListEntry, index: number) => ( - + + <> +
+ {sectionName} + {infoToolTip(tooltipIcon, DATA_CONFIG_HINTS_INFO[`${sectionName}`])} +
+ +
+ {sectionName === GROUPBY && dimensionSpan && !isEmpty(timeField) && ( handleServiceEdit(index, sectionName, false)} + onClick={() => handleServiceEdit(list.length - 1, GROUPBY, true)} data-test-subj="viz-config-add-btn" > - {removeBacktick( - obj[CUSTOM_LABEL] || `${isAggregation ? obj.aggregation : ''} ${obj.label}` - )} + {`${SPAN}(${timeField[0]?.name}, ${interval} ${unit[0]?.value})`} - {isAggregation - ? infoToolTip(crossIcon(index, sectionName), DATA_CONFIG_HINTS_INFO[AGGREGATIONS]) - : crossIcon(index, sectionName)} + {crossIcon(-1, SPAN)} + + )} + {isArray(list) && + list.map((obj: ConfigListEntry, index: number) => ( + + + + handleServiceEdit(index, sectionName, false)} + data-test-subj="viz-config-add-btn" + > + {removeBacktick( + obj[CUSTOM_LABEL] || `${isAggregation ? obj.aggregation : ''} ${obj.label}` + )} + + + {isAggregation + ? infoToolTip( + crossIcon(index, sectionName), + DATA_CONFIG_HINTS_INFO[AGGREGATIONS] + ) + : crossIcon(index, sectionName)} + + + ))} + {!hideClickToAddButton(sectionName) && ( + + {addButtonText} + handleServiceAdd(sectionName)} + data-test-subj="viz-config-add-btn" + /> - - - ))} - {!hideClickToAddButton(sectionName) && ( - - {addButtonText} - handleServiceAdd(sectionName)} - data-test-subj="viz-config-add-btn" - /> - - )} - -
+ )} + + +
); }; diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.scss b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.scss index cac373f90..6ca8a2e84 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.scss +++ b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.scss @@ -39,4 +39,50 @@ &.showSecondary > .wizConfig__section { transform: translateX(-100%); } +} + +.vbConfig { + @include euiYScrollWithShadows; + + background: $euiColorLightestShade; + border-left: $euiBorderThin; + position: relative; + overflow-x: hidden; + + &__section { + width: 100%; + transition: transform $euiAnimSpeedNormal 0s $euiAnimSlightResistance; + } + + &__title { + padding: $euiSizeS; + padding-bottom: 0; + + &.showDivider { + border-bottom: 1px solid $euiColorLightShade; + } + } + + &__content { + padding: $euiSizeS; + } + + &__aggEditor { + padding: 0 $euiSizeM; + } + + &--secondary { + position: absolute; + top: 0; + left: 0; + padding: $euiSizeS; + + .visEditorAggParam--half { + margin: $euiSize 0; + } + } + + &.showSecondary > .vbConfig__section { + transform: translateX(-100%); + } } \ No newline at end of file diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx index e5374811e..24e10d5d3 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx +++ b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx @@ -16,6 +16,9 @@ import { EuiSpacer, EuiTitle, htmlIdGenerator, + EuiForm, + EuiFlexGroup, + EuiHorizontalRule, } from '@elastic/eui'; import { filter, isEmpty, isEqual } from 'lodash'; import { @@ -340,7 +343,7 @@ export const DataConfigPanelItem = ({ const selectedObj = isTimeStampSelected ? configList[SPAN] : configList[name][index]; const isAggregations = name === AGGREGATIONS; return ( - <> +
- +
); }; @@ -535,49 +538,60 @@ export const DataConfigPanelItem = ({ return isAddConfigClicked ? ( getCommonUI(selectedConfigItem.name) ) : ( - <> - -

Configuration

-
- - {visualizations.vis.name !== VIS_CHART_TYPES.Histogram ? ( - <> - {DataConfigPanelFields(getRenderFieldsObj(AGGREGATIONS))} - - {DataConfigPanelFields(getRenderFieldsObj(GROUPBY))} - - {(visualizations.vis.name === VIS_CHART_TYPES.Bar || - visualizations.vis.name === VIS_CHART_TYPES.HorizontalBar || - visualizations.vis.name === VIS_CHART_TYPES.Line) && ( - <>{DataConfigPanelFields(getRenderFieldsObj(BREAKDOWNS))} - )} - - ) : ( - <> - -

Bucket Size

-
- {getNumberField('bucketSize')} + +
+
+ + + +

Configuration

+
+
+
+
+ {visualizations.vis.name !== VIS_CHART_TYPES.Histogram ? ( +
+ + {DataConfigPanelFields(getRenderFieldsObj(AGGREGATIONS))} + + {DataConfigPanelFields(getRenderFieldsObj(GROUPBY))} + + {(visualizations.vis.name === VIS_CHART_TYPES.Bar || + visualizations.vis.name === VIS_CHART_TYPES.HorizontalBar || + visualizations.vis.name === VIS_CHART_TYPES.Line) && ( + <>{DataConfigPanelFields(getRenderFieldsObj(BREAKDOWNS))} + )} + +
+ ) : ( + <> + +

Bucket Size

+
+ {getNumberField('bucketSize')} - - -

Bucket Offset

-
- {getNumberField('bucketOffset')} - - )} - - - updateChart()} - size="s" - isDisabled={isEmpty(configList[AGGREGATIONS])} - > - Update chart - - - + + +

Bucket Offset

+
+ {getNumberField('bucketOffset')} + + )} + {/* */} +
+ + updateChart()} + size="s" + isDisabled={isEmpty(configList[AGGREGATIONS])} + > + Update chart + + +
+
+
); }; diff --git a/public/components/event_analytics/explorer/visualizations/index.tsx b/public/components/event_analytics/explorer/visualizations/index.tsx index f97db37f3..0b3a6bea5 100644 --- a/public/components/event_analytics/explorer/visualizations/index.tsx +++ b/public/components/event_analytics/explorer/visualizations/index.tsx @@ -93,16 +93,7 @@ export const ExplorerVisualizations = ({ paddingSize="none" className="vis__leftPanel" > -
- {!isMarkDown && ( -
- {renderDataConfigContainer()} -
- )} -
+ {!isMarkDown && <>{renderDataConfigContainer()}} Date: Fri, 20 Oct 2023 09:34:04 -0700 Subject: [PATCH 4/5] add margin to resizable Signed-off-by: Paul Sebastian --- .../explorer/visualizations/config_panel/config_panel.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss b/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss index f24c6782c..8e0032e9f 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss +++ b/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.scss @@ -158,6 +158,7 @@ $vis-editor-sidebar-min-width: 350px; #vis__mainContent .vis__leftPanel { overflow-y: unset; // unset default setting + margin-right: 8px; } .panelItem_button { From 5793db031af6fddf45d9f486ea3c0d265174ad6b Mon Sep 17 00:00:00 2001 From: Paul Sebastian Date: Fri, 20 Oct 2023 10:33:13 -0700 Subject: [PATCH 5/5] pr requested changes Signed-off-by: Paul Sebastian --- .../explorer/sidebar/sidebar.tsx | 19 ++++--------------- .../data_configurations_panel.tsx | 1 - 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/public/components/event_analytics/explorer/sidebar/sidebar.tsx b/public/components/event_analytics/explorer/sidebar/sidebar.tsx index 687815f6e..71049987f 100644 --- a/public/components/event_analytics/explorer/sidebar/sidebar.tsx +++ b/public/components/event_analytics/explorer/sidebar/sidebar.tsx @@ -54,13 +54,13 @@ export const Sidebar = (props: ISidebarProps) => { const [showFields, setShowFields] = useState(false); const [searchTerm, setSearchTerm] = useState(''); - // list of every single field object - const [allFields, setAllFields] = useState([]); - // method to return the type of a field from its name const getFieldTypes = (newFieldName: string) => { let fieldType: string = ''; - allFields.map((field) => { + explorerFields.availableFields.map((field) => { + if (field.name === newFieldName) fieldType = field.type; + }); + explorerFields.selectedFields.map((field) => { if (field.name === newFieldName) fieldType = field.type; }); return fieldType; @@ -129,17 +129,6 @@ export const Sidebar = (props: ISidebarProps) => { [explorerFields, tabId] ); - // this useEffect will set allFields when the page is rendered - useEffect(() => { - if ( - explorerFields.availableFields.length > 0 && - explorerFields.selectedFields.length === 0 && - allFields.length === 0 - ) { - setAllFields(explorerFields.availableFields); - } - }, [explorerFields.availableFields]); - const onDragEnd = ({ destination, source, diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx index 24e10d5d3..d55fedc85 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx +++ b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx @@ -577,7 +577,6 @@ export const DataConfigPanelItem = ({ {getNumberField('bucketOffset')} )} - {/* */}