Copilot changes to improve initial load time.

This commit is contained in:
Jade Welton
2026-02-27 15:29:25 -08:00
parent 204444b878
commit 1689cbf75a
4 changed files with 143 additions and 57 deletions
+57 -32
View File
@@ -2,26 +2,48 @@ import { Spinner, SpinnerSize, TooltipHost } from "@fluentui/react";
import { CollectionTabKind } from "Contracts/ViewModels";
import Explorer from "Explorer/Explorer";
import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter";
import { QueryCopilotTab } from "Explorer/QueryCopilot/QueryCopilotTab";
import { FabricHomeScreen } from "Explorer/SplashScreen/FabricHome";
import { SplashScreen } from "Explorer/SplashScreen/SplashScreen";
import { ConnectTab } from "Explorer/Tabs/ConnectTab";
import { PostgresConnectTab } from "Explorer/Tabs/PostgresConnectTab";
import { QuickstartTab } from "Explorer/Tabs/QuickstartTab";
import { VcoreMongoConnectTab } from "Explorer/Tabs/VCoreMongoConnectTab";
import { VcoreMongoQuickstartTab } from "Explorer/Tabs/VCoreMongoQuickstartTab";
import { KeyboardAction, KeyboardActionGroup, useKeyboardActionGroup } from "KeyboardShortcuts";
import { isFabricNative } from "Platform/Fabric/FabricUtil";
import { userContext } from "UserContext";
import { useTeachingBubble } from "hooks/useTeachingBubble";
import ko from "knockout";
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
import React, { MutableRefObject, Suspense, useEffect, useRef, useState } from "react";
import errorQuery from "../../../images/error_no_outline.svg";
import warningIconSvg from "../../../images/warning.svg";
import { useObservable } from "../../hooks/useObservable";
import { ReactTabKind, useTabs } from "../../hooks/useTabs";
import TabsBase from "./TabsBase";
// Lazy-loaded tab components (code-split by API type)
const QueryCopilotTab = React.lazy(() =>
import(/* webpackChunkName: "QueryCopilotTab" */ "Explorer/QueryCopilot/QueryCopilotTab").then((m) => ({
default: m.QueryCopilotTab,
})),
);
const FabricHomeScreen = React.lazy(() =>
import(/* webpackChunkName: "FabricHomeScreen" */ "Explorer/SplashScreen/FabricHome").then((m) => ({
default: m.FabricHomeScreen,
})),
);
const PostgresConnectTab = React.lazy(() =>
import(/* webpackChunkName: "PostgresConnectTab" */ "Explorer/Tabs/PostgresConnectTab").then((m) => ({
default: m.PostgresConnectTab,
})),
);
const VcoreMongoConnectTab = React.lazy(() =>
import(/* webpackChunkName: "VcoreMongoConnectTab" */ "Explorer/Tabs/VCoreMongoConnectTab").then((m) => ({
default: m.VcoreMongoConnectTab,
})),
);
const VcoreMongoQuickstartTab = React.lazy(() =>
import(/* webpackChunkName: "VcoreMongoQuickstartTab" */ "Explorer/Tabs/VCoreMongoQuickstartTab").then((m) => ({
default: m.VcoreMongoQuickstartTab,
})),
);
type Tab = TabsBase | (TabsBase & { render: () => JSX.Element });
interface TabsProps {
@@ -302,30 +324,33 @@ const isQueryErrorThrown = (tab?: Tab, tabKind?: ReactTabKind): boolean => {
};
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
switch (activeReactTab) {
case ReactTabKind.Connect:
return userContext.apiType === "VCoreMongo" ? (
<VcoreMongoConnectTab />
) : userContext.apiType === "Postgres" ? (
<PostgresConnectTab />
) : (
<ConnectTab />
);
case ReactTabKind.Home:
if (isFabricNative()) {
return <FabricHomeScreen explorer={explorer} />;
} else {
return <SplashScreen explorer={explorer} />;
}
case ReactTabKind.Quickstart:
return userContext.apiType === "VCoreMongo" ? (
<VcoreMongoQuickstartTab explorer={explorer} />
) : (
<QuickstartTab explorer={explorer} />
);
case ReactTabKind.QueryCopilot:
return <QueryCopilotTab explorer={explorer} />;
default:
throw new Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
}
const content = (() => {
switch (activeReactTab) {
case ReactTabKind.Connect:
return userContext.apiType === "VCoreMongo" ? (
<VcoreMongoConnectTab />
) : userContext.apiType === "Postgres" ? (
<PostgresConnectTab />
) : (
<ConnectTab />
);
case ReactTabKind.Home:
if (isFabricNative()) {
return <FabricHomeScreen explorer={explorer} />;
} else {
return <SplashScreen explorer={explorer} />;
}
case ReactTabKind.Quickstart:
return userContext.apiType === "VCoreMongo" ? (
<VcoreMongoQuickstartTab explorer={explorer} />
) : (
<QuickstartTab explorer={explorer} />
);
case ReactTabKind.QueryCopilot:
return <QueryCopilotTab explorer={explorer} />;
default:
throw new Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
}
})();
return <Suspense fallback={<Spinner size={SpinnerSize.large} />}>{content}</Suspense>;
};
+7 -5
View File
@@ -34,7 +34,7 @@ import Explorer from "../Explorer";
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
import { CassandraAPIDataClient, CassandraTableKey, CassandraTableKeys } from "../Tables/TableDataClient";
import ConflictsTab from "../Tabs/ConflictsTab";
import GraphTab from "../Tabs/GraphTab";
import type GraphTab from "../Tabs/GraphTab";
import { NewMongoQueryTab } from "../Tabs/MongoQueryTab/MongoQueryTab";
import { NewMongoShellTab } from "../Tabs/MongoShellTab/MongoShellTab";
import { NewQueryTab } from "../Tabs/QueryTab/QueryTab";
@@ -450,7 +450,7 @@ export default class Collection implements ViewModels.Collection {
}
}
public onGraphDocumentsClick() {
public async onGraphDocumentsClick() {
useSelectedNode.getState().setSelectedNode(this);
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Graph);
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
@@ -483,7 +483,8 @@ export default class Collection implements ViewModels.Collection {
tabTitle: title,
});
graphTab = new GraphTab({
const { default: GraphTabModule } = await import(/* webpackChunkName: "GraphTab" */ "../Tabs/GraphTab");
graphTab = new GraphTabModule({
account: userContext.databaseAccount,
tabKind: ViewModels.CollectionTabKind.Graph,
node: this,
@@ -727,7 +728,7 @@ export default class Collection implements ViewModels.Collection {
useTabs.getState().activateNewTab(newMongoQueryTab);
}
public onNewGraphClick() {
public async onNewGraphClick() {
const id: number = useTabs.getState().getTabs(ViewModels.CollectionTabKind.Graph).length + 1;
const title: string = "Graph Query " + id;
@@ -739,7 +740,8 @@ export default class Collection implements ViewModels.Collection {
tabTitle: title,
});
const graphTab: GraphTab = new GraphTab({
const { default: GraphTabModule } = await import(/* webpackChunkName: "GraphTab" */ "../Tabs/GraphTab");
const graphTab: GraphTab = new GraphTabModule({
account: userContext.databaseAccount,
tabKind: ViewModels.CollectionTabKind.Graph,
node: this,
+54 -19
View File
@@ -5,27 +5,14 @@ import "./ReactDevTools";
import { initializeIcons, loadTheme, useTheme } from "@fluentui/react";
import { FluentProvider, makeStyles, webDarkTheme, webLightTheme } from "@fluentui/react-components";
import { Platform } from "ConfigContext";
import ContainerCopyPanel from "Explorer/ContainerCopy/ContainerCopyPanel";
import Explorer from "Explorer/Explorer";
import { QuickstartCarousel } from "Explorer/Quickstart/QuickstartCarousel";
import { MongoQuickstartTutorial } from "Explorer/Quickstart/Tutorials/MongoQuickstartTutorial";
import { SQLQuickstartTutorial } from "Explorer/Quickstart/Tutorials/SQLQuickstartTutorial";
import { userContext } from "UserContext";
import "allotment/dist/style.css";
import "bootstrap/dist/css/bootstrap.css";
import { useCarousel } from "hooks/useCarousel";
import React from "react";
import ReactDOM from "react-dom";
import "../externals/jquery-ui.min.css";
import "../externals/jquery-ui.min.js";
import "../externals/jquery-ui.structure.min.css";
import "../externals/jquery-ui.theme.min.css";
import "../externals/jquery.dataTables.min.css";
import "../externals/jquery.typeahead.min.css";
import "../externals/jquery.typeahead.min.js";
// Image Dependencies
import { SidePanel } from "Explorer/Panes/PanelContainerComponent";
import { QueryCopilotCarousel } from "Explorer/QueryCopilot/CopilotCarousel";
import { SidebarContainer } from "Explorer/Sidebar";
import { KeyboardShortcutRoot } from "KeyboardShortcuts";
import "allotment/dist/style.css";
@@ -72,6 +59,50 @@ import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
import { useThemeStore } from "./hooks/useTheme";
import "./less/DarkModeMenus.less";
import "./less/ThemeSystem.less";
// Lazy-loaded components (code-split into separate chunks)
const ContainerCopyPanel = React.lazy(
() => import(/* webpackChunkName: "ContainerCopyPanel" */ "Explorer/ContainerCopy/ContainerCopyPanel"),
);
const QuickstartCarousel = React.lazy(() =>
import(/* webpackChunkName: "QuickstartCarousel" */ "Explorer/Quickstart/QuickstartCarousel").then((m) => ({
default: m.QuickstartCarousel,
})),
);
const SQLQuickstartTutorial = React.lazy(() =>
import(/* webpackChunkName: "SQLQuickstartTutorial" */ "Explorer/Quickstart/Tutorials/SQLQuickstartTutorial").then(
(m) => ({ default: m.SQLQuickstartTutorial }),
),
);
const MongoQuickstartTutorial = React.lazy(() =>
import(
/* webpackChunkName: "MongoQuickstartTutorial" */ "Explorer/Quickstart/Tutorials/MongoQuickstartTutorial"
).then((m) => ({ default: m.MongoQuickstartTutorial })),
);
const QueryCopilotCarousel = React.lazy(() =>
import(/* webpackChunkName: "QueryCopilotCarousel" */ "Explorer/QueryCopilot/CopilotCarousel").then((m) => ({
default: m.QueryCopilotCarousel,
})),
);
// Defer loading legacy jQuery/Bootstrap CSS and JS — they are needed by Tables features, not on initial render
const loadLegacyDependencies = () => {
// @ts-expect-error — side-effect-only imports handled by webpack, not real TS/ES modules
import(/* webpackChunkName: "legacy-styles" */ "bootstrap/dist/css/bootstrap.css");
// @ts-expect-error — webpack handles CSS imports
import(/* webpackChunkName: "legacy-styles" */ "../externals/jquery-ui.min.css");
// @ts-expect-error — webpack handles JS side-effect imports
import(/* webpackChunkName: "legacy-scripts" */ "../externals/jquery-ui.min.js");
// @ts-expect-error — webpack handles CSS imports
import(/* webpackChunkName: "legacy-styles" */ "../externals/jquery-ui.structure.min.css");
// @ts-expect-error — webpack handles CSS imports
import(/* webpackChunkName: "legacy-styles" */ "../externals/jquery-ui.theme.min.css");
// @ts-expect-error — webpack handles CSS imports
import(/* webpackChunkName: "legacy-styles" */ "../externals/jquery.dataTables.min.css");
// @ts-expect-error — webpack handles CSS imports
import(/* webpackChunkName: "legacy-styles" */ "../externals/jquery.typeahead.min.css");
import(/* webpackChunkName: "legacy-scripts" */ "../externals/jquery.typeahead.min.js");
};
// Initialize icons before React is loaded
initializeIcons(undefined, { disableWarnings: true });
@@ -98,6 +129,8 @@ const App = (): JSX.Element => {
import("../less/documentDBFabric.less");
}
StyleConstants.updateStyles();
// Load legacy jQuery/Bootstrap dependencies after initial render
loadLegacyDependencies();
}, [config?.platform]);
const explorer = useKnockoutExplorer(config?.platform);
@@ -131,11 +164,11 @@ const App = (): JSX.Element => {
<KeyboardShortcutRoot>
<div className="flexContainer" aria-hidden="false">
{userContext.features.enableContainerCopy && userContext.apiType === "SQL" ? (
<>
<React.Suspense fallback={null}>
<ContainerCopyPanel explorer={explorer} />
<SidePanel />
<Dialog />
</>
</React.Suspense>
) : (
<DivExplorer explorer={explorer} />
)}
@@ -191,10 +224,12 @@ const DivExplorer: React.FC<{ explorer: Explorer }> = ({ explorer }) => {
</div>
<SidePanel />
<Dialog />
{<QuickstartCarousel isOpen={isCarouselOpen} />}
{<SQLQuickstartTutorial />}
{<MongoQuickstartTutorial />}
{<QueryCopilotCarousel isOpen={isCopilotCarouselOpen} explorer={explorer} />}
<React.Suspense fallback={null}>
{<QuickstartCarousel isOpen={isCarouselOpen} />}
{<SQLQuickstartTutorial />}
{<MongoQuickstartTutorial />}
{<QueryCopilotCarousel isOpen={isCopilotCarouselOpen} explorer={explorer} />}
</React.Suspense>
</div>
);
};
+25 -1
View File
@@ -123,7 +123,7 @@ module.exports = function (_env = {}, argv = {}) {
new HtmlWebpackPlugin({
filename: "explorer.html",
template: "src/explorer.html",
chunks: ["main"],
chunks: ["main", "vendor", "vendor-fluentui", "vendor-nteract"],
}),
new HtmlWebpackPlugin({
filename: "terminal.html",
@@ -262,6 +262,30 @@ module.exports = function (_env = {}, argv = {}) {
},
}),
],
splitChunks: {
chunks: "all",
maxInitialRequests: 10,
cacheGroups: {
fluentui: {
test: /[\\/]node_modules[\\/]@fluentui[\\/]/,
name: "vendor-fluentui",
chunks: "all",
priority: 30,
},
nteract: {
test: /[\\/]node_modules[\\/]@nteract[\\/]/,
name: "vendor-nteract",
chunks: "all",
priority: 30,
},
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "all",
priority: 10,
},
},
},
},
watch: false,
// Hack since it is hard to disable watch entirely with webpack dev server https://github.com/webpack/webpack-dev-server/issues/1251#issuecomment-654240734