changes after code review

This commit is contained in:
Archie Agarwal
2025-06-23 11:13:48 +05:30
parent 03eea3b0c2
commit 9008dd2ce4
2 changed files with 207 additions and 177 deletions
@@ -1,5 +1,4 @@
import { IPivotItemProps, IPivotProps, Pivot, PivotItem } from "@fluentui/react"; import { IPivotItemProps, IPivotProps, Pivot, PivotItem } from "@fluentui/react";
import { readCollection } from "Common/dataAccess/readCollection";
import { import {
ComputedPropertiesComponent, ComputedPropertiesComponent,
ComputedPropertiesComponentProps, ComputedPropertiesComponentProps,
@@ -304,9 +303,10 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
if (this.props.settingsTab.isActive()) { if (this.props.settingsTab.isActive()) {
useCommandBar.getState().setContextButtons(this.getTabsButtons()); useCommandBar.getState().setContextButtons(this.getTabsButtons());
} }
this.unsubscribe = useIndexingPolicyStore.subscribe((state) => { this.unsubscribe = useIndexingPolicyStore.subscribe((_,) => {
this.refreshCollectionData(); this.refreshCollectionData();
}); },
(state) => state.indexingPolicy);
this.refreshCollectionData(); this.refreshCollectionData();
} }
componentWillUnmount(): void { componentWillUnmount(): void {
@@ -934,15 +934,23 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
); );
}; };
private refreshCollectionData = async (): Promise<void> => { private refreshCollectionData = async (): Promise<void> => {
// Fetch the latest collection data from backend const storePolicy = useIndexingPolicyStore.getState().indexingPolicy;
const latestCollection = await readCollection(this.collection.databaseId, this.collection.id()); if (!storePolicy) {
// Update the observable and state console.warn("No indexing policy found in store.");
this.collection.rawDataModel = latestCollection; return;
this.collection.indexingPolicy(latestCollection.indexingPolicy); }
// console.log("Fetched latest indexing policy:", latestCollection.indexingPolicy); const indexingPolicy: DataModels.IndexingPolicy = {
...storePolicy,
automatic: storePolicy.automatic ?? true,
indexingMode: storePolicy.indexingMode ?? "consistent",
includedPaths: storePolicy.includedPaths ?? [],
excludedPaths: storePolicy.excludedPaths ?? [],
};
this.collection.indexingPolicy(indexingPolicy);
this.setState({ this.setState({
indexingPolicyContent: latestCollection.indexingPolicy, indexingPolicyContent: indexingPolicy,
indexingPolicyContentBaseline: latestCollection.indexingPolicy, indexingPolicyContentBaseline: indexingPolicy,
}); });
}; };
+188 -166
View File
@@ -1,3 +1,4 @@
import type { CompositePath, IndexingPolicy } from "@azure/cosmos";
import { FontIcon } from "@fluentui/react"; import { FontIcon } from "@fluentui/react";
import { import {
Button, Button,
@@ -35,8 +36,9 @@ import { logConsoleProgress } from "Utils/NotificationConsoleUtils";
import create from "zustand"; import create from "zustand";
import { client } from "../../../Common/CosmosClient"; import { client } from "../../../Common/CosmosClient";
import { handleError } from "../../../Common/ErrorHandlingUtils"; import { handleError } from "../../../Common/ErrorHandlingUtils";
import * as DataModels from "../../../Contracts/DataModels"; import { useIndexAdvisorStyles } from "./indexadv";
import { ResultsViewProps } from "./QueryResultSection"; import { ResultsViewProps } from "./QueryResultSection";
enum ResultsTabs { enum ResultsTabs {
Results = "results", Results = "results",
QueryStats = "queryStats", QueryStats = "queryStats",
@@ -538,17 +540,17 @@ interface IIndexMetric {
index: string; index: string;
impact: string; impact: string;
section: "Included" | "Not Included" | "Header"; section: "Included" | "Not Included" | "Header";
path?: string;
composite?: { path: string; order: string }[];
} }
interface IndexAdvisorTabProps { export const IndexAdvisorTab: React.FC = () => {
onPolicyUpdated: (newPolicy: DataModels.IndexingPolicy) => void; const style = useIndexAdvisorStyles();
}
const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) => {
const { userQuery, databaseId, containerId } = useQueryMetadataStore(); const { userQuery, databaseId, containerId } = useQueryMetadataStore();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [indexMetrics, setIndexMetrics] = useState<any>(null); const [indexMetrics, setIndexMetrics] = useState<string | null>(null);
const [showIncluded, setShowIncluded] = useState(true); const [showIncluded, setShowIncluded] = useState(true);
const [showNotIncluded, setShowNotIncluded] = useState(true); const [showNotIncluded, setShowNotIncluded] = useState(true);
const [selectedIndexes, setSelectedIndexes] = useState<any[]>([]); const [selectedIndexes, setSelectedIndexes] = useState<IIndexMetric[]>([]);
const [selectAll, setSelectAll] = useState(false); const [selectAll, setSelectAll] = useState(false);
const [updateMessageShown, setUpdateMessageShown] = useState(false); const [updateMessageShown, setUpdateMessageShown] = useState(false);
const [included, setIncludedIndexes] = useState<IIndexMetric[]>([]); const [included, setIncludedIndexes] = useState<IIndexMetric[]>([]);
@@ -569,10 +571,8 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
}) })
.fetchAll(); .fetchAll();
setIndexMetrics(sdkResponse.indexMetrics); setIndexMetrics(sdkResponse.indexMetrics);
console.log("Index Metrics:", sdkResponse.indexMetrics); console.log(sdkResponse.indexMetrics);
// console.log("Query Results:", sdkResponse.resources);
console.log(typeof sdkResponse.indexMetrics); console.log(typeof sdkResponse.indexMetrics);
console.log(typeof sdkResponse.resources)
} catch (error) { } catch (error) {
handleError(error, "queryItemsWithIndexMetrics", `Error querying items from ${containerId}`); handleError(error, "queryItemsWithIndexMetrics", `Error querying items from ${containerId}`);
} finally { } finally {
@@ -585,11 +585,125 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
} }
}, [userQuery, databaseId, containerId]); }, [userQuery, databaseId, containerId]);
// useEffect(() => {
// if (!indexMetrics) { return };
// const included: IIndexMetric[] = [];
// const notIncluded: IIndexMetric[] = [];
// const lines = indexMetrics.split("\n").map((line: string) => line.trim()).filter(Boolean);
// let currentSection = "";
// for (let i = 0; i < lines.length; i++) {
// const line = lines[i];
// if (line.startsWith("Utilized Single Indexes") || line.startsWith("Utilized Composite Indexes")) {
// currentSection = "included";
// } else if (line.startsWith("Potential Single Indexes") || line.startsWith("Potential Composite Indexes")) {
// currentSection = "notIncluded";
// } else if (line.startsWith("Index Spec:")) {
// const index = line.replace("Index Spec:", "").trim();
// const impactLine = lines[i + 1];
// const impact = impactLine?.includes("Index Impact Score:") ? impactLine.split(":")[1].trim() : "Unknown";
// const isComposite = index.includes(",");
// const indexObj: any = { index, impact };
// if (isComposite) {
// indexObj.composite = index.split(",").map((part: string) => {
// const [path, order] = part.trim().split(/\s+/);
// return {
// path: path.trim(),
// order: order?.toLowerCase() === "desc" ? "descending" : "ascending",
// };
// });
// } else {
// let path = "/unknown/*";
// const pathRegex = /\/[^\/\s*?]+(?:\/[^\/\s*?]+)*(\/\*|\?)/;
// const match = index.match(pathRegex);
// if (match) {
// path = match[0];
// } else {
// const simplePathRegex = /\/[^\/\s]+/;
// const simpleMatch = index.match(simplePathRegex);
// if (simpleMatch) {
// path = simpleMatch[0] + "/*";
// }
// }
// indexObj.path = path;
// }
// if (currentSection === "included") {
// included.push(indexObj);
// } else if (currentSection === "notIncluded") {
// notIncluded.push(indexObj);
// }
// }
// }
// setIncludedIndexes(included);
// setNotIncludedIndexes(notIncluded);
// }, [indexMetrics]);
useEffect(() => { useEffect(() => {
if (!indexMetrics) return; if (!indexMetrics) return;
const included: any[] = []; let metricsObj: any = indexMetrics;
const notIncluded: any[] = []; if (typeof indexMetrics === "string" && indexMetrics.trim().startsWith("{")) {
try {
metricsObj = JSON.parse(indexMetrics);
console.log("Parsed index metrics as JSON:", metricsObj);
} catch {
metricsObj = null;
}
}
if (metricsObj && typeof metricsObj === "object" && metricsObj.UtilizedIndexes) {
const included: IIndexMetric[] = [];
const notIncluded: IIndexMetric[] = [];
metricsObj.UtilizedIndexes.SingleIndexes?.forEach((si: any) => {
included.push({
index: si.IndexSpec,
impact: "",
section: "Included",
path: si.IndexSpec,
});
});
metricsObj.UtilizedIndexes.CompositeIndexes?.forEach((ci: any) => {
included.push({
index: ci.IndexSpecs.join(", "),
impact: "",
section: "Included",
composite: ci.IndexSpecs.map((spec: string) => {
const [path, order] = spec.split(" ");
return { path, order: (order || "ASC").toLowerCase() === "desc" ? "descending" : "ascending" };
}),
});
});
metricsObj.PotentialIndexes.SingleIndexes?.forEach((si: any) => {
notIncluded.push({
index: si.IndexSpec,
impact: si.IndexImpactScore || "",
section: "Not Included",
path: si.IndexSpec,
});
});
metricsObj.PotentialIndexes.CompositeIndexes?.forEach((ci: any) => {
notIncluded.push({
index: ci.IndexSpecs.join(", "),
impact: ci.IndexImpactScore || "",
section: "Not Included",
composite: ci.IndexSpecs.map((spec: string) => {
const [path, order] = spec.split(" ");
return { path, order: (order || "ASC").toLowerCase() === "desc" ? "descending" : "ascending" };
}),
});
});
setIncludedIndexes(included);
setNotIncludedIndexes(notIncluded);
return;
}
const included: IIndexMetric[] = [];
const notIncluded: IIndexMetric[] = [];
const lines = indexMetrics.split("\n").map((line: string) => line.trim()).filter(Boolean); const lines = indexMetrics.split("\n").map((line: string) => line.trim()).filter(Boolean);
let currentSection = ""; let currentSection = "";
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
@@ -639,13 +753,12 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
setIncludedIndexes(included); setIncludedIndexes(included);
setNotIncludedIndexes(notIncluded); setNotIncludedIndexes(notIncluded);
}, [indexMetrics]); }, [indexMetrics]);
useEffect(() => { useEffect(() => {
const allSelected = notIncluded.length > 0 && notIncluded.every((item) => selectedIndexes.some((s) => s.index === item.index)); const allSelected = notIncluded.length > 0 && notIncluded.every((item) => selectedIndexes.some((s) => s.index === item.index));
setSelectAll(allSelected); setSelectAll(allSelected);
}, [selectedIndexes, notIncluded]); }, [selectedIndexes, notIncluded]);
const handleCheckboxChange = (indexObj: any, checked: boolean) => { const handleCheckboxChange = (indexObj: IIndexMetric, checked: boolean) => {
if (checked) { if (checked) {
setSelectedIndexes((prev) => [...prev, indexObj]); setSelectedIndexes((prev) => [...prev, indexObj]);
} else { } else {
@@ -661,31 +774,28 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
}; };
const handleUpdatePolicy = async () => { const handleUpdatePolicy = async () => {
if (selectedIndexes.length === 0) {
console.log("No indexes selected for update");
return;
}
try { try {
const { resource: containerDef } = await client() const containerRef = client().database(databaseId).container(containerId);
.database(databaseId) const { resource: containerDef } = await containerRef.read();
.container(containerId)
.read();
// console.log("def1", containerDef.indexingPolicy);
const newIncludedPaths = selectedIndexes const newIncludedPaths = selectedIndexes
.filter(index => !index.composite) .filter(index => !index.composite)
.map(index => { .map(index => {
return { return {
path: index.path, path: index.path,
}; };
}); });
const newCompositeIndexes = selectedIndexes const newCompositeIndexes: CompositePath[][] = selectedIndexes
.filter(index => index.composite) .filter(index => Array.isArray(index.composite))
.map(index => index.composite); .map(index =>
(index.composite as { path: string; order: string }[]).map(comp => ({
path: comp.path,
order: comp.order === "descending" ? "descending" : "ascending",
})) as CompositePath[]
);
const updatedPolicy = { const updatedPolicy: IndexingPolicy = {
...containerDef.indexingPolicy, ...containerDef.indexingPolicy,
includedPaths: [ includedPaths: [
...(containerDef.indexingPolicy?.includedPaths || []), ...(containerDef.indexingPolicy?.includedPaths || []),
@@ -699,71 +809,45 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
indexingMode: containerDef.indexingPolicy?.indexingMode ?? "consistent", indexingMode: containerDef.indexingPolicy?.indexingMode ?? "consistent",
excludedPaths: containerDef.indexingPolicy?.excludedPaths ?? [], excludedPaths: containerDef.indexingPolicy?.excludedPaths ?? [],
}; };
await containerRef.replace({
id: containerId,
partitionKey: containerDef.partitionKey,
indexingPolicy: updatedPolicy,
});
await client()
.database(databaseId)
.container(containerId)
.replace({
id: containerId,
partitionKey: containerDef.partitionKey,
indexingPolicy: updatedPolicy,
});
useIndexingPolicyStore.getState().setIndexingPolicyOnly(updatedPolicy); useIndexingPolicyStore.getState().setIndexingPolicyOnly(updatedPolicy);
// console.log("Indexing policy successfully updated:", updatedPolicy); const selectedIndexSet = new Set(selectedIndexes.map(s => s.index));
const { resource: containerDef2 } = await client() const updatedNotIncluded: typeof notIncluded = [];
.database(databaseId) const newlyIncluded: typeof included = [];
.container(containerId) for (const item of notIncluded) {
.read(); if (selectedIndexSet.has(item.index)) {
onPolicyUpdated(containerDef2.indexingPolicy as DataModels.IndexingPolicy); newlyIncluded.push(item);
// console.log("def2", containerDef2.indexingPolicy); } else {
updatedNotIncluded.push(item);
const newIncluded = [...included, ...notIncluded.filter(item => }
selectedIndexes.find(s => s.index === item.index) }
)]; const newIncluded = [...included, ...newlyIncluded];
const newNotIncluded = notIncluded.filter(item => const newNotIncluded = updatedNotIncluded;
!selectedIndexes.find(s => s.index === item.index) setIncludedIndexes(newIncluded);
); setNotIncludedIndexes(newNotIncluded);
setSelectedIndexes([]); setSelectedIndexes([]);
setSelectAll(false); setSelectAll(false);
setIndexMetricsFromParsed(newIncluded, newNotIncluded);
setUpdateMessageShown(true); setUpdateMessageShown(true);
} catch (err) { } catch (err) {
console.error("Failed to update indexing policy:", err); console.error("Failed to update indexing policy:", err);
} }
}; };
const setIndexMetricsFromParsed = (included: { index: string; impact: string }[], notIncluded: { index: string; impact: string }[]) => {
const serialize = (sectionTitle: string, items: { index: string; impact: string }[], isUtilized: boolean) =>
items.length
? `${sectionTitle}\n` +
items
.map((item) => `Index Spec: ${item.index}\nIndex Impact Score: ${item.impact}`)
.join("\n") + "\n"
: "";
const composedMetrics =
serialize("Utilized Single Indexes", included, true) +
serialize("Potential Single Indexes", notIncluded, false);
setIndexMetrics(composedMetrics.trim());
};
const renderImpactDots = (impact: string) => { const renderImpactDots = (impact: string) => {
let count = 0; let count = 0;
if (impact === "High") count = 3; if (impact === "High") count = 3;
else if (impact === "Medium") count = 2; else if (impact === "Medium") count = 2;
else if (impact === "Low") count = 1; else if (impact === "Low") count = 1;
return ( return (
<div style={{ display: "flex", alignItems: "center", gap: "4px" }}> <div className={style.indexAdvisorImpactDots}>
{Array.from({ length: count }).map((_, i) => ( {Array.from({ length: count }).map((_, i) => (
<CircleFilled <CircleFilled
key={i} key={i}
style={{ className={style.indexAdvisorImpactDot}
color: "#0078D4",
fontSize: "12px",
display: "inline-flex",
}}
/> />
))} ))}
</div> </div>
@@ -773,30 +857,21 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
const renderRow = (item: IIndexMetric, index: number) => { const renderRow = (item: IIndexMetric, index: number) => {
const isHeader = item.section === "Header"; const isHeader = item.section === "Header";
const isNotIncluded = item.section === "Not Included"; const isNotIncluded = item.section === "Not Included";
const isIncluded = item.section === "Included";
return ( return (
<TableRow key={index}> <TableRow key={index}>
<TableCell colSpan={2}> <TableCell colSpan={2}>
<div <div className={style.indexAdvisorGrid}>
style={{
display: "grid",
gridTemplateColumns: "30px 30px 1fr 50px 120px",
alignItems: "center",
gap: "8px",
}}>
{isNotIncluded ? ( {isNotIncluded ? (
<Checkbox <Checkbox
checked={selectedIndexes.some((selected) => selected.index === item.index)} checked={selectedIndexes.some((selected) => selected.index === item.index)}
onChange={(_, data) => handleCheckboxChange(item, data.checked === true)} onChange={(_, data) => handleCheckboxChange(item, data.checked === true)} />
/>
) : isHeader && item.index === "Not Included in Current Policy" && notIncluded.length > 0 ? ( ) : isHeader && item.index === "Not Included in Current Policy" && notIncluded.length > 0 ? (
<Checkbox <Checkbox
checked={selectAll} checked={selectAll}
onChange={(_, data) => handleSelectAll(data.checked === true)} onChange={(_, data) => handleSelectAll(data.checked === true)} />
/>
) : ( ) : (
<div style={{ width: "18px", height: "18px" }}></div> <div className={style.indexAdvisorCheckboxSpacer}></div>
)} )}
{isHeader ? ( {isHeader ? (
<span <span
@@ -807,41 +882,31 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
} else if (item.index === "Not Included in Current Policy") { } else if (item.index === "Not Included in Current Policy") {
setShowNotIncluded(!showNotIncluded); setShowNotIncluded(!showNotIncluded);
} }
}} }}>
>
{item.index === "Included in Current Policy" {item.index === "Included in Current Policy"
? showIncluded ? showIncluded ? <ChevronDown20Regular /> : <ChevronRight20Regular />
? <ChevronDown20Regular /> : showNotIncluded ? <ChevronDown20Regular /> : <ChevronRight20Regular />
: <ChevronRight20Regular />
: showNotIncluded
? <ChevronDown20Regular />
: <ChevronRight20Regular />
} }
</span> </span>
) : ( ) : (
<div style={{ width: "24px" }}></div> <div className={style.indexAdvisorChevronSpacer}></div>
)} )}
<div style={{ fontWeight: isHeader ? "bold" : "normal" }}> <div className={isHeader ? style.indexAdvisorRowBold : style.indexAdvisorRowNormal}>
{item.index} {item.index}
</div> </div>
<div style={{ fontSize: isHeader ? 0 : undefined }}> <div className={isHeader ? style.indexAdvisorRowImpactHeader : style.indexAdvisorRowImpact}>
{isHeader ? null : item.impact} {!isHeader && item.impact}
</div> </div>
<div> <div>
{isHeader ? null : renderImpactDots(item.impact)} {!isHeader && renderImpactDots(item.impact)}
</div> </div>
</div> </div>
</TableCell> </TableCell>
</TableRow> </TableRow>
); );
}; };
const generateIndexMetricItems = ( const indexMetricItems = React.useMemo(() => {
included: { index: string; impact: string }[],
notIncluded: { index: string; impact: string }[]
): IIndexMetric[] => {
const items: IIndexMetric[] = []; const items: IIndexMetric[] = [];
items.push({ index: "Not Included in Current Policy", impact: "", section: "Header" }); items.push({ index: "Not Included in Current Policy", impact: "", section: "Header" });
if (showNotIncluded) { if (showNotIncluded) {
notIncluded.forEach((item) => notIncluded.forEach((item) =>
@@ -855,7 +920,7 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
); );
} }
return items; return items;
}; }, [included, notIncluded, showIncluded, showNotIncluded]);
if (loading) { if (loading) {
return <div> return <div>
@@ -871,19 +936,11 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
return ( return (
<div> <div>
<div style={{ padding: "1rem", fontSize: "1.2rem", display: "flex", alignItems: "center", gap: "0.5rem" }}> <div className={style.indexAdvisorMessage}>
{updateMessageShown ? ( {updateMessageShown ? (
<> <>
<span <span
style={{ className={style.indexAdvisorSuccessIcon}>
width: 18,
height: 18,
borderRadius: "50%",
backgroundColor: "#107C10",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}>
<FontIcon iconName="CheckMark" style={{ color: "white", fontSize: 12 }} /> <FontIcon iconName="CheckMark" style={{ color: "white", fontSize: 12 }} />
</span> </span>
<span> <span>
@@ -894,22 +951,14 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
"Here is an analysis on the indexes utilized for executing the query. Based on the analysis, Cosmos DB recommends adding the selected indexes to your indexing policy to optimize the performance of this particular query." "Here is an analysis on the indexes utilized for executing the query. Based on the analysis, Cosmos DB recommends adding the selected indexes to your indexing policy to optimize the performance of this particular query."
)} )}
</div> </div>
<div style={{ padding: "1rem", fontSize: "1.3rem", fontWeight: "bold" }}>Indexes analysis</div> <div className={style.indexAdvisorTitle}>Indexes analysis</div>
<Table style={{ display: "block", alignItems: "center", marginBottom: "7rem" }}> <Table className={style.indexAdvisorTable}>
<TableHeader> <TableHeader>
<TableRow > <TableRow>
<TableCell colSpan={2}> <TableCell colSpan={2}>
<div <div className={style.indexAdvisorGrid}>
style={{ <div className={style.indexAdvisorCheckboxSpacer}></div>
display: "grid", <div className={style.indexAdvisorChevronSpacer}></div>
gridTemplateColumns: "30px 30px 1fr 50px 120px",
alignItems: "center",
gap: "8px",
fontWeight: "bold",
}}
>
<div style={{ width: "18px", height: "18px" }}></div> {/* Checkbox column */}
<div style={{ width: "24px" }}></div> {/* Chevron column */}
<div>Index</div> <div>Index</div>
<div><span style={{ whiteSpace: "nowrap" }}>Estimated Impact</span></div> <div><span style={{ whiteSpace: "nowrap" }}>Estimated Impact</span></div>
</div> </div>
@@ -917,22 +966,14 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{generateIndexMetricItems(included, notIncluded).map(renderRow)} {indexMetricItems.map(renderRow)}
</TableBody> </TableBody>
</Table> </Table>
{selectedIndexes.length > 0 && ( {selectedIndexes.length > 0 && (
<div style={{ padding: "1rem", marginTop: "-7rem", flexWrap: "wrap" }}> <div className={style.indexAdvisorButtonBar}>
<button <button
onClick={handleUpdatePolicy} onClick={handleUpdatePolicy}
style={{ className={style.indexAdvisorButton}
backgroundColor: "#0078D4",
color: "white",
padding: "8px 16px",
border: "none",
borderRadius: "4px",
cursor: "pointer",
marginTop: "1rem",
}}
> >
Update Indexing Policy with selected index(es) Update Indexing Policy with selected index(es)
</button> </button>
@@ -944,9 +985,6 @@ const IndexAdvisorTab: React.FC<IndexAdvisorTabProps> = ({ onPolicyUpdated }) =>
export const ResultsView: React.FC<ResultsViewProps> = ({ isMongoDB, queryResults, executeQueryDocumentsPage }) => { export const ResultsView: React.FC<ResultsViewProps> = ({ isMongoDB, queryResults, executeQueryDocumentsPage }) => {
const styles = useQueryTabStyles(); const styles = useQueryTabStyles();
const [activeTab, setActiveTab] = useState<ResultsTabs>(ResultsTabs.Results); const [activeTab, setActiveTab] = useState<ResultsTabs>(ResultsTabs.Results);
const [indexingPolicy, setIndexingPolicy] = useState<DataModels.IndexingPolicy | null>(null);
const [baselinePolicy, setBaselinePolicy] = useState<DataModels.IndexingPolicy | null>(null);
const { setIndexingPolicies } = useIndexingPolicyStore.getState();
const onTabSelect = useCallback((event: SelectTabEvent, data: SelectTabData) => { const onTabSelect = useCallback((event: SelectTabEvent, data: SelectTabData) => {
setActiveTab(data.value as ResultsTabs); setActiveTab(data.value as ResultsTabs);
@@ -985,36 +1023,20 @@ export const ResultsView: React.FC<ResultsViewProps> = ({ isMongoDB, queryResult
/> />
)} )}
{activeTab === ResultsTabs.QueryStats && <QueryStatsTab queryResults={queryResults} />} {activeTab === ResultsTabs.QueryStats && <QueryStatsTab queryResults={queryResults} />}
{activeTab === ResultsTabs.IndexAdvisor && <IndexAdvisorTab {activeTab === ResultsTabs.IndexAdvisor && <IndexAdvisorTab />}
onPolicyUpdated={(newPolicy) => {
const freshPolicy = JSON.parse(JSON.stringify(newPolicy));
setIndexingPolicy(freshPolicy);
setBaselinePolicy(freshPolicy);
setIndexingPolicies(freshPolicy, freshPolicy);
}
}
/>}
</div> </div>
</div> </div>
); );
}; };
export interface IndexingPolicyStore { export interface IndexingPolicyStore {
indexingPolicy: DataModels.IndexingPolicy | null; indexingPolicy: IndexingPolicy | null;
baselinePolicy: DataModels.IndexingPolicy | null; setIndexingPolicyOnly: (indexingPolicy: IndexingPolicy) => void;
setIndexingPolicies: (
indexingPolicy: DataModels.IndexingPolicy,
baselinePolicy: DataModels.IndexingPolicy
) => void;
setIndexingPolicyOnly: (indexingPolicy: DataModels.IndexingPolicy) => void;
} }
export const useIndexingPolicyStore = create<IndexingPolicyStore>((set) => ({ export const useIndexingPolicyStore = create<IndexingPolicyStore>((set) => ({
indexingPolicy: null, indexingPolicy: null,
baselinePolicy: null,
setIndexingPolicies: (indexingPolicy, baselinePolicy) =>
set({ indexingPolicy, baselinePolicy }),
setIndexingPolicyOnly: (indexingPolicy) => setIndexingPolicyOnly: (indexingPolicy) =>
set((state) => ({ indexingPolicy: { ...indexingPolicy } })), set(() => ({ indexingPolicy: { ...indexingPolicy } })),
})); }));