diff --git a/src/webviews/QueryEditor/ResultPanel/IndexMetricsView.tsx b/src/webviews/QueryEditor/ResultPanel/IndexMetricsView.tsx
new file mode 100644
index 000000000..e2fcdb3d4
--- /dev/null
+++ b/src/webviews/QueryEditor/ResultPanel/IndexMetricsView.tsx
@@ -0,0 +1,163 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import {
+ Label,
+ Link,
+ Table,
+ TableBody,
+ TableCell,
+ TableHeader,
+ TableHeaderCell,
+ TableRow,
+} from '@fluentui/react-components';
+import type React from 'react';
+
+interface IndexMetricsSection {
+ title: string;
+ indexes: { [key: string]: string }[];
+}
+
+interface IndexMetrics {
+ title: string;
+ sections: IndexMetricsSection[];
+}
+
+const INDEX_METRICS_DOC_URL = 'https://learn.microsoft.com/azure/cosmos-db/nosql/index-metrics';
+
+export const IndexMetricsView: React.FC<{ indexMetricsStr: string; topLabelStyle?: string }> = ({
+ indexMetricsStr,
+ topLabelStyle,
+}) => {
+ // TODO Uncomment this example for testing
+ //indexMetricsStr = "Index Utilization Information\n Utilized Single Indexes\n Index Spec: /name/?\n Index Impact Score: High\n ---\n Index Spec: /age/?\n Index Impact Score: High\n ---\n Index Spec: /town/?\n Index Impact Score: High\n ---\n Index Spec: /timestamp/?\n Index Impact Score: High\n ---\n Potential Single Indexes\n Utilized Composite Indexes\n Potential Composite Indexes\n Index Spec: /name ASC, /town ASC, /age ASC\n Index Impact Score: High\n ---\n Index Spec: /name ASC, /town ASC, /timestamp ASC\n Index Impact Score: High\n ---"
+ const parsed = parseIndexMetrics(indexMetricsStr);
+ const columns = ['Index Spec', 'Index Impact Score'];
+
+ return (
+ <>
+
+ (Learn More…)
+
+
+
+
+
+ Metric
+
+
+
+
+ {columns.map((column) => (
+ {column}
+ ))}
+
+
+
+
+
+
+
+ {parsed.sections.map((section) => (
+
+ {section.title}
+
+ {section.indexes && section.indexes.length > 0 ? (
+
+
+ {section.indexes.map((cosmosdbIndex, index) => (
+
+ {columns.map((column) => (
+ {cosmosdbIndex[column]}
+ ))}
+
+ ))}
+
+
+ ) : (
+ '-'
+ )}
+
+
+ ))}
+
+
+ >
+ );
+};
+
+/**
+Parse the indexMetricsStr and display the following information in a table format:
+Index Utilization Information
+ Utilized Single Indexes
+ Index Spec: /type/?
+ Index Impact Score: High
+ ---
+ Potential Single Indexes
+ Utilized Composite Indexes
+ Potential Composite Indexes
+*/
+
+const oneSpace = ' ';
+const twoSpaces = oneSpace.repeat(2);
+const fourSpaces = oneSpace.repeat(4);
+
+const parseIndexMetrics = (indexMetricsStr: string): IndexMetrics => {
+ const lines = indexMetricsStr.split('\n');
+ let title: string = '';
+ const sections: IndexMetricsSection[] = [];
+
+ let currentSection: IndexMetricsSection | undefined = undefined;
+ let currentIndex: { [key: string]: string } | undefined = undefined;
+
+ for (const line of lines) {
+ if (line.length === 0) {
+ continue;
+ }
+ if (line[0] !== oneSpace) {
+ title = line;
+ continue;
+ }
+
+ if (line.startsWith(twoSpaces) && line[twoSpaces.length] !== oneSpace) {
+ currentSection = {
+ title: line.trim(),
+ indexes: [],
+ };
+ currentIndex = undefined;
+
+ sections.push(currentSection);
+ continue;
+ }
+
+ if (line.startsWith(fourSpaces) && line[fourSpaces.length] !== oneSpace && currentSection) {
+ if (line === `${fourSpaces}---`) {
+ currentIndex = undefined;
+ continue;
+ }
+
+ if (!currentIndex) {
+ currentIndex = {};
+ currentSection.indexes.push(currentIndex);
+ }
+
+ const [key, value] = line.split(':');
+ if (value !== undefined) {
+ currentIndex[key.trim()] = value.trim();
+ }
+ continue;
+ }
+ }
+
+ return {
+ title,
+ sections,
+ };
+};
diff --git a/src/webviews/QueryEditor/ResultPanel/StatsTab.tsx b/src/webviews/QueryEditor/ResultPanel/StatsTab.tsx
index 825b4b43f..fa9d12107 100644
--- a/src/webviews/QueryEditor/ResultPanel/StatsTab.tsx
+++ b/src/webviews/QueryEditor/ResultPanel/StatsTab.tsx
@@ -5,6 +5,7 @@
import {
Label,
+ Link,
makeStyles,
Table,
TableBody,
@@ -17,6 +18,7 @@ import {
} from '@fluentui/react-components';
import { queryMetricsToTable } from '../../utils';
import { useQueryEditorState } from '../state/QueryEditorContext';
+import { IndexMetricsView } from './IndexMetricsView';
const useStyles = makeStyles({
topLabel: {
@@ -39,12 +41,12 @@ const useStyles = makeStyles({
panel1: {
flexGrow: '1',
flexShrink: '1',
- flexBasis: '70%',
+ flexBasis: '49%',
},
panel2: {
flexGrow: '1',
flexShrink: '1',
- flexBasis: '28%',
+ flexBasis: '49%',
},
});
@@ -53,13 +55,15 @@ export const StatsTab = () => {
const state = useQueryEditorState();
const items = queryMetricsToTable(state.currentQueryResult);
const indexMetrics = state.currentQueryResult?.indexMetrics?.trim();
+ const QUERY_METRICS_DOC_URL = 'https://learn.microsoft.com/azure/cosmos-db/nosql/query-metrics';
return (
<>
-
+ (
+ Learn More…)
@@ -89,14 +93,11 @@ export const StatsTab = () => {
-
-
-
+ {indexMetrics && (
+
+
-
-
+ )}
>
);