diff --git a/dashboards-observability/common/constants/explorer.ts b/dashboards-observability/common/constants/explorer.ts
index 9d52923fe..564c68167 100644
--- a/dashboards-observability/common/constants/explorer.ts
+++ b/dashboards-observability/common/constants/explorer.ts
@@ -91,31 +91,31 @@ export const VIZ_CONTAIN_XY_AXIS = [
// default ppl aggregation method options
export const AGGREGATION_OPTIONS = [
{
- label: 'COUNT',
+ label: 'count',
},
{
- label: 'SUM',
+ label: 'sum',
},
{
- label: 'AVERAGE',
+ label: 'avg',
},
{
- label: 'MAX',
+ label: 'max',
},
{
- label: 'MIN',
+ label: 'min',
},
{
- label: 'VAR_SAMP',
+ label: 'var_samp',
},
{
- label: 'VAR_POP',
+ label: 'var_pop',
},
{
- label: 'STDDEV_SAMP',
+ label: 'stddev_samp',
},
{
- label: 'STDDEV_POP',
+ label: 'stddev_pop',
},
];
diff --git a/dashboards-observability/common/query_manager/ast/expression/span.ts b/dashboards-observability/common/query_manager/ast/expression/span.ts
index d69152b44..d2a570915 100644
--- a/dashboards-observability/common/query_manager/ast/expression/span.ts
+++ b/dashboards-observability/common/query_manager/ast/expression/span.ts
@@ -23,6 +23,6 @@ export class Span extends PPLNode {
}
toString(): string {
- return `${this.spanExpression.toString()} as ${this.alias}`;
+ return `${this.spanExpression.toString()}${this.alias ? ` as ${this.alias}` : ''}`;
}
}
diff --git a/dashboards-observability/common/types/explorer.ts b/dashboards-observability/common/types/explorer.ts
index 9d3cb5072..a734d7150 100644
--- a/dashboards-observability/common/types/explorer.ts
+++ b/dashboards-observability/common/types/explorer.ts
@@ -265,12 +265,21 @@ export interface ConfigListEntry {
side: string;
type: string;
}
+
export interface HistogramConfigList {
bucketSize: string;
bucketOffset: string;
}
+export interface DimensionSpan {
+ time_field: IField;
+ interval: number;
+ unit: string;
+}
+
export interface ConfigList {
dimensions?: ConfigListEntry[] | HistogramConfigList[];
metrics?: ConfigListEntry[];
+ breakdowns?: ConfigListEntry[] | HistogramConfigList[];
+ span?: DimensionSpan;
}
diff --git a/dashboards-observability/public/.DS_Store b/dashboards-observability/public/.DS_Store
new file mode 100644
index 000000000..dbd07c1a1
Binary files /dev/null and b/dashboards-observability/public/.DS_Store differ
diff --git a/dashboards-observability/public/components/common/search/autocomplete.tsx b/dashboards-observability/public/components/common/search/autocomplete.tsx
index 3d3fdac26..a8c4007a7 100644
--- a/dashboards-observability/public/components/common/search/autocomplete.tsx
+++ b/dashboards-observability/public/components/common/search/autocomplete.tsx
@@ -185,7 +185,13 @@ export const Autocomplete = (props: AutocompleteProps) => {
-
+
+ {fullWord.slice(0, -item.suggestion.length)}
+ {item.suggestion}
+
+
+ {/*
{
}
`,
}}
- />
+ /> */}
diff --git a/dashboards-observability/public/components/common/search/search.tsx b/dashboards-observability/public/components/common/search/search.tsx
index b4e2ebb16..ed9f85381 100644
--- a/dashboards-observability/public/components/common/search/search.tsx
+++ b/dashboards-observability/public/components/common/search/search.tsx
@@ -16,8 +16,8 @@ import {
EuiBadge,
EuiContextMenuPanel,
EuiToolTip,
+ EuiCallOut
} from '@elastic/eui';
-import _ from 'lodash';
import { DatePicker } from './date_picker';
import '@algolia/autocomplete-theme-classic';
import { Autocomplete } from './autocomplete';
@@ -82,10 +82,10 @@ export const Search = (props: any) => {
stopLive,
setIsLiveTailPopoverOpen,
liveTailName,
+ searchError = null,
} = props;
-
+
const appLogEvents = tabId.match(APP_ANALYTICS_TAB_ID_REGEX);
-
const [isSavePanelOpen, setIsSavePanelOpen] = useState(false);
const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
@@ -247,6 +247,17 @@ export const Search = (props: any) => {
>
)}
+ { searchError && searchError.error && (
+
+
+
+
+ {JSON.parse(searchError.message).error.details}
+
+
+
+ )
+ }
{flyout}
);
diff --git a/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap b/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap
index 24c8f5e45..e31ae697b 100644
--- a/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap
+++ b/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap
@@ -1477,188 +1477,80 @@ exports[`Utils helper functions renders displayVisualization function 1`] = `
}
}
>
-
-
+
-
-
+ className="euiText euiText--extraSmall lnsChart__empty"
+ data-test-subj="vizWorkspace__noData"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No results found
+
+
+
+
+
+
+
+
+
+
@@ -4307,188 +4199,80 @@ exports[`Utils helper functions renders displayVisualization function 3`] = `
}
}
>
-
-
+
-
-
+ className="euiText euiText--extraSmall lnsChart__empty"
+ data-test-subj="vizWorkspace__noData"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No results found
+
+
+
+
+
+
+
+
+
+
@@ -5225,132 +5009,80 @@ exports[`Utils helper functions renders displayVisualization function 4`] = `
}
}
>
-
-
+
-
-
+ className="euiText euiText--extraSmall lnsChart__empty"
+ data-test-subj="vizWorkspace__noData"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No results found
+
+
+
+
+
+
+
+
+
+
diff --git a/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx b/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx
index b375987bf..b1c2751f5 100644
--- a/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx
+++ b/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx
@@ -66,6 +66,7 @@ import { selectFields, updateFields, sortFields } from '../redux/slices/field_sl
import { updateTabName } from '../redux/slices/query_tab_slice';
import { selectCountDistribution } from '../redux/slices/count_distribution_slice';
import { selectExplorerVisualization } from '../redux/slices/visualization_slice';
+import { change as changeVizConfig } from '../redux/slices/viualization_config_slice';
import {
selectVisualizationConfig,
change as changeVisualizationConfig,
@@ -490,6 +491,7 @@ export const Explorer = ({
handleQuerySearch(availability);
};
+
/**
* Toggle fields between selected and unselected sets
* @param field field to be toggled
@@ -821,51 +823,6 @@ export const Explorer = ({
);
};
- const testAntlr = (query: string) => {
- const qm = new QueryManager();
- // const pplQueryBuilder = new PPLQueryBuilder();
-
- // build query
- const res =
- qm
- .queryBuilder()
- .addSource('index')
- .addPipe()
- .addStats()
- .addMetrics([
- {
- field: '',
- agg_func: 'count'
- },
- {
- field: 'bytes',
- agg_func: 'avg',
- alias: 'avg_bytes'
- }
- ])
- .addBy()
- .addGroupBy([{
- field: 'host'
- },
- {
- field: 'tags'
- }
- ])
- .getQuery();
-
- console.log('built res: ', res);
-
- // parse query
- const parsed_res =
- qm
- .queryParser()
- .parse(query)
- .getStats();
-
- console.log('parsed res: ', parsed_res);
-
- };
-
const handleQuerySearch = useCallback(
async (availability?: boolean) => {
@@ -881,10 +838,39 @@ export const Explorer = ({
if (availability !== true) {
await updateQueryInStore(tempQuery);
}
- testAntlr(query[RAW_QUERY]);
- fetchData();
+ await fetchData();
+
+ if (selectedContentTabId === TAB_CHART_ID) {
+ // parse stats section on every search
+ const qm = new QueryManager();
+ const statsTokens =
+ qm
+ .queryParser()
+ .parse(tempQuery)
+ .getStats();
+
+ await dispatch(
+ changeVizConfig({
+ tabId,
+ vizId: curVisId,
+ data: {
+ dataConfig: {
+ metrics: statsTokens.aggregations.map((agg) => ({
+ label: agg.function?.value_expression,
+ name: agg.function?.value_expression,
+ aggregation: agg.function?.name,
+ })),
+ dimensions: statsTokens.groupby?.group_fields?.map((agg) => ({
+ label: agg.name ?? '',
+ name: agg.name ?? '',
+ })),
+ },
+ },
+ })
+ );
+ }
},
- [tempQuery, query[RAW_QUERY]]
+ [tempQuery, query, selectedContentTabId]
);
const handleQueryChange = async (newQuery: string) => setTempQuery(newQuery);
@@ -1197,6 +1183,10 @@ export const Explorer = ({
explorerVisualizations,
setToast,
pplService,
+ handleQuerySearch,
+ handleQueryChange,
+ setTempQuery,
+ fetchData,
explorerFields,
explorerData,
http,
@@ -1236,6 +1226,7 @@ export const Explorer = ({
stopLive={stopLive}
setIsLiveTailPopoverOpen={setIsLiveTailPopoverOpen}
liveTailName={liveTailNameRef.current}
+ searchError={explorerVisualizations}
/>
({
+ name,
+ label: name,
+ type,
+});
export const DataConfigPanelItem = ({ fieldOptionList, visualizations }: any) => {
const dispatch = useDispatch();
- const { tabId, curVisId, changeVisualizationConfig } = useContext(TabContext);
+ const { tabId, handleQuerySearch, handleQueryChange, setTempQuery, fetchData } = useContext(
+ TabContext
+ );
+ const explorerVisualizationConfigs = useSelector(selectVisualizationConfig)[tabId];
const { data } = visualizations;
- const { userConfigs } = data;
-
const { data: vizData = {}, metadata: { fields = [] } = {} } = data?.rawVizData;
-
- const initialConfigEntry = {
- label: '',
- aggregation: '',
- custom_label: '',
- name: '',
- side: 'right',
- type: '',
- };
-
+ const {
+ indexFields: { availableFields },
+ } = data;
const [configList, setConfigList] = useState({});
useEffect(() => {
- if (userConfigs && userConfigs.dataConfig && userConfigs.dataConfig.valueOptions) {
+ if (
+ data.rawVizData?.[visualizations.vis.name] &&
+ data.rawVizData?.[visualizations.vis.name].dataConfig
+ ) {
+ setConfigList((staleState) => {
+ return {
+ ...staleState,
+ ...data.rawVizData[visualizations.vis.name].dataConfig,
+ };
+ });
+ } else if (some(SPECIAL_RENDERING_VIZS, (visType) => visType === visualizations.vis.name)) {
+ // any vis that doesn't conform normal metrics/dimensions data confiurations
setConfigList({
- ...userConfigs.dataConfig.valueOptions,
+ ...DEFAULT_DATA_CONFIGS[visualizations.vis.name],
});
+ } else {
+ // default
+ const qm = new QueryManager();
+ const statsTokens = qm.queryParser().parse(data.query.rawQuery).getStats();
+ if (!statsTokens) {
+ setConfigList({
+ metrics: [],
+ dimensions: [],
+ });
+ } else {
+ const fieldInfo = statsTokens.groupby?.span?.span_expression?.field;
+ setConfigList({
+ metrics: statsTokens.aggregations.map((agg) => ({
+ alias: agg.alias,
+ label: agg.function?.value_expression,
+ name: agg.function?.value_expression,
+ aggregation: agg.function?.name,
+ })),
+ dimensions: statsTokens.groupby?.group_fields?.map((agg) => ({
+ label: agg.name ?? '',
+ name: agg.name ?? '',
+ })),
+ span: {
+ time_field: statsTokens.groupby?.span?.span_expression?.field
+ ? [getStandardedOuiField(fieldInfo, 'timestamp')]
+ : [],
+ interval: statsTokens.groupby?.span?.span_expression?.literal_value ?? '0',
+ unit: statsTokens.groupby?.span?.span_expression?.time_unit
+ ? [getStandardedOuiField(statsTokens.groupby?.span?.span_expression?.time_unit)]
+ : [],
+ },
+ });
+ }
}
- }, [userConfigs?.dataConfig?.valueOptions, visualizations.vis.name]);
+ }, [
+ data.defaultAxes,
+ data.rawVizData?.[visualizations.vis.name]?.dataConfig,
+ visualizations.vis.name,
+ ]);
const updateList = (value: string, index: number, name: string, field: string) => {
- let list = { ...configList };
+ const list = { ...configList };
let listItem = { ...list[name][index] };
listItem = {
...listItem,
@@ -79,7 +162,7 @@ export const DataConfigPanelItem = ({ fieldOptionList, visualizations }: any) =>
const updateHistogramConfig = (configName: string, fieldName: string, value: string) => {
const list = { ...configList };
- let listItem = { ...list[configName][0] };
+ const listItem = { ...list[configName][0] };
listItem[fieldName] = value;
const updatedList = {
...list,
@@ -101,35 +184,47 @@ export const DataConfigPanelItem = ({ fieldOptionList, visualizations }: any) =>
setConfigList(updatedList);
};
- const updateChart = () => {
- dispatch(
- changeVisualizationConfig({
- tabId,
- vizId: curVisId,
- data: {
- ...userConfigs,
- dataConfig: {
- ...userConfigs.dataConfig,
- valueOptions: {
- dimensions: configList.dimensions,
- metrics: configList.metrics,
+ const updateChart = (updatedConfigList = configList) => {
+ const qm = new QueryManager();
+ const statsTokens = qm.queryParser().parse(data.query.rawQuery).getStats();
+ const newQuery = qm
+ .queryBuilder()
+ .build(data.query.rawQuery, composeAggregations(updatedConfigList, statsTokens));
+
+ batch(async () => {
+ await handleQueryChange(newQuery);
+ await dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ ...data.query,
+ [RAW_QUERY]: newQuery,
+ },
+ })
+ );
+ await fetchData();
+ await dispatch(
+ changeVizConfig({
+ tabId,
+ vizId: visualizations.vis.name,
+ data: {
+ dataConfig: {
+ metrics: updatedConfigList.metrics,
+ dimensions: updatedConfigList.dimensions,
+ breakdowns: updatedConfigList.breakdowns,
+ span: updatedConfigList.span,
},
},
- },
- })
- );
+ })
+ );
+ });
};
const isPositionButtonVisible = (sectionName: string) =>
- sectionName === 'metrics' &&
- (visualizations.vis.name === visChartTypes.Line ||
- visualizations.vis.name === visChartTypes.Scatter);
+ sectionName === 'metrics' && visualizations.vis.name === visChartTypes.Line;
const getOptionsAvailable = (sectionName: string) => {
- let selectedFields = {};
- for (const key in configList) {
- configList[key] && configList[key].forEach((field) => (selectedFields[field.label] = true));
- }
+ const selectedFields = {};
const unselectedFields = fieldOptionList.filter((field) => !selectedFields[field.label]);
return sectionName === 'metrics'
? unselectedFields
@@ -138,106 +233,133 @@ export const DataConfigPanelItem = ({ fieldOptionList, visualizations }: any) =>
: unselectedFields;
};
- const getCommonUI = (lists, sectionName: string) =>
- lists &&
- lists.map((singleField, index: number) => (
-
-
-
- {sectionName === 'dimensions' && visualizations.vis.name === visChartTypes.HeatMap && (
-
- {index === 0 ? 'X-Axis' : 'Y-Axis'}
-
- )}
-
- {sectionName == 'metrics' && (
-
- handleServiceRemove(index, sectionName)}
- />
-
- )
- }
- >
-
- updateList(e.length > 0 ? e[0].label : '', index, sectionName, 'aggregation')
- }
- />
-
- )}
-
-
- updateList(e.length > 0 ? e[0].label : '', index, sectionName, 'label')
- }
- />
-
-
-
- updateList(e.target.value, index, sectionName, 'custom_label')}
- aria-label="Use aria labels when no actual label is in use"
- />
-
-
- {isPositionButtonVisible(sectionName) && (
-
- updateList(id, index, sectionName, 'side')}
- />
-
- )}
+ const getCommonUI = (lists, sectionName: string) => {
+ return (
+ <>
+ {Array.isArray(lists) &&
+ lists.map((singleField, index: number) => (
+ <>
+
+
+ {sectionName === 'dimensions' &&
+ visualizations.vis.name === visChartTypes.HeatMap && (
+
+ {index === 0 ? 'X-Axis' : 'Y-Axis'}
+
+ )}
+
+ {sectionName === 'metrics' && (
+
+ handleServiceRemove(index, sectionName)}
+ />
+
+ )
+ }
+ >
+
+ updateList(
+ e.length > 0 ? e[0].label : '',
+ index,
+ sectionName,
+ 'aggregation'
+ )
+ }
+ />
+
+ )}
+
+ handleServiceRemove(index, sectionName)}
+ />
+
+ )
+ }
+ >
+
+ updateList(e.length > 0 ? e[0].label : '', index, sectionName, 'label')
+ }
+ />
+
+
+
+ updateList(e.target.value, index, sectionName, 'custom_label')
+ }
+ aria-label="Use aria labels when no actual label is in use"
+ />
+
+ {isPositionButtonVisible(sectionName) && (
+
+
+ updateList(id, index, sectionName, 'side')
+ }
+ />
+
+ )}
+
+
+
+
- {visualizations.vis.name !== visChartTypes.HeatMap && lists.length - 1 === index && (
-
- handleServiceAdd(sectionName)}
- disabled={
- sectionName === 'dimensions' && visualizations.vis.name === visChartTypes.Line
- }
- >
- Add
-
-
- )}
-
-
-
-
-
- ));
+ >
+ ))}
+ {visualizations.vis.name !== visChartTypes.HeatMap && (
+
+ handleServiceAdd(sectionName)}
+ disabled={
+ sectionName === 'dimensions' && visualizations.vis.name === visChartTypes.Line
+ }
+ >
+ Add
+
+
+ )}
+ >
+ );
+ };
const getNumberField = (type: string) => (
<>
@@ -259,6 +381,124 @@ export const DataConfigPanelItem = ({ fieldOptionList, visualizations }: any) =>
>
);
+ const getBreakDownFields = useCallback(
+ (configList) => {
+ return configList.dimensions;
+ },
+ [configList.dimensions]
+ );
+
+ const Breakdowns = useMemo(() => {
+ return (
+ <>
+
+
+
+
+ {
+ setConfigList((staleState) => {
+ return {
+ ...staleState,
+ breakdowns: fields,
+ };
+ });
+ }}
+ />
+
+
+
+
+ >
+ );
+ }, [configList.dimensions, configList.breakdowns]);
+
+ const DateHistogram = useMemo(() => {
+ return (
+ <>
+
+
+
+
+ idxField.type === 'timestamp')
+ .map((field) => ({ ...field, label: field.name }))}
+ selectedOptions={
+ configList.span?.time_field ? [...configList.span?.time_field] : []
+ }
+ onChange={(field) => {
+ setConfigList((staleState) => {
+ return {
+ ...staleState,
+ span: {
+ ...staleState.span,
+ time_field: field,
+ },
+ };
+ });
+ }}
+ />
+
+
+ {
+ setConfigList((staleState) => {
+ return {
+ ...staleState,
+ span: {
+ ...staleState.span,
+ interval: e.target.value,
+ },
+ };
+ });
+ }}
+ aria-label="Use aria labels when no actual label is in use"
+ />
+
+
+ {
+ return {
+ ...option,
+ label: option.text,
+ };
+ })}
+ selectedOptions={configList.span?.unit ? [...configList.span?.unit] : []}
+ onChange={(unit) => {
+ setConfigList((staleState) => {
+ return {
+ ...staleState,
+ span: {
+ ...staleState.span,
+ unit,
+ },
+ };
+ });
+ }}
+ />
+
+
+
+
+ >
+ );
+ }, [availableFields, configList.span]);
+
return (
<>
@@ -267,16 +507,26 @@ export const DataConfigPanelItem = ({ fieldOptionList, visualizations }: any) =>
{visualizations.vis.name !== visChartTypes.Histogram ? (
<>
+
+ Series
+
+
+ {getCommonUI(configList.metrics, 'metrics')}
+
Dimensions
+
{getCommonUI(configList.dimensions, 'dimensions')}
-
- Metrics
+ Date Histogram
- {getCommonUI(configList.metrics, 'metrics')}
+ {DateHistogram}
+ {/*
+ Breakdowns
+
+ {Breakdowns} */}
>
) : (
<>
@@ -292,11 +542,12 @@ export const DataConfigPanelItem = ({ fieldOptionList, visualizations }: any) =>
{getNumberField('bucketOffset')}
>
)}
+
updateChart()}
size="s"
>
Update chart
diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/index.tsx b/dashboards-observability/public/components/event_analytics/explorer/visualizations/index.tsx
index 2aa7c062d..2e51c1a7e 100644
--- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/index.tsx
+++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/index.tsx
@@ -52,7 +52,8 @@ export const ExplorerVisualizations = ({
const { data, vis } = visualizations;
const { data: vizData = {}, metadata: { fields = [] } = {} } = data?.rawVizData;
- const fieldOptionList = fields.map((field) => {
+ const fieldOptionList = explorerFields.availableFields.map((field) => {
+ // const fieldOptionList = fields.map((field) => {
return { ...field, label: field.name };
});
diff --git a/dashboards-observability/public/components/event_analytics/hooks/use_fetch_visualizations.ts b/dashboards-observability/public/components/event_analytics/hooks/use_fetch_visualizations.ts
index 866921201..446bcf229 100644
--- a/dashboards-observability/public/components/event_analytics/hooks/use_fetch_visualizations.ts
+++ b/dashboards-observability/public/components/event_analytics/hooks/use_fetch_visualizations.ts
@@ -37,7 +37,8 @@ export const useFetchVisualizations = ({
const fetchVisualizations = async (
{ query }: { query: string },
format: string,
- handler: (res: any) => void
+ successHandler: (res: any) => void,
+ errorHandler: (error: any) => void
) => {
setIsVisLoading(true);
@@ -45,16 +46,16 @@ export const useFetchVisualizations = ({
.fetch({
query,
format,
+ }, (error) => {
+ errorHandler(error);
+ setIsVisLoading(false);
})
.then((res: any) => {
- handler(res);
- })
- .catch((err: any) => {
- console.error(err);
- })
- .finally(() => {
+ if (res && res.status === 200) {
+ successHandler(res);
+ }
setIsVisLoading(false);
- });
+ })
};
const getCountVisualizations = (interval: string) => {
@@ -74,7 +75,8 @@ export const useFetchVisualizations = ({
data: res,
})
);
- }
+ },
+ (error: Error) => {}
);
};
@@ -118,6 +120,14 @@ export const useFetchVisualizations = ({
})
);
});
+ },
+ (error: any) => {
+ dispatch(
+ renderExplorerVis({
+ tabId: requestParams.tabId,
+ data: error.body,
+ })
+ );
}
);
};
diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap
index 34b400f3a..9a88fe43b 100644
--- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap
@@ -533,9 +533,7 @@ exports[`Bar component Renders bar component 1`] = `
}
}
>
-
+