updated the theme icon for now on DE to change the theme from portal/DE it self

This commit is contained in:
Sakshi Gupta 2025-09-30 16:06:12 +05:30
parent c42fe99c1a
commit 0bf9382eeb
28 changed files with 444 additions and 439 deletions

3
images/moon-blue.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 7.5C4 5.567 5.567 4 7.5 4C8.5 4 9.4 4.4 10 5.1C9.5 4.8 8.9 4.6 8.3 4.6C6.8 4.6 5.6 5.8 5.6 7.3C5.6 8.8 6.8 10 8.3 10C8.9 10 9.5 9.8 10 9.5C9.4 10.2 8.5 10.6 7.5 10.6C5.567 10.6 4 9.033 4 7.1V7.5Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 328 B

11
images/sun-blue.svg Normal file
View File

@ -0,0 +1,11 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 2C6 1.44772 6.44772 1 7 1C7.55228 1 8 1.44772 8 2C8 2.55228 7.55228 3 7 3C6.44772 3 6 2.55228 6 2Z" fill="#0078D4"/>
<path d="M6 13C6 12.4477 6.44772 12 7 12C7.55228 12 8 12.4477 8 13C8 13.5523 7.55228 14 7 14C6.44772 14 6 13.5523 6 13Z" fill="#0078D4"/>
<path d="M1 7C1 6.44772 1.44772 6 2 6C2.55228 6 3 6.44772 3 7C3 7.55228 2.55228 8 2 8C1.44772 8 1 7.55228 1 7Z" fill="#0078D4"/>
<path d="M12 7C12 6.44772 12.4477 6 13 6C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8C12.4477 8 12 7.55228 12 7Z" fill="#0078D4"/>
<path d="M2.63604 3.63604C3.02656 3.24551 3.65973 3.24551 4.05025 3.63604C4.44078 4.02656 4.44078 4.65973 4.05025 5.05025C3.65973 5.44078 3.02656 5.44078 2.63604 5.05025C2.24551 4.65973 2.24551 4.02656 2.63604 3.63604Z" fill="#0078D4"/>
<path d="M10.9497 9.94975C11.3403 9.55922 11.9734 9.55922 12.364 9.94975C12.7545 10.3403 12.7545 10.9734 12.364 11.364C11.9734 11.7545 11.3403 11.7545 10.9497 11.364C10.5592 10.9734 10.5592 10.3403 10.9497 9.94975Z" fill="#0078D4"/>
<path d="M10.9497 5.05025C10.5592 4.65973 10.5592 4.02656 10.9497 3.63604C11.3403 3.24551 11.9734 3.24551 12.364 3.63604C12.7545 4.02656 12.7545 4.65973 12.364 5.05025C11.9734 5.44078 11.3403 5.44078 10.9497 5.05025Z" fill="#0078D4"/>
<path d="M2.63604 11.364C2.24551 10.9734 2.24551 10.3403 2.63604 9.94975C3.02656 9.55922 3.65973 9.55922 4.05025 9.94975C4.44078 10.3403 4.44078 10.9734 4.05025 11.364C3.65973 11.7545 3.02656 11.7545 2.63604 11.364Z" fill="#0078D4"/>
<circle cx="7.5" cy="7.5" r="2.5" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -85,7 +85,7 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
},
rootPressed: {
backgroundColor: "transparent",
}
},
}}
onClick={(event) => {
event.stopPropagation();

View File

@ -179,18 +179,18 @@ export const Dialog: FC = () => {
title,
subText,
styles: {
title: {
fontSize: DIALOG_TITLE_FONT_SIZE,
title: {
fontSize: DIALOG_TITLE_FONT_SIZE,
fontWeight: DIALOG_TITLE_FONT_WEIGHT,
},
subText: {
subText: {
fontSize: DIALOG_SUBTEXT_FONT_SIZE,
color: 'var(--colorNeutralForeground2)'
color: "var(--colorNeutralForeground2)",
},
content: {
backgroundColor: 'var(--colorNeutralBackground1)',
color: 'var(--colorNeutralForeground1)'
}
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)",
},
},
showCloseButton: showCloseButton || false,
onDismiss,
@ -200,12 +200,12 @@ export const Dialog: FC = () => {
maxWidth: DIALOG_MAX_WIDTH,
styles: {
main: {
backgroundColor: 'var(--colorNeutralBackground1)',
backgroundColor: "var(--colorNeutralBackground1)",
selectors: {
'.ms-Dialog-title': { color: 'var(--colorNeutralForeground1)' },
}
}
}
".ms-Dialog-title": { color: "var(--colorNeutralForeground1)" },
},
},
},
};
const primaryButtonProps: IButtonProps = {

View File

@ -1,5 +1,5 @@
import { Spinner, SpinnerSize } from "@fluentui/react";
import { monacoTheme } from "hooks/useTheme";
import { useThemeStore } from "hooks/useTheme";
import * as React from "react";
import { loadMonaco, monaco } from "../../LazyMonaco";
// import "./EditorReact.less";
@ -67,6 +67,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
private rootNode: HTMLElement;
public editor: monaco.editor.IStandaloneCodeEditor;
private selectionListener: monaco.IDisposable;
private themeUnsubscribe: () => void;
monacoApi: {
default: typeof monaco;
Emitter: typeof monaco.Emitter;
@ -95,6 +96,13 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
public componentDidMount(): void {
this.createEditor(this.configureEditor.bind(this));
this.themeUnsubscribe = useThemeStore.subscribe((state) => {
if (this.editor) {
const newTheme = state.isDarkMode ? "vs-dark" : "vs";
this.monacoApi?.editor.setTheme(newTheme);
}
});
setTimeout(() => {
const suggestionWidget = this.editor?.getDomNode()?.querySelector(".suggest-widget") as HTMLElement;
if (suggestionWidget) {
@ -129,6 +137,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
public componentWillUnmount(): void {
this.selectionListener && this.selectionListener.dispose();
this.themeUnsubscribe && this.themeUnsubscribe();
}
public render(): JSX.Element {
@ -212,7 +221,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
ariaLabel: this.props.ariaLabel,
fontSize: this.props.fontSize || 12,
automaticLayout: true,
theme: monacoTheme,
theme: useThemeStore.getState().isDarkMode ? "vs-dark" : "vs",
wordWrap: this.props.wordWrap || "off",
lineNumbers: this.props.lineNumbers || "off",
lineNumbersMinChars: this.props.lineNumbersMinChars,

View File

@ -33,7 +33,7 @@ export interface FullTextPolicyData {
const labelStyles = {
root: {
fontSize: 12,
color: "var(--colorNeutralForeground1)"
color: "var(--colorNeutralForeground1)",
},
};
@ -223,31 +223,32 @@ export const FullTextPoliciesComponent: React.FunctionComponent<FullTextPolicies
</Stack>
</CollapsibleSectionComponent>
))}
<DefaultButton
id={`add-vector-policy`}
styles={{
root: {
maxWidth: 170,
<DefaultButton
id={`add-vector-policy`}
styles={{
root: {
maxWidth: 170,
fontSize: 12,
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
borderColor: "var(--colorNeutralStroke1)"
borderColor: "var(--colorNeutralStroke1)",
},
rootHovered: {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
borderColor: "var(--colorNeutralForeground1)"
borderColor: "var(--colorNeutralForeground1)",
},
rootPressed: {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
borderColor: "var(--colorNeutralForeground1)"
borderColor: "var(--colorNeutralForeground1)",
},
rootDisabled: {
backgroundColor: "transparent"
}
}}
onClick={onAdd}>
backgroundColor: "transparent",
},
}}
onClick={onAdd}
>
Add full text path
</DefaultButton>
</Stack>

View File

@ -3,7 +3,7 @@ import * as DataModels from "Contracts/DataModels";
import { titleAndInputStackProps, unsavedEditorWarningMessage } from "Explorer/Controls/Settings/SettingsRenderUtils";
import { isDirty } from "Explorer/Controls/Settings/SettingsUtils";
import { loadMonaco } from "Explorer/LazyMonaco";
import { monacoTheme } from "hooks/useTheme";
import { useThemeStore } from "hooks/useTheme";
import * as monaco from "monaco-editor";
import * as React from "react";
export interface ComputedPropertiesComponentProps {
@ -27,6 +27,7 @@ export class ComputedPropertiesComponent extends React.Component<
private shouldCheckComponentIsDirty = true;
private computedPropertiesDiv = React.createRef<HTMLDivElement>();
private computedPropertiesEditor: monaco.editor.IStandaloneCodeEditor;
private themeUnsubscribe: () => void;
constructor(props: ComputedPropertiesComponentProps) {
super(props);
@ -48,6 +49,10 @@ export class ComputedPropertiesComponent extends React.Component<
this.onComponentUpdate();
}
componentWillUnmount(): void {
this.themeUnsubscribe && this.themeUnsubscribe();
}
public resetComputedPropertiesEditor = (): void => {
if (!this.computedPropertiesEditor) {
this.createComputedPropertiesEditor();
@ -86,9 +91,17 @@ export class ComputedPropertiesComponent extends React.Component<
value: value,
language: "json",
ariaLabel: "Computed properties",
theme: monacoTheme,
theme: useThemeStore.getState().isDarkMode ? "vs-dark" : "vs",
});
if (this.computedPropertiesEditor) {
// Subscribe to theme changes
this.themeUnsubscribe = useThemeStore.subscribe((state) => {
if (this.computedPropertiesEditor) {
const newTheme = state.isDarkMode ? "vs-dark" : "vs";
monaco.editor.setTheme(newTheme);
}
});
const computedPropertiesEditorModel = this.computedPropertiesEditor.getModel();
computedPropertiesEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
this.props.logComputedPropertiesSuccessMessage();

View File

@ -102,51 +102,51 @@ export const ContainerPolicyComponent: React.FC<ContainerPolicyComponentProps> =
return (
<div>
<Pivot
onLinkClick={onPivotChange}
<Pivot
onLinkClick={onPivotChange}
selectedKey={ContainerPolicyTabTypes[selectedTab]}
styles={{
root: {
color: "var(--colorNeutralForeground1)"
root: {
color: "var(--colorNeutralForeground1)",
},
link: {
link: {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
selectors: {
':hover': {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent"
":hover": {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
},
':active': {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent"
}
}
":active": {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
},
},
},
linkIsSelected: {
linkIsSelected: {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
selectors: {
':before': {
color: "var(--colorNeutralForeground1)",
backgroundColor: "var(--colorBrandForeground1)"
},
':hover': {
":before": {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent"
backgroundColor: "var(--colorBrandForeground1)",
},
':active': {
":hover": {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent"
}
}
backgroundColor: "transparent",
},
":active": {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
},
},
},
linkContent: {
color: "inherit"
color: "inherit",
},
text: {
color: "inherit"
}
color: "inherit",
},
}}
>
{isVectorSearchEnabled && (
@ -190,26 +190,26 @@ export const ContainerPolicyComponent: React.FC<ContainerPolicyComponentProps> =
) : (
<DefaultButton
id={"create-full-text-policy"}
styles={{
root: {
styles={{
root: {
fontSize: 12,
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
borderColor: "var(--colorNeutralForeground1)"
borderColor: "var(--colorNeutralForeground1)",
},
rootHovered: {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
borderColor: "var(--colorNeutralForeground1)"
borderColor: "var(--colorNeutralForeground1)",
},
rootPressed: {
color: "var(--colorNeutralForeground1)",
backgroundColor: "transparent",
borderColor: "var(--colorNeutralForeground1)"
borderColor: "var(--colorNeutralForeground1)",
},
rootDisabled: {
backgroundColor: "transparent"
}
backgroundColor: "transparent",
},
}}
onClick={() => {
checkAndSendFullTextPolicyToSettings({

View File

@ -1,5 +1,5 @@
import { MessageBar, MessageBarType, Stack } from "@fluentui/react";
import { monacoTheme } from "hooks/useTheme";
import { useThemeStore } from "hooks/useTheme";
import * as monaco from "monaco-editor";
import * as React from "react";
import * as DataModels from "../../../../Contracts/DataModels";
@ -31,6 +31,7 @@ export class IndexingPolicyComponent extends React.Component<
private shouldCheckComponentIsDirty = true;
private indexingPolicyDiv = React.createRef<HTMLDivElement>();
private indexingPolicyEditor: monaco.editor.IStandaloneCodeEditor;
private themeUnsubscribe: () => void;
constructor(props: IndexingPolicyComponentProps) {
super(props);
@ -52,6 +53,10 @@ export class IndexingPolicyComponent extends React.Component<
this.onComponentUpdate();
}
componentWillUnmount(): void {
this.themeUnsubscribe && this.themeUnsubscribe();
}
public resetIndexingPolicyEditor = (): void => {
if (!this.indexingPolicyEditor) {
this.createIndexingPolicyEditor();
@ -98,59 +103,22 @@ export class IndexingPolicyComponent extends React.Component<
language: "json",
readOnly: isIndexTransforming(this.props.indexTransformationProgress),
ariaLabel: "Indexing Policy",
theme: monacoTheme,
theme: useThemeStore.getState().isDarkMode ? "vs-dark" : "vs",
});
if (this.indexingPolicyEditor) {
this.themeUnsubscribe = useThemeStore.subscribe((state) => {
if (this.indexingPolicyEditor) {
const newTheme = state.isDarkMode ? "vs-dark" : "vs";
monaco.editor.setTheme(newTheme);
}
});
const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
indexingPolicyEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
this.props.logIndexingPolicySuccessMessage();
}
}
}
// private async createIndexingPolicyEditor(): Promise<void> {
// const isDarkMode = true;
// const monacoThemeName = "fluent-theme";
// if (!this.indexingPolicyDiv.current) return;
// const value: string = JSON.stringify(this.props.indexingPolicyContent, undefined, 4);
// const monaco = await loadMonaco();
// // Safely get Fluent UI theme colors
// const bodyStyles = getComputedStyle(document.body);
// const backgroundColor = bodyStyles.getPropertyValue("--colorNeutralBackground1").trim() || "#1b1a19";
// const foregroundColor = bodyStyles.getPropertyValue("--colorNeutralForeground1").trim() || "#ffffff";
// // Define Monaco theme using Fluent UI colors
// monaco.editor.defineTheme(monacoThemeName, {
// base: isDarkMode ? "vs-dark" : "vs",
// inherit: true,
// rules: [],
// colors: {
// "editor.background": backgroundColor,
// "editor.foreground": foregroundColor,
// "editorCursor.foreground": "#ffcc00",
// "editorLineNumber.foreground": "#aaaaaa",
// "editor.selectionBackground": "#666666",
// "editor.lineHighlightBackground": "#333333"
// }
// });
// // Create the editor with the custom theme
// this.indexingPolicyEditor = monaco.editor.create(this.indexingPolicyDiv.current, {
// value,
// language: "json",
// readOnly: isIndexTransforming(this.props.indexTransformationProgress),
// ariaLabel: "Indexing Policy",
// theme: monacoThemeName
// });
// if (this.indexingPolicyEditor) {
// const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
// indexingPolicyEditorModel?.onDidChangeContent(this.onEditorContentChange.bind(this));
// this.props.logIndexingPolicySuccessMessage();
// }
// }
private onEditorContentChange = (): void => {

View File

@ -77,13 +77,14 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
onChange={(newValue) => handleBucketChange(bucket.id, newValue)}
showValue={false}
label={`Bucket ${bucket.id}${bucket.id === 1 ? " (Data Explorer Query Bucket)" : ""}`}
styles={{
styles={{
root: { flex: 2, maxWidth: 400 },
titleLabel: {
color: bucket.maxThroughputPercentage === 100 ?
"var(--colorNeutralForeground4)" :
"var(--colorNeutralForeground1)"
}
titleLabel: {
color:
bucket.maxThroughputPercentage === 100
? "var(--colorNeutralForeground4)"
: "var(--colorNeutralForeground1)",
},
}}
disabled={bucket.maxThroughputPercentage === 100}
/>

View File

@ -41,7 +41,7 @@ import {
noLeftPaddingCheckBoxStyle,
relaxedSpacingStackProps,
saveThroughputWarningMessage,
titleAndInputStackProps
titleAndInputStackProps,
} from "../../SettingsRenderUtils";
import { IsComponentDirtyResult, getSanitizedInputValue, isDirty } from "../../SettingsUtils";
import { ToolTipLabelComponent } from "../ToolTipLabelComponent";
@ -548,7 +548,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
};
private darkThemeMessageBarStyles: Partial<IMessageBarStyles> = {
root: {
root: {
marginTop: "5px",
selectors: {
"&.ms-MessageBar--severeWarning": {
@ -574,7 +574,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
this.currentThroughputValue() > this.props.softAllowedMaximumThroughput ||
this.currentThroughputValue() < this.props.minimum;
return (
<MessageBar
<MessageBar
messageBarType={isSevereWarning ? MessageBarType.severeWarning : MessageBarType.warning}
styles={this.darkThemeMessageBarStyles}
>
@ -590,7 +590,10 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
{/* Column 1: Minimum RU/s */}
<Stack tokens={{ childrenGap: 4 }}>
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
<Text
variant="small"
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
>
Minimum RU/s
</Text>
<FontIcon iconName="Info" style={{ fontSize: 12, color: "var(--colorNeutralForeground2)" }} />
@ -631,7 +634,10 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
{/* Column 3: Maximum RU/s */}
<Stack tokens={{ childrenGap: 4 }}>
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
<Text
variant="small"
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
>
Maximum RU/s
</Text>
<FontIcon iconName="Info" style={{ fontSize: 12, color: "var(--colorNeutralForeground2)" }} />
@ -643,25 +649,25 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
key="auto pilot throughput input"
styles={{
...getTextFieldStyles(this.props.maxAutoPilotThroughput, this.props.maxAutoPilotThroughputBaseline),
fieldGroup: {
width: 100,
fieldGroup: {
width: 100,
height: 28,
backgroundColor: "var(--colorNeutralBackground4)",
backgroundColor: "var(--colorNeutralBackground4)",
},
field: {
fontSize: 14,
field: {
fontSize: 14,
fontWeight: 400,
color: "var(--colorNeutralForeground1)",
color: "var(--colorNeutralForeground1)",
backgroundColor: "var(--colorNeutralBackground4)",
},
root: {
selectors: {
"input": {
input: {
backgroundColor: "var(--colorNeutralBackground4)",
color: "var(--colorNeutralForeground1)",
},
},
}
},
}}
disabled={this.overrideWithProvisionedThroughputSettings()}
step={AutoPilotUtils.autoPilotIncrementStep}

View File

@ -54,7 +54,7 @@ export const CostEstimateText: FunctionComponent<CostEstimateTextProps> = ({
if (isAutoscale) {
return (
<Stack style={{ marginBottom: 6 , color: "var(--colorNeutralForeground1)" }}>
<Stack style={{ marginBottom: 6, color: "var(--colorNeutralForeground1)" }}>
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
{estimatedMonthlyCost} ({currency}){iconWithEstimatedCostDisclaimer}:{" "}
<b>

View File

@ -193,7 +193,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
<div className="throughputInputContainer throughputInputSpacing">
<Stack horizontal>
<span className="mandatoryStar">*&nbsp;</span>
<Text aria-label="Throughput header" variant="small" style={{ lineHeight: "20px", fontWeight: 600 , color: "var(--colorNeutralForeground1)"}}>
<Text
aria-label="Throughput header"
variant="small"
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
>
{getThroughputLabelText()}
</Text>
<InfoTooltip>{PricingUtils.getRuToolTipText()}</InfoTooltip>
@ -236,14 +240,17 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
{isAutoscaleSelected && (
<Stack className="throughputInputSpacing">
<Text style={{ marginTop: -2, fontSize: 12 ,color: "var(--colorNeutralForeground1)" }}>
<Text style={{ marginTop: -2, fontSize: 12, color: "var(--colorNeutralForeground1)" }}>
Your container throughput will automatically scale up to the maximum value you select, from a minimum of 10%
of that value.
</Text>
<Stack horizontal verticalAlign="end" tokens={{ childrenGap: 8 }}>
<Stack tokens={{ childrenGap: 4 }}>
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
<Text
variant="small"
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
>
Minimum RU/s
</Text>
<InfoTooltip>The minimum RU/s your container will scale to</InfoTooltip>
@ -273,7 +280,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
fontSize: 12,
fontWeight: 400,
paddingBottom: 6,
color: "var(--colorNeutralForeground1)"
color: "var(--colorNeutralForeground1)",
}}
>
x 10 =
@ -281,7 +288,10 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
<Stack tokens={{ childrenGap: 4 }}>
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600,color: "var(--colorNeutralForeground1)" }}>
<Text
variant="small"
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
>
Maximum RU/s
</Text>
<InfoTooltip>{getAutoScaleTooltip()}</InfoTooltip>
@ -291,7 +301,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
type="number"
styles={{
fieldGroup: { width: 100, height: 27, flexShrink: 0 },
field: { fontSize: 14, fontWeight: 400 , color: "var(--colorNeutralForeground1)"},
field: { fontSize: 14, fontWeight: 400, color: "var(--colorNeutralForeground1)" },
}}
onChange={(_event, newInput?: string) => onThroughputValueChange(newInput)}
step={AutoPilotUtils.autoPilotIncrementStep}
@ -307,7 +317,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
<CostEstimateText requestUnits={throughput} isAutoscale={isAutoscaleSelected} />
<Stack className="throughputInputSpacing">
<Text variant="small" aria-label="ruDescription" style={{color: "var(--colorNeutralForeground1)" }}>
<Text variant="small" aria-label="ruDescription" style={{ color: "var(--colorNeutralForeground1)" }}>
Estimate your required RU/s with&nbsp;
<Link
className="underlinedLink"
@ -326,7 +336,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
{!isAutoscaleSelected && (
<Stack className="throughputInputSpacing">
<Text variant="small" aria-label="ruDescription" style={{color: "var(--colorNeutralForeground1)" }}>
<Text variant="small" aria-label="ruDescription" style={{ color: "var(--colorNeutralForeground1)" }}>
Estimate your required RU/s with&nbsp;
<Link
className="underlinedLink"
@ -339,7 +349,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
.
</Text>
<Stack horizontal>
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }} aria-label="maxRUDescription">
<Text
variant="small"
style={{ lineHeight: "20px", fontWeight: 600, color: "var(--colorNeutralForeground1)" }}
aria-label="maxRUDescription"
>
{isDatabase ? "Database" : getCollectionName()} Required RU/s
</Text>
<InfoTooltip>{getAutoScaleTooltip()}</InfoTooltip>

View File

@ -1,8 +1,4 @@
import {
Button as FluentButton,
makeStyles,
tokens,
} from "@fluentui/react-components";
import { Button as FluentButton, makeStyles, tokens } from "@fluentui/react-components";
import * as React from "react";
export type CustomButtonProps = {
@ -39,21 +35,13 @@ const useStyles = makeStyles({
},
});
export const Button = React.forwardRef<HTMLButtonElement, CustomButtonProps>(
({ primary, ...props }, ref) => {
const baseStyles = useStyles();
const buttonClassName = primary ? baseStyles.primary : baseStyles.button;
export const Button = React.forwardRef<HTMLButtonElement, CustomButtonProps>(({ primary, ...props }, ref) => {
const baseStyles = useStyles();
const buttonClassName = primary ? baseStyles.primary : baseStyles.button;
return (
<FluentButton
{...props}
ref={ref}
appearance={primary ? "primary" : "secondary"}
className={buttonClassName}
/>
);
}
);
return (
<FluentButton {...props} ref={ref} appearance={primary ? "primary" : "secondary"} className={buttonClassName} />
);
});
// Add display name
Button.displayName = "Button";

View File

@ -15,7 +15,7 @@ const useStyles = makeStyles({
},
});
export const DataExplorer: React.FC<DataExplorerProps> = ({ dataExplorer }) => {
export const DataExplorer: React.FC<DataExplorerProps> = () => {
const styles = useStyles();
return (

View File

@ -73,11 +73,11 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
const { targetDocument } = useFluent();
const setKeyboardHandlers = useKeyboardActionGroup(KeyboardActionGroup.COMMAND_BAR);
const styles = useStyles();
const { connectionInfo, isPhoenixNotebooks, isPhoenixFeatures } = useNotebook((state) => ({
connectionInfo: state.connectionInfo,
isPhoenixNotebooks: state.isPhoenixNotebooks,
isPhoenixFeatures: state.isPhoenixFeatures
isPhoenixFeatures: state.isPhoenixFeatures,
}));
if (userContext.apiType === "Postgres" || userContext.apiType === "VCoreMongo") {
@ -126,10 +126,7 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
// Add connection status if needed (using the hook values we got at the top level)
if (
(isPhoenixNotebooks || isPhoenixFeatures) &&
connectionInfo?.status !== ConnectionStatusType.Connect
) {
if ((isPhoenixNotebooks || isPhoenixFeatures) && connectionInfo?.status !== ConnectionStatusType.Connect) {
uiFabricControlButtons.unshift(
CommandBarUtil.createConnectionStatus(container, PoolIdType.DefaultPoolId, "connectionStatus"),
);
@ -152,8 +149,8 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
":active": {
backgroundColor: "var(--colorNeutralBackground3)",
color: "var(--colorNeutralForeground1)",
}
}
},
},
},
menuIcon: {
color: "var(--colorNeutralForeground1)",
@ -165,7 +162,7 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
link: {
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)",
}
},
};
const allButtons = staticButtons.concat(contextButtons).concat(controlButtons);

View File

@ -1,3 +1,4 @@
import { OpenFullScreen } from "Explorer/OpenFullScreen";
import { KeyboardAction } from "KeyboardShortcuts";
import { isDataplaneRbacSupported } from "Utils/APITypeUtils";
import * as React from "react";
@ -25,12 +26,12 @@ import { useSidePanel } from "../../../hooks/useSidePanel";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer";
import { useNotebook } from "../../Notebook/useNotebook";
import { OpenFullScreen } from "../../OpenFullScreen";
import { BrowseQueriesPane } from "../../Panes/BrowseQueriesPane/BrowseQueriesPane";
import { LoadQueryPane } from "../../Panes/LoadQueryPane/LoadQueryPane";
import { SettingsPane, useDataPlaneRbac } from "../../Panes/SettingsPane/SettingsPane";
import { useDatabases } from "../../useDatabases";
import { SelectedNodeState, useSelectedNode } from "../../useSelectedNode";
import { ThemeToggleButton } from "./ThemeToggleButton";
let counter = 0;
@ -175,6 +176,7 @@ export function createContextCommandBarButtons(
export function createControlCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
const buttons: CommandButtonComponentProps[] = [
ThemeToggleButton(),
{
iconSrc: SettingsIcon,
iconAlt: "Settings",

View File

@ -0,0 +1,29 @@
import * as React from "react";
import MoonBlueIcon from "../../../../images/moon-blue.svg";
import SunBlueIcon from "../../../../images/sun-blue.svg";
import { useThemeStore } from "../../../hooks/useTheme";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
export const ThemeToggleButton = (): CommandButtonComponentProps => {
const [darkMode, setDarkMode] = React.useState(useThemeStore.getState().isDarkMode);
React.useEffect(() => {
const unsubscribe = useThemeStore.subscribe((state) => {
setDarkMode(state.isDarkMode);
});
return unsubscribe;
}, []);
const tooltipText = darkMode ? "Switch to Light Theme" : "Switch to Dark Theme";
return {
iconSrc: darkMode ? SunBlueIcon : MoonBlueIcon,
iconAlt: "Theme Toggle",
onCommandClick: useThemeStore.getState().toggleTheme,
commandButtonLabel: undefined,
ariaLabel: tooltipText,
tooltipText: tooltipText,
hasPopup: false,
disabled: false,
};
};

View File

@ -6,7 +6,7 @@ export const OpenFullScreen: React.FunctionComponent = () => {
<>
<div style={{ padding: "34px" }}>
<Stack tokens={{ childrenGap: 10 }}>
<Text>
<Text style={{ color: "var(--colorNeutralForeground1)" }}>
Open this database account in a new browser tab with Cosmos DB Explorer. You can connect using your
Microsoft account or a connection string.
</Text>

View File

@ -653,26 +653,26 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
{userContext.apiType === "SQL" && (
<Stack className="panelGroupSpacing">
<DefaultButton
styles={{
root: {
padding: 0,
width: 200,
styles={{
root: {
padding: 0,
width: 200,
height: 30,
backgroundColor: 'var(--colorNeutralBackground2)',
color: 'var(--colorNeutralForeground1)',
borderColor: 'var(--colorNeutralStroke1)'
backgroundColor: "var(--colorNeutralBackground2)",
color: "var(--colorNeutralForeground1)",
borderColor: "var(--colorNeutralStroke1)",
},
rootHovered: {
backgroundColor: 'var(--colorNeutralBackground3)',
color: 'var(--colorNeutralForeground1)',
backgroundColor: "var(--colorNeutralBackground3)",
color: "var(--colorNeutralForeground1)",
},
rootPressed: {
backgroundColor: 'var(--colorBrandBackgroundPressed)',
color: 'var(--colorNeutralForegroundOnBrand)',
backgroundColor: "var(--colorBrandBackgroundPressed)",
color: "var(--colorNeutralForegroundOnBrand)",
},
label: {
fontSize: 12,
},
label: {
fontSize: 12
}
}}
hidden={this.state.useHashV1}
disabled={this.state.subPartitionKeys.length >= Constants.BackendDefaults.maxNumMultiHashPartition}
@ -707,9 +707,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
label: { padding: 0, alignItems: "center" },
root: {
selectors: {
':hover .ms-Checkbox-text': { color: "var(--colorNeutralForeground1)" }
}
}
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
},
},
}}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
this.setState({ enableDedicatedThroughput: isChecked })
@ -798,7 +798,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
<ActionButton
iconProps={{ iconName: "Add" }}
styles={{ root: { padding: 0 }, label: { fontSize: 12 , color: "var(--colorNeutralForeground1)"}}}
styles={{ root: { padding: 0 }, label: { fontSize: 12, color: "var(--colorNeutralForeground1)" } }}
onClick={() => this.setState({ uniqueKeys: [...this.state.uniqueKeys, ""] })}
>
Add unique key
@ -969,9 +969,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
label: { padding: 0, alignItems: "center" },
root: {
selectors: {
':hover .ms-Checkbox-text': { color: "var(--colorNeutralForeground1)" }
}
}
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
},
},
}}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
this.setState({ createMongoWildCardIndex: isChecked })
@ -991,9 +991,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
label: { padding: 0, alignItems: "center", wordWrap: "break-word", whiteSpace: "break-spaces" },
root: {
selectors: {
':hover .ms-Checkbox-text': { color: "var(--colorNeutralForeground1)" }
}
}
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
},
},
}}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
this.setState({ useHashV1: isChecked, subPartitionKeys: [] })

View File

@ -66,44 +66,43 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
onRenderNavigationContent={this.props.onRenderNavigationContent}
isFooterAtBottom={true}
styles={{
navigation: {
navigation: {
borderBottom: "1px solid var(--colorNeutralStroke1)",
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)"
color: "var(--colorNeutralForeground1)",
},
content: {
content: {
padding: 0,
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)"
color: "var(--colorNeutralForeground1)",
},
header: {
header: {
padding: "0 0 8px 34px",
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)"
color: "var(--colorNeutralForeground1)",
},
commands: {
marginTop: 8,
commands: {
marginTop: 8,
paddingTop: 0,
backgroundColor: "var(--colorNeutralBackground1)"
},
root: {
backgroundColor: "var(--colorNeutralBackground1)",
},
root: {},
overlay: {
backgroundColor: "var(--overlayBackground)"
backgroundColor: "var(--overlayBackground)",
},
main: {
backgroundColor: "var(--colorNeutralBackground1)"
backgroundColor: "var(--colorNeutralBackground1)",
},
scrollableContent: {
backgroundColor: "var(--colorNeutralBackground1)"
backgroundColor: "var(--colorNeutralBackground1)",
},
footerInner: {
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)"
color: "var(--colorNeutralForeground1)",
},
closeButton: {
color: "var(--colorNeutralForeground1)"
}
color: "var(--colorNeutralForeground1)",
},
}}
style={{ height: this.state.height }}
>

View File

@ -54,31 +54,6 @@ import React, { FunctionComponent, useState } from "react";
import create, { UseStore } from "zustand";
import Explorer from "../../Explorer";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
// Not currently used, but keeping for future reference
/*
const spinButtonStyles: ISpinButtonStyles = {
label: {
fontSize: 12,
fontWeight: 400,
color: "inherit",
},
root: {
paddingBottom: 10,
},
labelWrapper: {
color: "inherit",
},
icon: {},
spinButtonWrapper: {},
input: {
color: "inherit",
},
arrowButtonsContainer: {},
};
*/
export interface DataPlaneRbacState {
dataPlaneRbacEnabled: boolean;
aadTokenUpdated: boolean;
@ -187,9 +162,9 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
globalAccountName: userContext.databaseAccount?.name,
})
? (loadState({
componentName: AppStateComponentNames.SelectedRegionalEndpoint,
globalAccountName: userContext.databaseAccount?.name,
}) as string)
componentName: AppStateComponentNames.SelectedRegionalEndpoint,
globalAccountName: userContext.databaseAccount?.name,
}) as string)
: undefined,
);
const [retryAttempts, setRetryAttempts] = useState<number>(
@ -1049,6 +1024,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
checked={containerPaginationEnabled}
onChange={() => setContainerPaginationEnabled(!containerPaginationEnabled)}
label="Enable container pagination"
onRenderLabel={() => (
<span style={{ color: "var(--colorNeutralForeground1)" }}>
Enable container pagination
</span>
)}
/>
</div>
</AccordionPanel>
@ -1073,7 +1053,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
ariaLabel="Enable cross partition query"
checked={crossPartitionQueryEnabled}
onChange={() => setCrossPartitionQueryEnabled(!crossPartitionQueryEnabled)}
label="Enable cross-partition query"
onRenderLabel={() => (
<span style={{ color: "var(--colorNeutralForeground1)" }}>
Enable cross-partition query
</span>
)}
/>
</div>
</AccordionPanel>
@ -1105,7 +1089,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
ariaLabel="EnableQueryControl"
checked={queryControlEnabled}
onChange={() => setQueryControlEnabled(!queryControlEnabled)}
label="Enable query control"
onRenderLabel={() => (
<span style={{ color: "var(--colorNeutralForeground1)" }}>
Enable query control
</span>
)}
/>
</div>
</AccordionPanel>
@ -1139,6 +1127,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
onValidate={(newValue) => setMaxDegreeOfParallelism(parseInt(newValue) || maxDegreeOfParallelism)}
ariaLabel="Max degree of parallelism"
label="Max degree of parallelism"
styles={{
label: {
color: "var(--colorNeutralForeground1)"
}
}}
/>
</div>
</AccordionPanel>
@ -1208,7 +1201,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
ariaLabel="Enable sample db for query exploration"
checked={copilotSampleDBEnabled}
onChange={handleSampleDatabaseChange}
label="Enable sample database"
onRenderLabel={() => (
<span style={{ color: "var(--colorNeutralForeground1)" }}>
Enable sample database
</span>
)}
/>
</div>
</AccordionPanel>
@ -1248,12 +1245,12 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
selectors: {
":hover": {
backgroundColor: "var(--colorBrandBackgroundHover)",
color: "var(--colorNeutralForegroundOnBrand)"
color: "var(--colorNeutralForegroundOnBrand)",
},
":active": {
backgroundColor: "var(--colorBrandBackgroundPressed)",
color: "var(--colorNeutralForegroundOnBrand)"
}
color: "var(--colorNeutralForegroundOnBrand)",
},
},
},
}}

View File

@ -1,30 +1,5 @@
// @import "../../../less/Common/Constants";
// .splashScreenContainer {
// width: 100%;
// overflow-y: scroll;
// overflow-x: hidden;
// .splashScreen {
// .flex-display();
// .flex-direction();
// text-align: left;
// margin: auto;
// padding-left: 21px;
// padding-right: 16px;
// max-width: 1168px;
// > .title {
// position: relative; // To attach FeaturePanelLauncher as absolute
// color: @BaseHigh;
// font-size: 48px;
// padding-left: 0px;
// margin: 16px auto;
// text-align: center;
// }
> .subtitle {
// color: @BaseHigh;
font-size: 18px;
padding-left: 0px;
margin: 0px auto;
@ -46,148 +21,3 @@
}
}
// .mainButtonsContainer {
// .flex-display();
// text-align: center;
// cursor: pointer;
// margin: 40px auto;
// width: 84%;
// > .mainButton {
// min-width: 124px;
// max-width: 296px;
// padding: 32px 16px;
// background-color: @BaseLight;
// border: 1px solid #949494;
// box-sizing: border-box;
// box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
// border-radius: 4px;
// > .legendContainer {
// margin-left: 16px;
// text-align: left;
// .legend {
// font-family: @SemiboldFont;
// font-size: 18px;
// }
// .description {
// font-size: 10px;
// }
// .newDescription {
// font-size: 13px;
// }
// }
// }
// > :nth-child(n + 2) {
// margin-left: 32px;
// }
// }
// .moreStuffContainer {
// .flex-display();
// justify-content: space-between;
// .moreStuffColumn {
// flex-grow: 1;
// flex-basis: 0;
// min-width: 124px;
// max-width: 296px;
// > .title {
// font-size: 18px;
// font-family: @SemiboldFont;
// color: @BaseDark;
// padding: 0px;
// margin-bottom: 16px;
// }
// > ul {
// list-style: none;
// padding-left: 0px;
// margin-bottom: 0px;
// li {
// padding: @DefaultSpace;
// .flex-display();
// align-items: flex-start;
// > img {
// margin-right: @DefaultSpace;
// width: 24px;
// height: 24px;
// }
// .oneLineContent {
// margin-top: 4px;
// }
// .description {
// font-size: 10px;
// color: @BaseMediumHigh;
// }
// }
// }
// .tipContainer {
// padding: 8px 16px;
// width: 100%;
// cursor: pointer;
// .flex-display();
// .flex-direction();
// > .title {
// color: @BaseDark;
// padding: 0px;
// font-size: 12px;
// }
// > .description {
// color: @BaseDark;
// }
// &:not(:hover):not(:focus) {
// background-color: @BaseLow;
// }
// }
// &.commonTasks {
// li {
// cursor: pointer;
// }
// }
// &.tipsContainer {
// li {
// margin: 2px 0px;
// }
// }
// }
// }
// .focusable {
// &:hover {
// .hover();
// }
// &:focus {
// .focus();
// }
// &:active {
// .active();
// }
// }
// .notebookSplashScreenItem {
// padding: 12px 0 12px 12px;
// .itemText {
// margin-left: 12px;
// font-family: @SemiboldFont;
// }
// }
// }
// }

View File

@ -35,7 +35,6 @@ import CollectionIcon from "../../../images/tree-collection.svg";
import * as Constants from "../../Common/Constants";
import { userContext } from "../../UserContext";
import { getCollectionName } from "../../Utils/APITypeUtils";
import { useTheme } from "../../hooks/useTheme";
import Explorer from "../Explorer";
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
import { useNotebook } from "../Notebook/useNotebook";
@ -61,18 +60,15 @@ const useStyles = makeStyles({
display: "flex",
flexDirection: "column",
alignItems: "center",
// justifyContent: "center",
minHeight: "100vh",
backgroundColor: "var(--colorNeutralBackground1)",
color: "var(--colorNeutralForeground1)",
},
splashScreen: {
display: "flex",
// overflow: "scroll",
flexDirection: "column",
alignItems: "center",
textAlign: "left",
// ...shorthands.padding("40px")
},
title: {
fontSize: "48px",
@ -140,7 +136,6 @@ const useStyles = makeStyles({
moreStuffColumn: {
display: "flex",
flexDirection: "column",
// justifyContent:"space-between"
},
columnTitle: {
fontSize: "20px",
@ -166,9 +161,6 @@ const useStyles = makeStyles({
export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
const styles = useStyles();
// isDarkMode is used for conditional styling in the component
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { isDarkMode } = useTheme();
const container = explorer;
const subscriptions: Array<{ dispose: () => void }> = [];

View File

@ -24,7 +24,7 @@ import { Allotment } from "allotment";
import { useClientWriteEnabled } from "hooks/useClientWriteEnabled";
import { QueryCopilotState, useQueryCopilot } from "hooks/useQueryCopilot";
import { TabsState, useTabs } from "hooks/useTabs";
import { monacoTheme } from "hooks/useTheme";
import { useMonacoTheme } from "hooks/useTheme";
import React, { Fragment, createRef } from "react";
import "react-splitter-layout/lib/index.css";
import { format } from "react-string-format";
@ -126,6 +126,7 @@ interface IQueryTabStates {
export const QueryTabCopilotComponent = (props: IQueryTabComponentProps): any => {
const styles = useQueryTabStyles();
const monacoTheme = useMonacoTheme();
const copilotStore = useCopilotStore();
const isSampleCopilotActive = useSelectedNode.getState().isQueryCopilotCollectionSelected();
@ -137,16 +138,18 @@ export const QueryTabCopilotComponent = (props: IQueryTabComponentProps): any =>
isSampleCopilotActive: isSampleCopilotActive,
copilotStore: copilotStore,
};
return <QueryTabComponentImpl styles={styles} {...queryTabProps} />;
return <QueryTabComponentImpl styles={styles} monacoTheme={monacoTheme} {...queryTabProps} />;
};
export const QueryTabComponent = (props: IQueryTabComponentProps): any => {
const styles = useQueryTabStyles();
return <QueryTabComponentImpl styles={styles} {...{ ...props }} />;
const monacoTheme = useMonacoTheme();
return <QueryTabComponentImpl styles={styles} monacoTheme={monacoTheme} {...{ ...props }} />;
};
type QueryTabComponentImplProps = IQueryTabComponentProps & {
styles: QueryTabStyles;
monacoTheme: string;
};
// Inner (legacy) class component. We only use this component via one of the two functional components above (since we need to use the `useQueryTabStyles` hook).
@ -761,7 +764,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
wordWrap={"on"}
ariaLabel={"Editing Query"}
lineNumbers={"on"}
theme={monacoTheme}
theme={this.props.monacoTheme}
onContentChanged={(newContent: string) => this.onChangeContent(newContent)}
onContentSelected={(selectedContent: string, selection: monaco.Selection) =>
this.onSelectedContent(selectedContent, selection)

View File

@ -3,7 +3,7 @@ import { Label, TextField } from "@fluentui/react";
import { FluentProvider, webDarkTheme, webLightTheme } from "@fluentui/react-components";
import { KeyboardAction } from "KeyboardShortcuts";
import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils";
import { isDarkMode } from "hooks/useTheme";
import { useThemeStore } from "hooks/useTheme";
import React, { Component } from "react";
import DiscardIcon from "../../../images/discard.svg";
import SaveIcon from "../../../images/save-cosmos.svg";
@ -259,7 +259,7 @@ export default class UserDefinedFunctionTabContent extends Component<
render(): JSX.Element {
const { udfId, udfBody, isUdfIdEditable } = this.state;
const currentTheme = isDarkMode ? webDarkTheme : webLightTheme;
const currentTheme = useThemeStore.getState().isDarkMode ? webDarkTheme : webLightTheme;
return (
<div className="tab-pane flexContainer trigger-form" role="tabpanel">
<FluentProvider theme={currentTheme}>

View File

@ -63,7 +63,7 @@ import { appThemeFabric } from "./Platform/Fabric/FabricTheme";
import "./Shared/appInsights";
import { useConfig } from "./hooks/useConfig";
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
import { isDarkMode } from "./hooks/useTheme";
import { useThemeStore } from "./hooks/useTheme";
import "./less/DarkModeMenus.less";
import "./less/ThemeSystem.less";
// Initialize icons before React is loaded
@ -153,7 +153,18 @@ const App = (): JSX.Element => {
};
const Root: React.FC = () => {
// Use React state to track isDarkMode and subscribe to changes
const [isDarkMode, setIsDarkMode] = React.useState(useThemeStore.getState().isDarkMode);
const currentTheme = isDarkMode ? webDarkTheme : webLightTheme;
// Subscribe to theme changes
React.useEffect(() => {
return useThemeStore.subscribe(
(state) => {
setIsDarkMode(state.isDarkMode);
}
);
}, []);
useEffect(() => {
if (isDarkMode) {

View File

@ -1,5 +1,30 @@
import { useFluent } from "@fluentui/react-components";
import React, { createContext, FC, ReactNode, useEffect, useState } from "react";
import create from "zustand";
interface ThemeSettings {
mode: number;
}
interface FxsTheme {
(): ThemeSettings;
subscribe: (context: null, callback: (update: ThemeSettings) => void) => void;
}
interface MsPortalFxSettings {
"fxs-theme"?: FxsTheme;
[key: string]: unknown;
}
declare global {
interface Window {
MsPortalFx?: {
Services: {
getSettings: () => Promise<MsPortalFxSettings>;
};
};
}
}
interface ThemeContextType {
theme: "Light" | "Dark";
@ -17,19 +42,129 @@ export const CustomThemeProvider: FC<ThemeProviderProps> = ({ children, theme })
const isDarkMode = theme === "Dark";
return <ThemeContext.Provider value={{ theme, isDarkMode }}>{children}</ThemeContext.Provider>;
};
export const isDarkMode = true;
export const monacoTheme = isDarkMode ? "vs-dark" : "vs";
export interface ThemeStore {
isDarkMode: boolean;
themeMode: number;
toggleTheme: () => void;
}
export const useThemeStore = create<ThemeStore>((set) => ({
isDarkMode: false,
themeMode: 0,
toggleTheme: () =>
set((state) => {
const newIsDarkMode = !state.isDarkMode;
const newThemeMode = newIsDarkMode ? 1 : 0;
if (newIsDarkMode) {
document.body.classList.add("isDarkMode");
} else {
document.body.classList.remove("isDarkMode");
}
// Save to localStorage for persistence
localStorage.setItem("cosmos-explorer-theme", newIsDarkMode ? "dark" : "light");
localStorage.setItem("cosmos-explorer-theme-mode", String(newThemeMode));
return {
isDarkMode: newIsDarkMode,
themeMode: newThemeMode,
};
}),
}));
// Initialize the theme from localStorage or MsPortalFx if available
if (typeof window !== "undefined") {
// Try to initialize from MsPortalFx.Services if available
try {
if (window.MsPortalFx && window.MsPortalFx.Services) {
window.MsPortalFx.Services.getSettings()
.then((settings: MsPortalFxSettings) => {
if (settings["fxs-theme"]) {
const theme = settings["fxs-theme"];
// Initial theme value
const initialTheme = theme();
if (initialTheme && typeof initialTheme.mode === "number") {
const isDark = initialTheme.mode === 1;
useThemeStore.setState({
isDarkMode: isDark,
themeMode: initialTheme.mode,
});
if (isDark) {
document.body.classList.add("isDarkMode");
} else {
document.body.classList.remove("isDarkMode");
}
}
theme.subscribe(null, (themeUpdate: ThemeSettings) => {
if (themeUpdate && typeof themeUpdate.mode === "number") {
const isDark = themeUpdate.mode === 1;
useThemeStore.setState({
isDarkMode: isDark,
themeMode: themeUpdate.mode,
});
if (isDark) {
document.body.classList.add("isDarkMode");
} else {
document.body.classList.remove("isDarkMode");
}
}
});
}
})
.catch(() => {
fallbackToLocalStorage();
});
} else {
fallbackToLocalStorage();
}
} catch (error) {
fallbackToLocalStorage();
}
}
function fallbackToLocalStorage() {
const savedTheme = localStorage.getItem("cosmos-explorer-theme");
const savedThemeMode = localStorage.getItem("cosmos-explorer-theme-mode");
if (savedTheme || savedThemeMode) {
const isDark = savedTheme === "dark" || savedThemeMode === "1";
const themeMode = isDark ? 1 : 0;
useThemeStore.setState({
isDarkMode: isDark,
themeMode: themeMode,
});
if (isDark) {
document.body.classList.add("isDarkMode");
}
}
}
// Dynamic exports that use the theme store
export const isDarkMode = () => useThemeStore.getState().isDarkMode;
export const useMonacoTheme = () => {
const { isDarkMode } = useThemeStore();
return isDarkMode ? "vs-dark" : "vs";
};
export const monacoTheme = () => (useThemeStore.getState().isDarkMode ? "vs-dark" : "vs");
export const useTheme = () => {
const { targetDocument } = useFluent();
const context = React.useContext(ThemeContext);
const [isDarkMode, setIsDarkMode] = useState(() => {
// First check if we're in a theme context
if (context) {
return context.isDarkMode;
}
// Fallback to checking body class
return targetDocument?.body.classList.contains("isDarkMode") ?? true;
});
@ -38,20 +173,16 @@ export const useTheme = () => {
return undefined;
}
const checkTheme = () => {
// First check if we're in a theme context
if (context) {
setIsDarkMode(context.isDarkMode);
return;
}
// Fallback to checking body class
const hasDarkMode = targetDocument.body.classList.contains("isDarkMode");
setIsDarkMode(hasDarkMode);
};
// Initial check
checkTheme();
// Create a MutationObserver to watch for class changes
const observer = new MutationObserver(() => {
checkTheme();
});