mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-05 18:47:41 +00:00
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:
@@ -1,6 +1,6 @@
|
||||
import { FitAddon } from "@xterm/addon-fit";
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { Terminal } from "xterm";
|
||||
import { FitAddon } from "xterm-addon-fit";
|
||||
import "xterm/css/xterm.css";
|
||||
import { DatabaseAccount } from "../../../Contracts/DataModels";
|
||||
import { TerminalKind } from "../../../Contracts/ViewModels";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
import { Terminal } from "xterm";
|
||||
import { Areas } from "../../../Common/Constants";
|
||||
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||
import { TerminalKind } from "../../../Contracts/ViewModels";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IDisposable, ITerminalAddon, Terminal } from "@xterm/xterm";
|
||||
import { IDisposable, ITerminalAddon, Terminal } from "xterm";
|
||||
import { AbstractShellHandler } from "../ShellTypes/AbstractShellHandler";
|
||||
import { formatErrorMessage } from "./TerminalLogFormats";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
import { Terminal } from "xterm";
|
||||
import { TerminalKind } from "../../../../Contracts/ViewModels";
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,13 +70,23 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
|
||||
const textfieldStyles: Partial<ITextFieldStyles> = {
|
||||
root: { width: "100%" },
|
||||
field: { backgroundColor: "rgb(230, 230, 230)" },
|
||||
fieldGroup: { borderColor: "rgb(138, 136, 134)" },
|
||||
field: {
|
||||
backgroundColor: "var(--colorNeutralBackground3)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
fieldGroup: { borderColor: "var(--colorNeutralStroke1)" },
|
||||
suffix: {
|
||||
backgroundColor: "rgb(230, 230, 230)",
|
||||
backgroundColor: "var(--colorNeutralBackground3)",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
},
|
||||
subComponentStyles: {
|
||||
label: {
|
||||
root: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const renderCopyButton = (selector: string) => (
|
||||
@@ -86,19 +96,65 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
styles={{
|
||||
root: {
|
||||
height: "100%",
|
||||
backgroundColor: "rgb(230, 230, 230)",
|
||||
backgroundColor: "var(--colorNeutralBackground3)",
|
||||
border: "none",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootHovered: {
|
||||
backgroundColor: "rgb(220, 220, 220)",
|
||||
backgroundColor: "var(--colorNeutralBackground4)",
|
||||
},
|
||||
rootPressed: {
|
||||
backgroundColor: "rgb(210, 210, 210)",
|
||||
backgroundColor: "var(--colorNeutralBackground5)",
|
||||
},
|
||||
icon: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const themeAwareIconButtonStyles = {
|
||||
root: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
rootHovered: {
|
||||
backgroundColor: "var(--colorNeutralBackground3)",
|
||||
},
|
||||
icon: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
};
|
||||
|
||||
const pivotStyles = {
|
||||
root: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
link: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "transparent",
|
||||
selectors: {
|
||||
"&:hover": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "var(--colorNeutralBackground3)",
|
||||
},
|
||||
"&:active": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
linkIsSelected: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
selectors: {
|
||||
"&::before": {
|
||||
backgroundColor: "var(--colorBrandBackground)",
|
||||
},
|
||||
},
|
||||
},
|
||||
text: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", padding: 16 }}>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 16, margin: 10 }}>
|
||||
@@ -113,7 +169,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<div style={{ width: 32 }}></div>
|
||||
</Stack>
|
||||
|
||||
<Pivot>
|
||||
<Pivot styles={pivotStyles}>
|
||||
{userContext.hasWriteAccess && (
|
||||
<PivotItem headerText="Read-write Keys">
|
||||
<Stack style={{ margin: 10, overflow: "auto", maxHeight: "calc(100vh - 300px)" }}>
|
||||
@@ -131,6 +187,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showPrimaryMasterKey ? "Hide3" : "View" }}
|
||||
onClick={() => setShowPrimaryMasterKey(!showPrimaryMasterKey)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
@@ -147,6 +204,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showSecondaryMasterKey ? "Hide3" : "View" }}
|
||||
onClick={() => setShowSecondaryMasterKey(!showSecondaryMasterKey)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
@@ -163,6 +221,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showPrimaryConnectionStr ? "Hide3" : "View" }}
|
||||
onClick={() => setShowPrimaryConnectionStr(!showPrimaryConnectionStr)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
@@ -179,6 +238,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showSecondaryConnectionStr ? "Hide3" : "View" }}
|
||||
onClick={() => setShowSecondaryConnectionStr(!showSecondaryConnectionStr)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
@@ -200,6 +260,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showPrimaryReadonlyMasterKey ? "Hide3" : "View" }}
|
||||
onClick={() => setShowPrimaryReadonlyMasterKey(!showPrimaryReadonlyMasterKey)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
@@ -216,6 +277,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showSecondaryReadonlyMasterKey ? "Hide3" : "View" }}
|
||||
onClick={() => setShowSecondaryReadonlyMasterKey(!showSecondaryReadonlyMasterKey)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
@@ -232,6 +294,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showPrimaryReadonlyConnectionStr ? "Hide3" : "View" }}
|
||||
onClick={() => setShowPrimaryReadonlyConnectionStr(!showPrimaryReadonlyConnectionStr)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
@@ -248,6 +311,7 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
<IconButton
|
||||
iconProps={{ iconName: showSecondaryReadonlyConnectionStr ? "Hide3" : "View" }}
|
||||
onClick={() => setShowSecondaryReadonlyConnectionStr(!showSecondaryReadonlyConnectionStr)}
|
||||
styles={themeAwareIconButtonStyles}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
@@ -255,10 +319,23 @@ export const ConnectTab: React.FC = (): JSX.Element => {
|
||||
</Pivot>
|
||||
|
||||
<Stack style={{ margin: 10 }}>
|
||||
<Text style={{ fontWeight: 600, marginBottom: 8 }}>Download sample app</Text>
|
||||
<Text style={{ marginBottom: 8 }}>
|
||||
Don’t have an app ready? No worries, download one of our sample app with a platform of your choice. Connection
|
||||
string is already included in the app.
|
||||
<Text
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
marginBottom: 8,
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
}}
|
||||
>
|
||||
Download sample app
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
marginBottom: 8,
|
||||
color: "var(--colorNeutralForeground2)",
|
||||
}}
|
||||
>
|
||||
Don't have an app ready? No worries, download one of our sample app with a platform of your choice.
|
||||
Connection string is already included in the app.
|
||||
</Text>
|
||||
<PrimaryButton
|
||||
style={{ width: 185 }}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Link } from "@fluentui/react-components";
|
||||
import { Link, tokens } from "@fluentui/react-components";
|
||||
import QueryError from "Common/QueryError";
|
||||
import { IndeterminateProgressBar } from "Explorer/Controls/IndeterminateProgressBar";
|
||||
import { MessageBanner } from "Explorer/Controls/MessageBanner";
|
||||
@@ -36,7 +36,7 @@ const ExecuteQueryCallToAction: React.FC = () => {
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</p>
|
||||
<p>Execute a query to see the results</p>
|
||||
<p style={{ color: tokens.colorNeutralForeground1 }}>Execute a query to see the results</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -24,6 +24,7 @@ import { Allotment } from "allotment";
|
||||
import { useClientWriteEnabled } from "hooks/useClientWriteEnabled";
|
||||
import { QueryCopilotState, useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import { TabsState, useTabs } from "hooks/useTabs";
|
||||
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 +127,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 +139,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,6 +765,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
|
||||
wordWrap={"on"}
|
||||
ariaLabel={"Editing Query"}
|
||||
lineNumbers={"on"}
|
||||
theme={this.props.monacoTheme}
|
||||
onContentChanged={(newContent: string) => this.onChangeContent(newContent)}
|
||||
onContentSelected={(selectedContent: string, selection: monaco.Selection) =>
|
||||
this.onSelectedContent(selectedContent, selection)
|
||||
|
||||
@@ -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]}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { TriggerDefinition } from "@azure/cosmos";
|
||||
import { Dropdown, IDropdownOption, Label, TextField } from "@fluentui/react";
|
||||
import { IDropdownOption, IDropdownStyles, Label, TextField } from "@fluentui/react";
|
||||
import { Dropdown } from "@fluentui/react/lib/Dropdown";
|
||||
import { KeyboardAction } from "KeyboardShortcuts";
|
||||
import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils";
|
||||
import React, { Component } from "react";
|
||||
@@ -17,12 +18,134 @@ import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandBu
|
||||
import { EditorReact } from "../Controls/Editor/EditorReact";
|
||||
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
||||
import TriggerTab from "./TriggerTab";
|
||||
|
||||
const triggerTypeOptions: IDropdownOption[] = [
|
||||
{ key: "Pre", text: "Pre" },
|
||||
{ key: "Post", text: "Post" },
|
||||
];
|
||||
|
||||
const dropdownStyles: Partial<IDropdownStyles> = {
|
||||
root: {
|
||||
width: "40%",
|
||||
marginTop: "10px",
|
||||
selectors: {
|
||||
"&:hover .ms-Dropdown-title": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
borderColor: "var(--colorNeutralStroke1)",
|
||||
},
|
||||
"&:hover span.ms-Dropdown-title": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:focus .ms-Dropdown-title": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
},
|
||||
"&:focus span.ms-Dropdown-title": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
label: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
dropdown: {
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
borderColor: "var(--colorNeutralStroke1)",
|
||||
},
|
||||
title: {
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
borderColor: "var(--colorNeutralStroke1)",
|
||||
selectors: {
|
||||
"&:hover": {
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:focus": {
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:hover .ms-Dropdown-titleText": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:focus .ms-Dropdown-titleText": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"& .ms-Dropdown-titleText": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
caretDown: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
callout: {
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
border: "1px solid var(--colorNeutralStroke1)",
|
||||
},
|
||||
dropdownItems: {
|
||||
backgroundColor: "var(--colorNeutralBackground2)",
|
||||
},
|
||||
dropdownItem: {
|
||||
backgroundColor: "transparent",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
minHeight: "36px",
|
||||
lineHeight: "36px",
|
||||
selectors: {
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:hover .ms-Dropdown-optionText": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:focus": {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:active": {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"& .ms-Dropdown-optionText": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
dropdownItemSelected: {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.08)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
minHeight: "36px",
|
||||
lineHeight: "36px",
|
||||
selectors: {
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:hover .ms-Dropdown-optionText": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:focus": {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"&:active": {
|
||||
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
"& .ms-Dropdown-optionText": {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
dropdownOptionText: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
dropdownItemHeader: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
};
|
||||
|
||||
const triggerOperationOptions: IDropdownOption[] = [
|
||||
{ key: "All", text: "All" },
|
||||
{ key: "Create", text: "Create" },
|
||||
@@ -304,6 +427,23 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
|
||||
value={triggerId}
|
||||
readOnly={!isIdEditable}
|
||||
onChange={this.handleTriggerIdChange}
|
||||
styles={{
|
||||
root: { width: "40%", marginTop: "10px" },
|
||||
fieldGroup: {
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
border: "1px solid var(--colorNeutralStroke1)",
|
||||
},
|
||||
field: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
subComponentStyles: {
|
||||
label: {
|
||||
root: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Dropdown
|
||||
placeholder="Trigger Type"
|
||||
@@ -312,6 +452,7 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
|
||||
selectedKey={triggerType}
|
||||
className="trigger-field"
|
||||
onChange={(event, selectedKey) => this.handleTriggerTypeOprationChange(event, selectedKey, "triggerType")}
|
||||
styles={dropdownStyles}
|
||||
/>
|
||||
<Dropdown
|
||||
placeholder="Trigger Operation"
|
||||
@@ -322,6 +463,7 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
|
||||
onChange={(event, selectedKey) =>
|
||||
this.handleTriggerTypeOprationChange(event, selectedKey, "triggerOperation")
|
||||
}
|
||||
styles={dropdownStyles}
|
||||
/>
|
||||
<Label className="trigger-field">Trigger Body</Label>
|
||||
<EditorReact
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||
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 { useThemeStore } from "hooks/useTheme";
|
||||
import React, { Component } from "react";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
@@ -16,7 +18,6 @@ import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandBu
|
||||
import { EditorReact } from "../Controls/Editor/EditorReact";
|
||||
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
||||
import UserDefinedFunctionTab from "./UserDefinedFunctionTab";
|
||||
|
||||
interface IUserDefinedFunctionTabContentState {
|
||||
udfId: string;
|
||||
udfBody: string;
|
||||
@@ -258,23 +259,46 @@ export default class UserDefinedFunctionTabContent extends Component<
|
||||
|
||||
render(): JSX.Element {
|
||||
const { udfId, udfBody, isUdfIdEditable } = this.state;
|
||||
const currentTheme = useThemeStore.getState().isDarkMode ? webDarkTheme : webLightTheme;
|
||||
return (
|
||||
<div className="tab-pane flexContainer trigger-form" role="tabpanel">
|
||||
<TextField
|
||||
className="trigger-field"
|
||||
label="User Defined Function Id"
|
||||
id="entityTimeId"
|
||||
autoFocus
|
||||
required
|
||||
readOnly={!isUdfIdEditable}
|
||||
type="text"
|
||||
pattern={ValidCosmosDbIdInputPattern.source}
|
||||
title={ValidCosmosDbIdDescription}
|
||||
placeholder="Enter the new user defined function id"
|
||||
size={40}
|
||||
value={udfId}
|
||||
onChange={this.handleUdfIdChange}
|
||||
/>
|
||||
<FluentProvider theme={currentTheme}>
|
||||
<TextField
|
||||
className="trigger-field"
|
||||
label="User Defined Function Id"
|
||||
id="entityTimeId"
|
||||
autoFocus
|
||||
required
|
||||
readOnly={!isUdfIdEditable}
|
||||
type="text"
|
||||
pattern={ValidCosmosDbIdInputPattern.source}
|
||||
title={ValidCosmosDbIdDescription}
|
||||
placeholder="Enter the new user defined function id"
|
||||
size={40}
|
||||
value={udfId}
|
||||
onChange={this.handleUdfIdChange}
|
||||
styles={{
|
||||
root: {
|
||||
width: "40%",
|
||||
marginTop: "10px",
|
||||
},
|
||||
fieldGroup: {
|
||||
backgroundColor: "var(--colorNeutralBackground1)",
|
||||
border: "1px solid var(--colorNeutralStroke1)",
|
||||
},
|
||||
field: {
|
||||
color: "var(--colorNeutralForeground2)",
|
||||
},
|
||||
subComponentStyles: {
|
||||
label: {
|
||||
root: {
|
||||
color: "var(--colorNeutralForeground1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>{" "}
|
||||
</FluentProvider>
|
||||
<Label className="trigger-field">User Defined Function Body</Label>
|
||||
<EditorReact
|
||||
language={"javascript"}
|
||||
|
||||
Reference in New Issue
Block a user