Dark theme for Explorer (#2185)

* First dark theme commits for command bar

* Updated theme on sidebar

* Updated tabs, sidebar, splash screen

* settings theme changes

* Dark theme applied to Monaco editor

* Dark theme to stored procedures

* Fixed sidebar scroll

* Updated scroll issue in sidebar

* Command bar items fixed

* Fixed lint errors

* fixed lint errors

* settings side panel fixed

* Second last iteration for css

* Fixed all the issues of css

* Updated the theme icon for now on DE to change the theme from portal/DE itself

* Formatting issue resolved

* Remove CloudShellTerminalComponent changes - revert to master version

* Fixed test issue

* Fixed formatting issue

* Fix tests: update snapshots and revert xterm imports for compatibility

* Fix xterm imports in CloudShellTerminalComponent to use @xterm packages

* Fix Cloud Shell component imports for compatibility

* Update test snapshots

* Fix xterm package consistency across all CloudShell components

* Fix TypeScript compilation errors in CloudShell components and query Documents

- Standardized xterm package imports across CloudShell components to use legacy 'xterm' package
- Fixed Terminal type compatibility issues in CommonUtils.tsx
- Added type casting for enableQueryControl property in queryDocuments.ts to handle Azure Cosmos SDK interface limitations
- Applied code formatting to ensure consistency

* Update failing snapshot tests

- Updated TreeNodeComponent snapshot tests for loading states
- Updated ThroughputInputAutoPilotV3Component snapshots for number formatting changes (10,00,000 -> 1,000,000)
- All snapshot tests now pass

* Fixed test issue

* Fixed test issue

* Updated the buttons for theme

* Updated the Theme changes based on portal theme changes

* Updated review comments

* Updated the duplicate code and fixed the fabric react error

* Few places styling added and resolving few comments

* Fixed errors

* Fixed comments

* Fixed comments

* Fixed comments

* Fixed full text policy issue for mongoru accounts

* Resolved comments for class Name and few others

* Added css for homepage in ru accounts

* Final commit with all the feedback issues resolved

* Lint error resolved

* Updated the review comments and few Ui issues

* Resolved review comments and changed header bg and active state color

* Moved svg code to different file and imported

* css fixed for the hpome page boxed for ru account

* Lint errors

* Fixed boxes issue in ru accounts

* Handled the initial theme from the portal

* Updated snap

* Update snapshots for TreeNodeComponent and CreateCopyJobScreensProvider tests

* Fix duplicate DataExplorerRoot test id causing Playwright strict mode violation

* Fix locale-dependent number formatting in ThroughputInputAutoPilotV3Component

---------

Co-authored-by: Sakshi Gupta <sakshig+microsoft@microsoft.com>
Co-authored-by: Sakshi Gupta <sakshig@microsoft.com>
This commit is contained in:
sakshigupta12feb
2025-12-16 12:21:58 +05:30
committed by GitHub
parent bc7e8a71ca
commit 2c31ec2a8d
100 changed files with 7344 additions and 1929 deletions

View File

@@ -1,3 +1,4 @@
import { Spinner, SpinnerSize, TooltipHost } from "@fluentui/react";
import { CollectionTabKind } from "Contracts/ViewModels";
import Explorer from "Explorer/Explorer";
import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter";
@@ -15,8 +16,6 @@ import { userContext } from "UserContext";
import { useTeachingBubble } from "hooks/useTeachingBubble";
import ko from "knockout";
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
import errorIcon from "../../../images/close-black.svg";
import errorQuery from "../../../images/error_no_outline.svg";
import warningIconSvg from "../../../images/warning.svg";
import { useObservable } from "../../hooks/useObservable";
@@ -41,6 +40,14 @@ export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
});
}, [setKeyboardHandlers]);
// Add useEffect to handle context buttons
useEffect(() => {
if (activeReactTab !== undefined) {
// React tabs have no context buttons
useCommandBar.getState().setContextButtons([]);
}
}, [activeReactTab]);
return (
<div className="tabsManagerContainer">
<div className="nav-tabs-margin">
@@ -92,49 +99,59 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
>
<span className="tabNavContentContainer">
<div className="tab_Content">
<span
className="contentWrapper"
onClick={() => {
if (tab) {
tab.onTabClick();
} else if (tabKind !== undefined) {
useTabs.getState().activateReactTab(tabKind);
}
}}
onKeyPress={({ nativeEvent: e }) => {
if (tab) {
tab.onKeyPressActivate(undefined, e);
} else if (tabKind !== undefined) {
onKeyPressReactTab(e, tabKind);
}
}}
title={useObservable(tab?.tabPath || ko.observable(""))}
aria-selected={active}
aria-expanded={active}
aria-controls={tabId}
tabIndex={0}
role="tab"
ref={focusTab}
>
<span className="statusIconContainer" style={{ width: tabKind === ReactTabKind.Home ? 0 : 18 }}>
{useObservable(tab?.isExecutionError || ko.observable(false)) && <ErrorIcon tab={tab} active={active} />}
{useObservable(tab?.isExecutionWarning || ko.observable(false)) && (
<WarningIcon tab={tab} active={active} />
)}
{isTabExecuting(tab, tabKind) && (
<img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" />
)}
{isQueryErrorThrown(tab, tabKind) && (
<img
src={errorQuery}
title="Error"
alt="Error"
style={{ marginTop: 4, marginLeft: 4, width: 10, height: 11 }}
/>
)}
<TooltipHost content={useObservable(tab?.tabPath || ko.observable(""))}>
<span
className="contentWrapper"
onClick={() => {
if (tab) {
tab.onTabClick();
} else if (tabKind !== undefined) {
useTabs.getState().activateReactTab(tabKind);
}
}}
onKeyPress={({ nativeEvent: e }) => {
if (tab) {
tab.onKeyPressActivate(undefined, e);
} else if (tabKind !== undefined) {
onKeyPressReactTab(e, tabKind);
}
}}
aria-selected={active}
aria-expanded={active}
aria-controls={tabId}
tabIndex={0}
role="tab"
ref={focusTab}
>
<span className="statusIconContainer" style={{ width: tabKind === ReactTabKind.Home ? 0 : 18 }}>
{useObservable(tab?.isExecutionError || ko.observable(false)) && (
<ErrorIcon tab={tab} active={active} />
)}
{useObservable(tab?.isExecutionWarning || ko.observable(false)) && (
<WarningIcon tab={tab} active={active} />
)}
{isTabExecuting(tab, tabKind) && (
<Spinner
size={SpinnerSize.small}
styles={{
circle: {
borderTopColor: "var(--colorNeutralForeground1)",
borderLeftColor: "var(--colorNeutralForeground1)",
borderBottomColor: "var(--colorNeutralForeground1)",
borderRightColor: "var(--colorNeutralBackground1)",
},
}}
/>
)}
{isQueryErrorThrown(tab, tabKind) && (
<TooltipHost content="Error">
<img src={errorQuery} alt="Error" style={{ marginTop: 4, marginLeft: 4, width: 10, height: 11 }} />
</TooltipHost>
)}
</span>
<span className="tabNavText">{tabTitle}</span>
</span>
<span className="tabNavText">{tabTitle}</span>
</span>
</TooltipHost>
<span className="tabIconSection">
<CloseButton tab={tab} active={active} hovering={hovering} tabKind={tabKind} ariaLabel={tabTitle} />
</span>
@@ -164,52 +181,60 @@ const CloseButton = ({
tabKind?: ReactTabKind;
ariaLabel: string;
}) => (
<span
style={{ display: hovering || active ? undefined : "none" }}
title="Close"
role="button"
aria-label={ariaLabel}
className="cancelButton"
onClick={(event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
event.stopPropagation();
tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind);
// tabKind === ReactTabKind.QueryCopilot && useQueryCopilot.getState().resetQueryCopilotStates();
<TooltipHost
content="Close"
styles={{
root: {
display: hovering || active ? undefined : "none",
},
}}
tabIndex={active ? 0 : undefined}
onKeyPress={({ nativeEvent: e }) => (tab ? tab.onKeyPressClose(undefined, e) : onKeyPressReactTabClose(e, tabKind))}
>
<span className="tabIcon close-Icon">
<img src={errorIcon} title="Close" alt="Close" aria-label="hidden" />
<span
role="button"
aria-label={ariaLabel}
className="cancelButton"
onClick={(event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
event.stopPropagation();
tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind);
}}
tabIndex={active ? 0 : undefined}
onKeyPress={({ nativeEvent: e }) =>
tab ? tab.onKeyPressClose(undefined, e) : onKeyPressReactTabClose(e, tabKind)
}
>
<span className="tabIcon close-Icon" />
</span>
</span>
</TooltipHost>
);
const ErrorIcon = ({ tab, active }: { tab: Tab; active: boolean }) => (
<div
id="errorStatusIcon"
role="button"
title="Click to view more details"
tabIndex={active ? 0 : undefined}
className={active ? "actionsEnabled errorIconContainer" : "errorIconContainer"}
onClick={({ nativeEvent: e }) => tab.onErrorDetailsClick(undefined, e)}
onKeyPress={({ nativeEvent: e }) => tab.onErrorDetailsKeyPress(undefined, e)}
>
<span className="errorIcon" />
</div>
<TooltipHost content="Click to view more details">
<div
id="errorStatusIcon"
role="button"
tabIndex={active ? 0 : undefined}
className={active ? "actionsEnabled errorIconContainer" : "errorIconContainer"}
onClick={({ nativeEvent: e }) => tab.onErrorDetailsClick(undefined, e)}
onKeyPress={({ nativeEvent: e }) => tab.onErrorDetailsKeyPress(undefined, e)}
>
<span className="errorIcon" />
</div>
</TooltipHost>
);
const WarningIcon = ({ tab, active }: { tab: Tab; active: boolean }) => (
<div
id="warningStatusIcon"
role="button"
title="Click to view more details"
tabIndex={active ? 0 : undefined}
className={active ? "actionsEnabled warningIconContainer" : "warningIconContainer"}
onClick={({ nativeEvent: e }) => tab.onErrorDetailsClick(undefined, e)}
onKeyPress={({ nativeEvent: e }) => tab.onErrorDetailsKeyPress(undefined, e)}
>
<img src={warningIconSvg} alt="Warning Icon" style={{ height: 15, marginBottom: 5 }} />
</div>
<TooltipHost content="Click to view more details">
<div
id="warningStatusIcon"
role="button"
tabIndex={active ? 0 : undefined}
className={active ? "actionsEnabled warningIconContainer" : "warningIconContainer"}
onClick={({ nativeEvent: e }) => tab.onErrorDetailsClick(undefined, e)}
onKeyPress={({ nativeEvent: e }) => tab.onErrorDetailsKeyPress(undefined, e)}
>
<img src={warningIconSvg} alt="Warning Icon" style={{ height: 15, marginBottom: 5 }} />
</div>
</TooltipHost>
);
function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
@@ -277,10 +302,6 @@ const isQueryErrorThrown = (tab?: Tab, tabKind?: ReactTabKind): boolean => {
};
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
// React tabs have no context buttons.
useCommandBar.getState().setContextButtons([]);
// eslint-disable-next-line no-console
switch (activeReactTab) {
case ReactTabKind.Connect:
return userContext.apiType === "VCoreMongo" ? (
@@ -305,6 +326,6 @@ const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): J
case ReactTabKind.QueryCopilot:
return <QueryCopilotTab explorer={explorer} />;
default:
throw Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
throw new Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
}
};