Compare commits

..

2 Commits

Author SHA1 Message Date
sunilyadav840
27d129e689 configure and fixed eslint jsx-a11y issues 2021-10-01 11:51:27 +05:30
sunilyadav840
fb9f97b43a configure eslint-plugin-jsx-a11y 2021-09-30 19:53:04 +05:30
74 changed files with 500 additions and 788 deletions

View File

@@ -106,6 +106,7 @@ src/Explorer/Tabs/ScriptTabBase.ts
src/Explorer/Tabs/TabComponents.ts src/Explorer/Tabs/TabComponents.ts
src/Explorer/Tabs/TabsBase.ts src/Explorer/Tabs/TabsBase.ts
src/Explorer/Tabs/TriggerTab.ts src/Explorer/Tabs/TriggerTab.ts
src/Explorer/Tabs/UserDefinedFunctionTab.ts
src/Explorer/Tree/AccessibleVerticalList.ts src/Explorer/Tree/AccessibleVerticalList.ts
src/Explorer/Tree/Collection.ts src/Explorer/Tree/Collection.ts
src/Explorer/Tree/ConflictId.ts src/Explorer/Tree/ConflictId.ts
@@ -117,12 +118,14 @@ src/Explorer/Tree/TreeComponents.ts
src/Explorer/Tree/Trigger.ts src/Explorer/Tree/Trigger.ts
src/Explorer/WaitsForTemplateViewModel.ts src/Explorer/WaitsForTemplateViewModel.ts
src/GitHub/GitHubClient.test.ts src/GitHub/GitHubClient.test.ts
src/GitHub/GitHubClient.ts
src/GitHub/GitHubConnector.ts src/GitHub/GitHubConnector.ts
src/GitHub/GitHubOAuthService.ts src/GitHub/GitHubOAuthService.ts
src/Index.ts src/Index.ts
src/Juno/JunoClient.test.ts src/Juno/JunoClient.test.ts
src/Juno/JunoClient.ts src/Juno/JunoClient.ts
src/Platform/Hosted/Authorization.ts src/Platform/Hosted/Authorization.ts
src/ReactDevTools.ts
src/Shared/Constants.ts src/Shared/Constants.ts
src/Shared/DefaultExperienceUtility.test.ts src/Shared/DefaultExperienceUtility.test.ts
src/Shared/DefaultExperienceUtility.ts src/Shared/DefaultExperienceUtility.ts
@@ -154,6 +157,7 @@ src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
src/Explorer/Notebook/NotebookComponent/VirtualCommandBarComponent.tsx src/Explorer/Notebook/NotebookComponent/VirtualCommandBarComponent.tsx
src/Explorer/Notebook/NotebookComponent/contents/index.tsx src/Explorer/Notebook/NotebookComponent/contents/index.tsx
src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx
src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx
src/Explorer/Notebook/NotebookRenderer/decorators/draggable/index.tsx src/Explorer/Notebook/NotebookRenderer/decorators/draggable/index.tsx
src/Explorer/Notebook/NotebookRenderer/decorators/hijack-scroll/index.tsx src/Explorer/Notebook/NotebookRenderer/decorators/hijack-scroll/index.tsx
src/Explorer/Notebook/NotebookRenderer/decorators/kbd-shortcuts/index.tsx src/Explorer/Notebook/NotebookRenderer/decorators/kbd-shortcuts/index.tsx

View File

@@ -3,8 +3,8 @@ module.exports = {
browser: true, browser: true,
es6: true, es6: true,
}, },
plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks"], plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks", "jsx-a11y"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:jsx-a11y/recommended"],
globals: { globals: {
Atomics: "readonly", Atomics: "readonly",
SharedArrayBuffer: "readonly", SharedArrayBuffer: "readonly",

View File

@@ -3079,3 +3079,6 @@ settings-pane {
background: white; background: white;
height: 100%; height: 100%;
} }
.moreOption {
color: #337ab7;
}

91
package-lock.json generated
View File

@@ -6809,6 +6809,11 @@
"integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=", "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=",
"dev": true "dev": true
}, },
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0="
},
"astral-regex": { "astral-regex": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
@@ -6876,6 +6881,11 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
}, },
"axe-core": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz",
"integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA=="
},
"axios": { "axios": {
"version": "0.21.1", "version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
@@ -6891,6 +6901,11 @@
} }
} }
}, },
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
"integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA=="
},
"babel-code-frame": { "babel-code-frame": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -8878,6 +8893,11 @@
"d3-transition": "2" "d3-transition": "2"
} }
}, },
"damerau-levenshtein": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz",
"integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw=="
},
"dashdash": { "dashdash": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -10171,6 +10191,64 @@
"@typescript-eslint/experimental-utils": "^2.5.0" "@typescript-eslint/experimental-utils": "^2.5.0"
} }
}, },
"eslint-plugin-jsx-a11y": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz",
"integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==",
"requires": {
"@babel/runtime": "^7.11.2",
"aria-query": "^4.2.2",
"array-includes": "^3.1.1",
"ast-types-flow": "^0.0.7",
"axe-core": "^4.0.2",
"axobject-query": "^2.2.0",
"damerau-levenshtein": "^1.0.6",
"emoji-regex": "^9.0.0",
"has": "^1.0.3",
"jsx-ast-utils": "^3.1.0",
"language-tags": "^1.0.5"
},
"dependencies": {
"emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
"get-intrinsic": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
}
},
"jsx-ast-utils": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz",
"integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==",
"requires": {
"array-includes": "^3.1.3",
"object.assign": "^4.1.2"
},
"dependencies": {
"array-includes": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
"integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"es-abstract": "^1.18.0-next.2",
"get-intrinsic": "^1.1.1",
"is-string": "^1.0.5"
}
}
}
}
}
},
"eslint-plugin-no-null": { "eslint-plugin-no-null": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
@@ -18065,6 +18143,19 @@
"resolved": "https://registry.npmjs.org/labella/-/labella-1.1.4.tgz", "resolved": "https://registry.npmjs.org/labella/-/labella-1.1.4.tgz",
"integrity": "sha1-xsxaNA6N80DrM1YzaD6lm4KMMi0=" "integrity": "sha1-xsxaNA6N80DrM1YzaD6lm4KMMi0="
}, },
"language-subtag-registry": {
"version": "0.3.21",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
"integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg=="
},
"language-tags": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
"integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=",
"requires": {
"language-subtag-registry": "~0.3.2"
}
},
"lcid": { "lcid": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",

View File

@@ -61,6 +61,7 @@
"dom-to-image": "2.6.0", "dom-to-image": "2.6.0",
"dotenv": "8.2.0", "dotenv": "8.2.0",
"eslint-plugin-jest": "23.13.2", "eslint-plugin-jest": "23.13.2",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-react": "7.20.0", "eslint-plugin-react": "7.20.0",
"hasher": "1.2.0", "hasher": "1.2.0",
"html2canvas": "1.0.0-rc.5", "html2canvas": "1.0.0-rc.5",

View File

@@ -31,17 +31,15 @@ export const CollapsedResourceTree: FunctionComponent<CollapsedResourceTreeProps
<div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}> <div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}>
<div className="main-nav nav"> <div className="main-nav nav">
<ul className="nav"> <ul className="nav">
<li <li className="resourceTreeCollapse" id="collapseToggleLeftPaneButton" aria-label="Expand Tree">
className="resourceTreeCollapse" <span
id="collapseToggleLeftPaneButton" className="leftarrowCollapsed"
role="button" role="button"
tabIndex={0} tabIndex={0}
aria-label="Expand Tree"
onClick={toggleLeftPaneExpanded} onClick={toggleLeftPaneExpanded}
onKeyPress={onKeyPressToggleLeftPaneExpanded} onKeyPress={onKeyPressToggleLeftPaneExpanded}
ref={focusButton} ref={focusButton}
> >
<span className="leftarrowCollapsed">
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" /> <img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
</span> </span>
<span className="collectionCollapsed"> <span className="collectionCollapsed">

View File

@@ -339,11 +339,9 @@ export enum ConflictOperationType {
} }
export enum ConnectionStatusType { export enum ConnectionStatusType {
Connect = "Connect",
Connecting = "Connecting", Connecting = "Connecting",
Connected = "Connected", Connected = "Connected",
Failed = "Connection Failed", Failed = "Connection Failed",
ReConnect = "Reconnect",
} }
export const EmulatorMasterKey = export const EmulatorMasterKey =
@@ -355,32 +353,15 @@ export const StyleConstants = require("less-vars-loader!../../less/Common/Consta
export class Notebook { export class Notebook {
public static readonly defaultBasePath = "./notebooks"; public static readonly defaultBasePath = "./notebooks";
public static readonly heartbeatDelayMs = 60000; public static readonly heartbeatDelayMs = 5000;
public static readonly kernelRestartInitialDelayMs = 1000; public static readonly kernelRestartInitialDelayMs = 1000;
public static readonly kernelRestartMaxDelayMs = 20000; public static readonly kernelRestartMaxDelayMs = 20000;
public static readonly autoSaveIntervalMs = 120000; public static readonly autoSaveIntervalMs = 120000;
public static readonly memoryGuageToGB = 1048576;
public static readonly temporarilyDownMsg = "Notebooks is currently not available. We are working on it."; public static readonly temporarilyDownMsg = "Notebooks is currently not available. We are working on it.";
public static readonly mongoShellTemporarilyDownMsg = public static readonly mongoShellTemporarilyDownMsg =
"We have identified an issue with the Mongo Shell and it is unavailable right now. We are actively working on the mitigation."; "We have identified an issue with the Mongo Shell and it is unavailable right now. We are actively working on the mitigation.";
public static readonly cassandraShellTemporarilyDownMsg = public static readonly cassandraShellTemporarilyDownMsg =
"We have identified an issue with the Cassandra Shell and it is unavailable right now. We are actively working on the mitigation."; "We have identified an issue with the Cassandra Shell and it is unavailable right now. We are actively working on the mitigation.";
public static saveNotebookModalTitle = "Save Notebook in temporary workspace";
public static saveNotebookModalContent =
"This notebook will be saved in the temporary workspace and will be removed when the session expires. To save your work permanently, save your notebooks to a GitHub repository or download the notebooks to your local machine before the session ends.";
public static newNotebookModalTitle = "Create Notebook in temporary workspace";
public static newNotebookUploadModalTitle = "Upload Notebook in temporary workspace";
public static newNotebookModalContent1 =
"A temporary workspace will be created to enable you to work with notebooks. When the session expires, any notebooks in the workspace will be removed.";
public static newNotebookModalContent2 =
"To save your work permanently, save your notebooks to a GitHub repository or download the notebooks to your local machine before the session ends. ";
public static galleryNotebookDownloadContent1 =
"To download, run, and make changes to this sample notebook, a temporary workspace will be created. When the session expires, any notebooks in the workspace will be removed.";
public static galleryNotebookDownloadContent2 =
"To save your work permanently, save your notebooks to a GitHub repository or download the Notebooks to your local machine before the session ends. ";
public static cosmosNotebookHomePageUrl = "https://aka.ms/cosmos-notebooks-limits";
public static cosmosNotebookGitDocumentationUrl = "https://aka.ms/cosmos-notebooks-github";
public static learnMore = "Learn more.";
} }
export class SparkLibrary { export class SparkLibrary {

View File

@@ -40,7 +40,6 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
<TextField <TextField
label={entityValueLabel && entityValueLabel} label={entityValueLabel && entityValueLabel}
id="entityTimeId" id="entityTimeId"
autoFocus
type="time" type="time"
value={entityTimeValue} value={entityTimeValue}
onChange={onEntityTimeValueChange} onChange={onEntityTimeValueChange}
@@ -55,7 +54,6 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
label={entityValueLabel && entityValueLabel} label={entityValueLabel && entityValueLabel}
className="addEntityTextField" className="addEntityTextField"
id="entityValueId" id="entityValueId"
autoFocus
disabled={isEntityValueDisable} disabled={isEntityValueDisable}
type={entityValueType} type={entityValueType}
placeholder={entityValuePlaceholder} placeholder={entityValuePlaceholder}

View File

@@ -96,7 +96,6 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
<TextField <TextField
label={entityPropertyLabel && entityPropertyLabel} label={entityPropertyLabel && entityPropertyLabel}
id="entityPropertyId" id="entityPropertyId"
autoFocus
disabled={isPropertyTypeDisable} disabled={isPropertyTypeDisable}
placeholder={entityPropertyPlaceHolder} placeholder={entityPropertyPlaceHolder}
value={entityProperty} value={entityProperty}

View File

@@ -66,9 +66,15 @@ export const Upload: FunctionComponent<UploadProps> = ({
onChange={onUpload} onChange={onUpload}
role="button" role="button"
/> />
<a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}> <span
id="fileImportLinkNotebook"
role="button"
tabIndex={0}
onClick={onImportLinkClick}
onKeyPress={onImportLinkKeyPress}
>
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} /> <Image className="fileImportImg" src={FolderIcon} alt={title} title={title} />
</a> </span>
</Stack> </Stack>
</div> </div>
); );

View File

@@ -55,7 +55,13 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
public render(): JSX.Element { public render(): JSX.Element {
return ( return (
<div className="accordionItemContainer"> <div className="accordionItemContainer">
<div className="accordionItemHeader" onClick={this.onHeaderClick} onKeyPress={this.onHeaderKeyPress}> <div
className="accordionItemHeader"
onClick={this.onHeaderClick}
onKeyPress={this.onHeaderKeyPress}
role="button"
tabIndex={0}
>
{this.renderCollapseExpandIcon()} {this.renderCollapseExpandIcon()}
{this.props.title} {this.props.title}
</div> </div>
@@ -74,8 +80,6 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
className="expandCollapseIcon" className="expandCollapseIcon"
src={this.state.isExpanded ? TriangleDownIcon : TriangleRightIcon} src={this.state.isExpanded ? TriangleDownIcon : TriangleRightIcon}
alt="Hide" alt="Hide"
tabIndex={0}
role="button"
/> />
); );
} }

View File

@@ -49,7 +49,7 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
onClick={this.toggleCollapsed} onClick={this.toggleCollapsed}
onKeyPress={this.onKeyPress} onKeyPress={this.onKeyPress}
tabIndex={0} tabIndex={0}
aria-name="Advanced" aria-label="Advanced"
role="button" role="button"
aria-expanded={this.state.isExpanded} aria-expanded={this.state.isExpanded}
> >

View File

@@ -4,7 +4,7 @@ exports[`CollapsibleSectionComponent renders 1`] = `
<Fragment> <Fragment>
<Stack <Stack
aria-expanded={true} aria-expanded={true}
aria-name="Advanced" aria-label="Advanced"
className="collapsibleSection" className="collapsibleSection"
horizontal={true} horizontal={true}
onClick={[Function]} onClick={[Function]}

View File

@@ -188,12 +188,13 @@ export class CommandButtonComponent extends React.Component<CommandButtonCompone
ref={(ref: HTMLElement) => { ref={(ref: HTMLElement) => {
this.expandButtonElt = ref; this.expandButtonElt = ref;
}} }}
role="button"
onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => this.onLauncherKeyDown(e)} onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => this.onLauncherKeyDown(e)}
> >
<div className="commandDropdownLauncher"> <div className="commandDropdownLauncher">
<span className="partialSplitter" /> <span className="partialSplitter" />
<span className="expandDropdown"> <span className="expandDropdown">
<img src={CollapseChevronDownIcon} /> <img src={CollapseChevronDownIcon} alt="Collapse down icon" />
</span> </span>
</div> </div>
<div <div

View File

@@ -13,7 +13,6 @@ import {
Link, Link,
PrimaryButton, PrimaryButton,
ProgressIndicator, ProgressIndicator,
Text,
TextField, TextField,
} from "@fluentui/react"; } from "@fluentui/react";
import React, { FC } from "react"; import React, { FC } from "react";
@@ -31,7 +30,6 @@ export interface DialogState {
onOk: () => void, onOk: () => void,
cancelLabel: string, cancelLabel: string,
onCancel: () => void, onCancel: () => void,
contentHtml?: JSX.Element,
choiceGroupProps?: IChoiceGroupProps, choiceGroupProps?: IChoiceGroupProps,
textFieldProps?: TextFieldProps, textFieldProps?: TextFieldProps,
primaryButtonDisabled?: boolean primaryButtonDisabled?: boolean
@@ -60,7 +58,6 @@ export const useDialog: UseStore<DialogState> = create((set, get) => ({
onOk: () => void, onOk: () => void,
cancelLabel: string, cancelLabel: string,
onCancel: () => void, onCancel: () => void,
contentHtml?: JSX.Element,
choiceGroupProps?: IChoiceGroupProps, choiceGroupProps?: IChoiceGroupProps,
textFieldProps?: TextFieldProps, textFieldProps?: TextFieldProps,
primaryButtonDisabled?: boolean primaryButtonDisabled?: boolean
@@ -79,7 +76,6 @@ export const useDialog: UseStore<DialogState> = create((set, get) => ({
get().closeDialog(); get().closeDialog();
onCancel && onCancel(); onCancel && onCancel();
}, },
contentHtml,
choiceGroupProps, choiceGroupProps,
textFieldProps, textFieldProps,
primaryButtonDisabled, primaryButtonDisabled,
@@ -128,7 +124,6 @@ export interface DialogProps {
type?: DialogType; type?: DialogType;
showCloseButton?: boolean; showCloseButton?: boolean;
onDismiss?: () => void; onDismiss?: () => void;
contentHtml?: JSX.Element;
} }
const DIALOG_MIN_WIDTH = "400px"; const DIALOG_MIN_WIDTH = "400px";
@@ -155,7 +150,6 @@ export const Dialog: FC = () => {
type, type,
showCloseButton, showCloseButton,
onDismiss, onDismiss,
contentHtml,
} = props || {}; } = props || {};
const dialogProps: IDialogProps = { const dialogProps: IDialogProps = {
@@ -197,7 +191,6 @@ export const Dialog: FC = () => {
{linkProps.linkText} <FontIcon iconName="NavigateExternalInline" /> {linkProps.linkText} <FontIcon iconName="NavigateExternalInline" />
</Link> </Link>
)} )}
{contentHtml && <Text>{contentHtml}</Text>}
{progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />} {progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />}
<DialogFooter> <DialogFooter>
<PrimaryButton {...primaryButtonProps} /> <PrimaryButton {...primaryButtonProps} />

View File

@@ -17,8 +17,6 @@ import Explorer from "../../Explorer";
import { NotebookClientV2 } from "../../Notebook/NotebookClientV2"; import { NotebookClientV2 } from "../../Notebook/NotebookClientV2";
import { NotebookComponentBootstrapper } from "../../Notebook/NotebookComponent/NotebookComponentBootstrapper"; import { NotebookComponentBootstrapper } from "../../Notebook/NotebookComponent/NotebookComponentBootstrapper";
import NotebookReadOnlyRenderer from "../../Notebook/NotebookRenderer/NotebookReadOnlyRenderer"; import NotebookReadOnlyRenderer from "../../Notebook/NotebookRenderer/NotebookReadOnlyRenderer";
import { NotebookUtil } from "../../Notebook/NotebookUtil";
import { useNotebook } from "../../Notebook/useNotebook";
import { Dialog, TextFieldProps, useDialog } from "../Dialog"; import { Dialog, TextFieldProps, useDialog } from "../Dialog";
import { NotebookMetadataComponent } from "./NotebookMetadataComponent"; import { NotebookMetadataComponent } from "./NotebookMetadataComponent";
import "./NotebookViewerComponent.less"; import "./NotebookViewerComponent.less";
@@ -148,9 +146,7 @@ export class NotebookViewerComponent
<NotebookMetadataComponent <NotebookMetadataComponent
data={this.state.galleryItem} data={this.state.galleryItem}
isFavorite={this.state.isFavorite} isFavorite={this.state.isFavorite}
downloadButtonText={ downloadButtonText={this.props.container && "Download to my notebooks"}
this.props.container && NotebookUtil.getNotebookBtnTitle(useNotebook.getState().notebookFolderName)
}
onTagClick={this.props.onTagClick} onTagClick={this.props.onTagClick}
onFavoriteClick={this.favoriteItem} onFavoriteClick={this.favoriteItem}
onUnfavoriteClick={this.unfavoriteItem} onUnfavoriteClick={this.unfavoriteItem}

View File

@@ -150,7 +150,7 @@ export class QueriesGridComponent extends React.Component<QueriesGridComponentPr
To write a new query, open a new query tab and enter the desired query. Once ready to save, click on Save To write a new query, open a new query tab and enter the desired query. Once ready to save, click on Save
Query and follow the prompt in order to save the query. Query and follow the prompt in order to save the query.
</div> </div>
<img {...bannerProps} /> <img {...bannerProps} alt="Save query helper banner" />
</div> </div>
); );
} }

View File

@@ -122,7 +122,7 @@ export class IndexingPolicyComponent extends React.Component<
{isDirty(this.props.indexingPolicyContent, this.props.indexingPolicyContentBaseline) && ( {isDirty(this.props.indexingPolicyContent, this.props.indexingPolicyContentBaseline) && (
<MessageBar messageBarType={MessageBarType.warning}>{indexingPolicynUnsavedWarningMessage}</MessageBar> <MessageBar messageBarType={MessageBarType.warning}>{indexingPolicynUnsavedWarningMessage}</MessageBar>
)} )}
<div className="settingsV2IndexingPolicyEditor" tabIndex={0} ref={this.indexingPolicyDiv}></div> <div className="settingsV2IndexingPolicyEditor" ref={this.indexingPolicyDiv}></div>
</Stack> </Stack>
); );
} }

View File

@@ -13,7 +13,6 @@ exports[`IndexingPolicyComponent renders 1`] = `
/> />
<div <div
className="settingsV2IndexingPolicyEditor" className="settingsV2IndexingPolicyEditor"
tabIndex={0}
/> />
</Stack> </Stack>
`; `;

View File

@@ -118,10 +118,8 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
<input <input
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
aria-label="Autoscale mode" aria-label="Autoscale mode"
aria-required={true}
checked={isAutoscaleSelected} checked={isAutoscaleSelected}
type="radio" type="radio"
role="radio"
tabIndex={0} tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Autoscale")} onChange={(e) => handleOnChangeMode(e, "Autoscale")}
/> />
@@ -132,8 +130,6 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
aria-label="Manual mode" aria-label="Manual mode"
checked={!isAutoscaleSelected} checked={!isAutoscaleSelected}
type="radio" type="radio"
aria-required={true}
role="radio"
tabIndex={0} tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Manual")} onChange={(e) => handleOnChangeMode(e, "Manual")}
/> />

View File

@@ -654,12 +654,10 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
> >
<input <input
aria-label="Autoscale mode" aria-label="Autoscale mode"
aria-required={true}
checked={true} checked={true}
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
key=".0:$.0" key=".0:$.0"
onChange={[Function]} onChange={[Function]}
role="radio"
tabIndex={0} tabIndex={0}
type="radio" type="radio"
/> />
@@ -671,12 +669,10 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
</span> </span>
<input <input
aria-label="Manual mode" aria-label="Manual mode"
aria-required={true}
checked={false} checked={false}
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
key=".0:$.2" key=".0:$.2"
onChange={[Function]} onChange={[Function]}
role="radio"
tabIndex={0} tabIndex={0}
type="radio" type="radio"
/> />

View File

@@ -1,11 +1,9 @@
import { Link } from "@fluentui/react/lib/Link";
import * as ko from "knockout"; import * as ko from "knockout";
import React from "react"; import React from "react";
import _ from "underscore"; import _ from "underscore";
import { AuthType } from "../AuthType"; import { AuthType } from "../AuthType";
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer"; import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
import * as Constants from "../Common/Constants"; import * as Constants from "../Common/Constants";
import { ConnectionStatusType, HttpStatusCodes, Notebook } from "../Common/Constants";
import { readCollection } from "../Common/dataAccess/readCollection"; import { readCollection } from "../Common/dataAccess/readCollection";
import { readDatabases } from "../Common/dataAccess/readDatabases"; import { readDatabases } from "../Common/dataAccess/readDatabases";
import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility"; import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility";
@@ -13,7 +11,6 @@ import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHand
import * as Logger from "../Common/Logger"; import * as Logger from "../Common/Logger";
import { QueriesClient } from "../Common/QueriesClient"; import { QueriesClient } from "../Common/QueriesClient";
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import { ContainerConnectionInfo } from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels"; import * as ViewModels from "../Contracts/ViewModels";
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService"; import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
import { useSidePanel } from "../hooks/useSidePanel"; import { useSidePanel } from "../hooks/useSidePanel";
@@ -166,10 +163,23 @@ export default class Explorer {
useNotebook.subscribe( useNotebook.subscribe(
async () => { async () => {
this.initiateAndRefreshNotebookList(); if (!this.notebookManager) {
useNotebook.getState().setIsRefreshed(false); const NotebookManager = await (
await import(/* webpackChunkName: "NotebookManager" */ "./Notebook/NotebookManager")
).default;
this.notebookManager = new NotebookManager();
this.notebookManager.initialize({
container: this,
resourceTree: this.resourceTree,
refreshCommandBarButtons: () => this.refreshCommandBarButtons(),
refreshNotebookList: () => this.refreshNotebookList(),
});
}
this.refreshCommandBarButtons();
this.refreshNotebookList();
}, },
(state) => state.isNotebookEnabled || state.isRefreshed (state) => state.isNotebookEnabled
); );
this.resourceTree = new ResourceTreeAdapter(this); this.resourceTree = new ResourceTreeAdapter(this);
@@ -202,23 +212,6 @@ export default class Explorer {
this.refreshExplorer(); this.refreshExplorer();
} }
public async initiateAndRefreshNotebookList(): Promise<void> {
if (!this.notebookManager) {
const NotebookManager = (await import(/* webpackChunkName: "NotebookManager" */ "./Notebook/NotebookManager"))
.default;
this.notebookManager = new NotebookManager();
this.notebookManager.initialize({
container: this,
resourceTree: this.resourceTree,
refreshCommandBarButtons: () => this.refreshCommandBarButtons(),
refreshNotebookList: () => this.refreshNotebookList(),
});
}
this.refreshCommandBarButtons();
this.refreshNotebookList();
}
public openEnableSynapseLinkDialog(): void { public openEnableSynapseLinkDialog(): void {
const addSynapseLinkDialogProps: DialogProps = { const addSynapseLinkDialogProps: DialogProps = {
linkProps: { linkProps: {
@@ -352,7 +345,23 @@ export default class Explorer {
return; return;
} }
this._isInitializingNotebooks = true; this._isInitializingNotebooks = true;
if (userContext.features.phoenix === false) { if (userContext.features.phoenix) {
const provisionData = {
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
resourceId: userContext.databaseAccount.id,
dbAccountName: userContext.databaseAccount.name,
aadToken: userContext.authorizationToken,
resourceGroup: userContext.resourceGroup,
subscriptionId: userContext.subscriptionId,
};
const connectionInfo = await this.phoenixClient.containerConnectionInfo(provisionData);
if (connectionInfo.data && connectionInfo.data.notebookServerUrl) {
useNotebook.getState().setNotebookServerInfo({
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.data.notebookServerUrl,
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
});
}
} else {
await this.ensureNotebookWorkspaceRunning(); await this.ensureNotebookWorkspaceRunning();
const connectionInfo = await listConnectionInfo( const connectionInfo = await listConnectionInfo(
userContext.subscriptionId, userContext.subscriptionId,
@@ -367,59 +376,13 @@ export default class Explorer {
}); });
} }
useNotebook.getState().initializeNotebooksTree(this.notebookManager);
this.refreshNotebookList(); this.refreshNotebookList();
this._isInitializingNotebooks = false; this._isInitializingNotebooks = false;
} }
public async allocateContainer(): Promise<void> {
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
const isAllocating = useNotebook.getState().isAllocating;
if (isAllocating === false && notebookServerInfo && notebookServerInfo.notebookServerEndpoint === undefined) {
const provisionData = {
aadToken: userContext.authorizationToken,
subscriptionId: userContext.subscriptionId,
resourceGroup: userContext.resourceGroup,
dbAccountName: userContext.databaseAccount.name,
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
};
const connectionStatus: ContainerConnectionInfo = {
status: ConnectionStatusType.Connecting,
};
useNotebook.getState().setConnectionInfo(connectionStatus);
try {
useNotebook.getState().setIsAllocating(true);
const connectionInfo = await this.phoenixClient.containerConnectionInfo(provisionData);
if (
connectionInfo.status === HttpStatusCodes.OK &&
connectionInfo.data &&
connectionInfo.data.notebookServerUrl
) {
connectionStatus.status = ConnectionStatusType.Connected;
useNotebook.getState().setConnectionInfo(connectionStatus);
useNotebook.getState().setNotebookServerInfo({
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.data.notebookServerUrl,
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
});
this.notebookManager?.notebookClient
.getMemoryUsage()
.then((memoryUsageInfo) => useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo));
useNotebook.getState().setIsAllocating(false);
} else {
connectionStatus.status = ConnectionStatusType.Failed;
useNotebook.getState().resetConatinerConnection(connectionStatus);
}
} catch (error) {
connectionStatus.status = ConnectionStatusType.Failed;
useNotebook.getState().resetConatinerConnection(connectionStatus);
throw error;
}
this.refreshNotebookList();
this._isInitializingNotebooks = false;
}
}
public resetNotebookWorkspace(): void { public resetNotebookWorkspace(): void {
if (!useNotebook.getState().isNotebookEnabled || !this.notebookManager?.notebookClient) { if (!useNotebook.getState().isNotebookEnabled || !this.notebookManager?.notebookClient) {
handleError( handleError(
@@ -691,9 +654,6 @@ export default class Explorer {
if (!notebookContentItem || !notebookContentItem.path) { if (!notebookContentItem || !notebookContentItem.path) {
throw new Error(`Invalid notebookContentItem: ${notebookContentItem}`); throw new Error(`Invalid notebookContentItem: ${notebookContentItem}`);
} }
if (notebookContentItem.type === NotebookContentItemType.Notebook && NotebookUtil.isPhoenixEnabled()) {
this.allocateContainer();
}
const notebookTabs = useTabs const notebookTabs = useTabs
.getState() .getState()
@@ -915,51 +875,9 @@ export default class Explorer {
handleError(error, "Explorer/onNewNotebookClicked"); handleError(error, "Explorer/onNewNotebookClicked");
throw new Error(error); throw new Error(error);
} }
const isPhoenixEnabled = NotebookUtil.isPhoenixEnabled();
if (isPhoenixEnabled) {
if (isGithubTree) {
async () => {
await this.allocateContainer();
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.createNewNoteBook(parent, isGithubTree);
};
} else {
useDialog.getState().showOkCancelModalDialog(
Notebook.newNotebookModalTitle,
undefined,
"Create",
async () => {
await this.allocateContainer();
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.createNewNoteBook(parent, isGithubTree);
},
"Cancel",
undefined,
this.getNewNoteWarningText()
);
}
} else {
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.createNewNoteBook(parent, isGithubTree);
}
}
private getNewNoteWarningText(): JSX.Element { parent = parent || this.resourceTree.myNotebooksContentRoot;
return (
<>
<p>{Notebook.newNotebookModalContent1}</p>
<br />
<p>
{Notebook.newNotebookModalContent2}
<Link href={Notebook.cosmosNotebookHomePageUrl} target="_blank">
{Notebook.learnMore}
</Link>
</p>
</>
);
}
private createNewNoteBook(parent?: NotebookContentItem, isGithubTree?: boolean): void {
const clearInProgressMessage = logConsoleProgress(`Creating new notebook in ${parent.path}`); const clearInProgressMessage = logConsoleProgress(`Creating new notebook in ${parent.path}`);
const startKey: number = TelemetryProcessor.traceStart(Action.CreateNewNotebook, { const startKey: number = TelemetryProcessor.traceStart(Action.CreateNewNotebook, {
dataExplorerArea: Constants.Areas.Notebook, dataExplorerArea: Constants.Areas.Notebook,
@@ -1006,26 +924,7 @@ export default class Explorer {
await this.notebookManager?.notebookContentClient.updateItemChildrenInPlace(item); await this.notebookManager?.notebookContentClient.updateItemChildrenInPlace(item);
} }
public async openNotebookTerminal(kind: ViewModels.TerminalKind): Promise<void> { public openNotebookTerminal(kind: ViewModels.TerminalKind): void {
if (NotebookUtil.isPhoenixEnabled()) {
await this.allocateContainer();
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
if (notebookServerInfo && notebookServerInfo.notebookServerEndpoint !== undefined) {
this.connectToNotebookTerminal(kind);
} else {
useDialog
.getState()
.showOkModalDialog(
"Failed to Connect",
"Failed to connect temporary workspace, this could happen because of network issue please refresh and try again."
);
}
} else {
this.connectToNotebookTerminal(kind);
}
}
private connectToNotebookTerminal(kind: ViewModels.TerminalKind): void {
let title: string; let title: string;
switch (kind) { switch (kind) {
@@ -1076,7 +975,7 @@ export default class Explorer {
notebookUrl?: string, notebookUrl?: string,
galleryItem?: IGalleryItem, galleryItem?: IGalleryItem,
isFavorite?: boolean isFavorite?: boolean
): Promise<void> { ) {
const title = "Gallery"; const title = "Gallery";
const GalleryTab = await (await import(/* webpackChunkName: "GalleryTab" */ "./Tabs/GalleryTab")).default; const GalleryTab = await (await import(/* webpackChunkName: "GalleryTab" */ "./Tabs/GalleryTab")).default;
const galleryTab = useTabs const galleryTab = useTabs
@@ -1180,27 +1079,7 @@ export default class Explorer {
} }
public openUploadFilePanel(parent?: NotebookContentItem): void { public openUploadFilePanel(parent?: NotebookContentItem): void {
if (NotebookUtil.isPhoenixEnabled()) {
useDialog.getState().showOkCancelModalDialog(
Notebook.newNotebookUploadModalTitle,
undefined,
"Upload",
async () => {
await this.allocateContainer();
parent = parent || this.resourceTree.myNotebooksContentRoot; parent = parent || this.resourceTree.myNotebooksContentRoot;
this.uploadFilePanel(parent);
},
"Cancel",
undefined,
this.getNewNoteWarningText()
);
} else {
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.uploadFilePanel(parent);
}
}
private uploadFilePanel(parent?: NotebookContentItem): void {
useSidePanel useSidePanel
.getState() .getState()
.openSidePanel( .openSidePanel(
@@ -1209,24 +1088,6 @@ export default class Explorer {
); );
} }
public getDownloadModalConent(fileName: string): JSX.Element {
if (NotebookUtil.isPhoenixEnabled()) {
return (
<>
<p>{Notebook.galleryNotebookDownloadContent1}</p>
<br />
<p>
{Notebook.galleryNotebookDownloadContent2}
<Link href={Notebook.cosmosNotebookGitDocumentationUrl} target="_blank">
{Notebook.learnMore}
</Link>
</p>
</>
);
}
return <p> Download {fileName} from gallery as a copy to your notebooks to run and/or edit the notebook. </p>;
}
public async refreshExplorer(): Promise<void> { public async refreshExplorer(): Promise<void> {
userContext.authType === AuthType.ResourceToken userContext.authType === AuthType.ResourceToken
? this.refreshDatabaseForResourceToken() ? this.refreshDatabaseForResourceToken()

View File

@@ -214,8 +214,14 @@ export class EditorNeighborsComponent extends React.Component<EditorNeighborsCom
/> />
</td> </td>
<td className="actionCol"> <td className="actionCol">
<span className="rightPaneTrashIcon rightPaneBtns"> <span
<img src={DeleteIcon} alt="Delete" onClick={() => this.removeAddedEdgeToNeighbor(index)} /> className="rightPaneTrashIcon rightPaneBtns"
role="button"
onKeyPress={() => this.removeAddedEdgeToNeighbor(index)}
onClick={() => this.removeAddedEdgeToNeighbor(index)}
tabIndex={0}
>
<img src={DeleteIcon} alt="Delete" />
</span> </span>
</td> </td>
</tr> </tr>

View File

@@ -123,7 +123,7 @@ export class EditorNodePropertiesComponent extends React.Component<EditorNodePro
<select <select
className="typeSelect" className="typeSelect"
value={singleValue.type} value={singleValue.type}
onChange={(e) => { onBlur={(e) => {
singleValue.type = e.target.value as ViewModels.InputPropertyValueTypeString; singleValue.type = e.target.value as ViewModels.InputPropertyValueTypeString;
if (singleValue.type === "null") { if (singleValue.type === "null") {
singleValue.value = undefined; singleValue.value = undefined;
@@ -217,7 +217,7 @@ export class EditorNodePropertiesComponent extends React.Component<EditorNodePro
<select <select
className="typeSelect" className="typeSelect"
value={firstValue.type} value={firstValue.type}
onChange={(e) => { onBlur={(e) => {
firstValue.type = e.target.value as ViewModels.InputPropertyValueTypeString; firstValue.type = e.target.value as ViewModels.InputPropertyValueTypeString;
this.props.onUpdateProperties(this.props.editedProperties); this.props.onUpdateProperties(this.props.editedProperties);
}} }}

View File

@@ -93,7 +93,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
<td> <td>
<select <select
className="typeSelect" className="typeSelect"
onChange={[Function]} onBlur={[Function]}
required={true} required={true}
value="string" value="string"
> >
@@ -282,7 +282,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
<td> <td>
<select <select
className="typeSelect" className="typeSelect"
onChange={[Function]} onBlur={[Function]}
required={true} required={true}
value="string" value="string"
> >
@@ -344,7 +344,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
<td> <td>
<select <select
className="typeSelect" className="typeSelect"
onChange={[Function]} onBlur={[Function]}
required={true} required={true}
value="string" value="string"
> >

View File

@@ -132,7 +132,6 @@ export const NewVertexComponent: FunctionComponent<INewVertexComponentProps> = (
onChange={(event: React.ChangeEvent<HTMLInputElement>) => { onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
onLabelChange(event); onLabelChange(event);
}} }}
autoFocus
/> />
<div className="actionCol"></div> <div className="actionCol"></div>
</div> </div>

View File

@@ -12,7 +12,6 @@ import { useTabs } from "../../../hooks/useTabs";
import { userContext } from "../../../UserContext"; import { userContext } from "../../../UserContext";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer"; import Explorer from "../../Explorer";
import { NotebookUtil } from "../../Notebook/NotebookUtil";
import { useSelectedNode } from "../../useSelectedNode"; import { useSelectedNode } from "../../useSelectedNode";
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory"; import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
import * as CommandBarUtil from "./CommandBarUtil"; import * as CommandBarUtil from "./CommandBarUtil";
@@ -56,15 +55,15 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor); const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true)); uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
if (NotebookUtil.isPhoenixEnabled()) {
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus(container, "connectionStatus"));
}
if ( if (
userContext.features.phoenix === false &&
userContext.features.notebooksTemporarilyDown === false && userContext.features.notebooksTemporarilyDown === false &&
userContext.features.phoenix === true &&
useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2 useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2
) { ) {
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus("connectionStatus"));
}
if (useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2) {
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker")); uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
} }

View File

@@ -596,7 +596,7 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
return { return {
iconSrc: GitHubIcon, iconSrc: GitHubIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => { onCommandClick: () =>
useSidePanel useSidePanel
.getState() .getState()
.openSidePanel( .openSidePanel(
@@ -606,8 +606,7 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
gitHubClientProp={container.notebookManager.gitHubClient} gitHubClientProp={container.notebookManager.gitHubClient}
junoClientProp={junoClient} junoClientProp={junoClient}
/> />
); ),
},
commandButtonLabel: label, commandButtonLabel: label,
hasPopup: false, hasPopup: false,
disabled: false, disabled: false,

View File

@@ -13,7 +13,6 @@ import { StyleConstants } from "../../../Common/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor"; import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer";
import { ConnectionStatus } from "./ConnectionStatusComponent"; import { ConnectionStatus } from "./ConnectionStatusComponent";
import { MemoryTracker } from "./MemoryTrackerComponent"; import { MemoryTracker } from "./MemoryTrackerComponent";
@@ -204,9 +203,9 @@ export const createMemoryTracker = (key: string): ICommandBarItemProps => {
}; };
}; };
export const createConnectionStatus = (container: Explorer, key: string): ICommandBarItemProps => { export const createConnectionStatus = (key: string): ICommandBarItemProps => {
return { return {
key, key,
onRender: () => <ConnectionStatus container={container} />, onRender: () => <ConnectionStatus />,
}; };
}; };

View File

@@ -3,182 +3,77 @@
.connectionStatusContainer { .connectionStatusContainer {
cursor: default; cursor: default;
align-items: center; align-items: center;
margin: 0 9px;
border: 1px; border: 1px;
min-height: 44px; min-height: 44px;
> span { > span {
padding-right: 12px; padding-right: 12px;
font-size: 12px; font-size: 13px;
font-family: @DataExplorerFont; font-family: @DataExplorerFont;
color: @DefaultFontColor; color: @DefaultFontColor;
} }
&:focus{
outline: 0px;
} }
.connectionStatusFailed{
color: #bd1919;
} }
.commandReactBtn { .ring-container {
&:hover { position: relative;
background-color: rgb(238, 247, 255);
color: rgb(32, 31, 30);
cursor: pointer;
} }
&:focus{
outline: 1px dashed #605e5c; .ringringGreen {
} border: 3px solid green;
} border-radius: 30px;
.connectedReactBtn {
&:hover {
background-color: rgb(238, 247, 255);
color: rgb(32, 31, 30);
cursor: pointer;
}
&:focus{
outline: 0px;
}
}
.connectIcon{
margin: 0px 4px;
height: 18px; height: 18px;
width: 18px; width: 18px;
color: rgb(0, 120, 212);
}
.status {
position: relative;
display: block;
margin-right: 8px;
width: 1em;
height: 1em;
font-size: 9px!important;
padding: 0px!important;
border-radius: 0.5em;
}
.status::before,
.status::after {
position: absolute; position: absolute;
content: ""; margin: .4285em 0em 0em 0.07477em;
animation: pulsate 3s ease-out;
animation-iteration-count: infinite;
opacity: 0.0
} }
.ringringYellow{
.status::before { border: 3px solid #ffbf00;
top: 0; border-radius: 30px;
left: 0; height: 18px;
width: 1em; width: 18px;
height: 1em; position: absolute;
background-color: rgba(#fff, 0.1); margin: .4285em 0em 0em 0.07477em;
border-radius: 100%; animation: pulsate 3s ease-out;
opacity: 1; animation-iteration-count: infinite;
transform: translate3d(0, 0, 0) scale(0); opacity: 0.0
} }
.ringringRed{
.connected{ border: 3px solid #bd1919;
background-color: green; border-radius: 30px;
box-shadow: height: 18px;
0 0 0 0em rgba(green, 0), width: 18px;
0em 0.05em 0.1em rgba(#000000, 0.2); position: absolute;
transform: translate3d(0, 0, 0) scale(1); margin: .4285em 0em 0em 0.07477em;
animation: pulsate 3s ease-out;
animation-iteration-count: infinite;
opacity: 0.0
} }
.connecting{ @keyframes pulsate {
background-color:#ffbf00; 0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
box-shadow: 15% {opacity: 0.8;}
0 0 0 0em rgba(#ffbf00, 0), 25% {opacity: 0.6;}
0em 0.05em 0.1em rgba(#000000, 0.2); 45% {opacity: 0.4;}
transform: translate3d(0, 0, 0) scale(1); 70% {opacity: 0.3;}
100% {-webkit-transform: scale(.7, .7); opacity: 0.1;}
} }
.failed{ .locationGreenDot{
background-color:#bd1919; font-size: 20px;
box-shadow: margin-right: 0.07em;
0 0 0 0em rgba(#bd1919, 0), color: green;
0em 0.05em 0.1em rgba(#000000, 0.2);
transform: translate3d(0, 0, 0) scale(1);
} }
.locationYellowDot{
.status.connecting.is-animating { font-size: 20px;
animation: status-outer-connecting 3000ms infinite; margin-right: 0.07em;
} color: #ffbf00;
.status.failed.is-animating {
animation: status-outer-failed 3000ms infinite;
}
.status.connected.is-animating {
animation: status-outer-connected 3000ms infinite;
}
@keyframes status-outer-connected {
0% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em #008000, 0em 0.05em 0.1em rgba(0, 0, 0, 0.2);
}
20% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.6), 0em 0.05em 0.1em rgba(0, 0, 0, 0.5);
}
40% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.5), 0em 0.05em 0.1em rgba(0, 0, 0, 0.4);
}
60% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.3), 0em 0.05em 0.1em rgba(0, 0, 0, 0.3);
}
80% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0.5em rgba(0, 128, 0, 0.1), 0em 0.05em 0.1em rgba(0, 0, 0, 0.1);
}
85% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0), 0em 0.05em 0.1em rgba(0, 0, 0, 0);
}
}
@keyframes status-outer-failed {
0% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em #bd1919, 0em 0.05em 0.1em rgba(0, 0, 0, 0.2);
}
20% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em #c52d2d, 0em 0.05em 0.1em rgba(0, 0, 0, 0.5);
}
40% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em #b47b7b, 0em 0.05em 0.1em rgba(0, 0, 0, 0.4);
}
60% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.3), 0em 0.05em 0.1em rgba(0, 0, 0, 0.3);
}
80% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0.5em rgba(0, 128, 0, 0.1), 0em 0.05em 0.1em rgba(0, 0, 0, 0.1);
}
85% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0), 0em 0.05em 0.1em rgba(0, 0, 0, 0);
}
}
@keyframes status-outer-connecting {
0% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em #ffbf00, 0em 0.05em 0.1em rgba(0, 0, 0, 0.2);
}
20% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em #f0dfad, 0em 0.05em 0.1em rgba(0, 0, 0, 0.5);
}
40% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(198, 243, 198, 0.5), 0em 0.05em 0.1em rgba(0, 0, 0, 0.4);
}
60% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(213, 241, 213, 0.3), 0em 0.05em 0.1em rgba(0, 0, 0, 0.3);
}
80% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0.5em rgba(0, 128, 0, 0.1), 0em 0.05em 0.1em rgba(0, 0, 0, 0.1);
}
85% {
transform: translate3d(0, 0, 0) scale(1);
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0), 0em 0.05em 0.1em rgba(0, 0, 0, 0);
} }
.locationRedDot{
font-size: 20px;
margin-right: 0.07em;
color: #bd1919;
} }

View File

@@ -1,21 +1,17 @@
import { Icon, ProgressIndicator, Stack, TooltipHost } from "@fluentui/react"; import { Icon, ProgressIndicator, Stack, TooltipHost } from "@fluentui/react";
import { ActionButton } from "@fluentui/react/lib/Button";
import * as React from "react"; import * as React from "react";
import "../../../../less/hostedexplorer.less"; import { ConnectionStatusType } from "../../../Common/Constants";
import { ConnectionStatusType, Notebook } from "../../../Common/Constants";
import Explorer from "../../Explorer";
import { useNotebook } from "../../Notebook/useNotebook"; import { useNotebook } from "../../Notebook/useNotebook";
import "../CommandBar/ConnectionStatusComponent.less"; import "../CommandBar/ConnectionStatusComponent.less";
interface Props {
container: Explorer; export const ConnectionStatus: React.FC = (): JSX.Element => {
}
export const ConnectionStatus: React.FC<Props> = ({ container }: Props): JSX.Element => {
const [second, setSecond] = React.useState("00"); const [second, setSecond] = React.useState("00");
const [minute, setMinute] = React.useState("00"); const [minute, setMinute] = React.useState("00");
const [isActive, setIsActive] = React.useState(false); const [isActive, setIsActive] = React.useState(false);
const [counter, setCounter] = React.useState(0); const [counter, setCounter] = React.useState(0);
const [statusColor, setStatusColor] = React.useState(""); const [statusColor, setStatusColor] = React.useState("locationYellowDot");
const [toolTipContent, setToolTipContent] = React.useState("Connect to temporary workspace."); const [statusColorAnimation, setStatusColorAnimation] = React.useState("ringringYellow");
const toolTipContent = "Hosted runtime status.";
React.useEffect(() => { React.useEffect(() => {
let intervalId: NodeJS.Timeout; let intervalId: NodeJS.Timeout;
@@ -43,65 +39,34 @@ export const ConnectionStatus: React.FC<Props> = ({ container }: Props): JSX.Ele
}; };
const connectionInfo = useNotebook((state) => state.connectionInfo); const connectionInfo = useNotebook((state) => state.connectionInfo);
const memoryUsageInfo = useNotebook((state) => state.memoryUsageInfo); if (!connectionInfo) {
return <></>;
const totalGB = memoryUsageInfo ? memoryUsageInfo.totalKB / Notebook.memoryGuageToGB : 0;
const usedGB = totalGB > 0 ? totalGB - memoryUsageInfo.freeKB / Notebook.memoryGuageToGB : 0;
if (
connectionInfo &&
(connectionInfo.status === ConnectionStatusType.Connect || connectionInfo.status === ConnectionStatusType.ReConnect)
) {
return (
<ActionButton className="commandReactBtn" onClick={() => container.allocateContainer()}>
<TooltipHost content={toolTipContent}>
<Stack className="connectionStatusContainer" horizontal>
<Icon iconName="ConnectVirtualMachine" className="connectIcon" />
<span>{connectionInfo.status}</span>
</Stack>
</TooltipHost>
</ActionButton>
);
} }
if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connecting && isActive === false) { if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connecting && isActive === false) {
setIsActive(true); setIsActive(true);
setStatusColor("status connecting is-animating");
setToolTipContent("Connecting to temporary workspace.");
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connected && isActive === true) { } else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connected && isActive === true) {
stopTimer(); stopTimer();
setStatusColor("status connected is-animating"); setStatusColor("locationGreenDot");
setToolTipContent("Connected to temporary workspace."); setStatusColorAnimation("ringringGreen");
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Failed && isActive === true) { } else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Failed && isActive === true) {
stopTimer(); stopTimer();
setStatusColor("status failed is-animating"); setStatusColor("locationRedDot");
setToolTipContent("Click here to Reconnect to temporary workspace."); setStatusColorAnimation("ringringRed");
} }
return ( return (
<ActionButton
className={connectionInfo.status === ConnectionStatusType.Failed ? "commandReactBtn" : "connectedReactBtn"}
onClick={(e: React.MouseEvent<HTMLSpanElement>) =>
connectionInfo.status === ConnectionStatusType.Failed ? container.allocateContainer() : e.preventDefault()
}
>
<TooltipHost content={toolTipContent}> <TooltipHost content={toolTipContent}>
<Stack className="connectionStatusContainer" horizontal> <Stack className="connectionStatusContainer" horizontal>
<i className={statusColor}></i> <div className="ring-container">
<div className={statusColorAnimation}></div>
<Icon iconName="LocationDot" className={statusColor} />
</div>
<span className={connectionInfo.status === ConnectionStatusType.Failed ? "connectionStatusFailed" : ""}> <span className={connectionInfo.status === ConnectionStatusType.Failed ? "connectionStatusFailed" : ""}>
{connectionInfo.status} {connectionInfo.status}
</span> </span>
{connectionInfo.status === ConnectionStatusType.Connecting && isActive && ( {connectionInfo.status === ConnectionStatusType.Connecting && isActive && (
<ProgressIndicator description={minute + ":" + second} /> <ProgressIndicator description={minute + ":" + second} />
)} )}
{connectionInfo.status === ConnectionStatusType.Connected && !isActive && (
<ProgressIndicator
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
percentComplete={usedGB / totalGB}
/>
)}
</Stack> </Stack>
</TooltipHost> </TooltipHost>
</ActionButton>
); );
}; };

View File

@@ -103,6 +103,7 @@ export class NotificationConsoleComponent extends React.Component<
onClick={() => this.expandCollapseConsole()} onClick={() => this.expandCollapseConsole()}
onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => this.onExpandCollapseKeyPress(event)} onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => this.onExpandCollapseKeyPress(event)}
tabIndex={0} tabIndex={0}
role="button"
> >
<div className="statusBar"> <div className="statusBar">
<span className="dataTypeIcons"> <span className="dataTypeIcons">
@@ -162,7 +163,7 @@ export class NotificationConsoleComponent extends React.Component<
onKeyDown={(event: React.KeyboardEvent<HTMLSpanElement>) => this.onClearNotificationsKeyPress(event)} onKeyDown={(event: React.KeyboardEvent<HTMLSpanElement>) => this.onClearNotificationsKeyPress(event)}
tabIndex={0} tabIndex={0}
> >
<img src={ClearIcon} alt="clear notifications image" /> <img src={ClearIcon} alt="clear notifications icon" />
Clear Notifications Clear Notifications
</span> </span>
</div> </div>

View File

@@ -9,6 +9,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
id="notificationConsoleHeader" id="notificationConsoleHeader"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}
role="button"
tabIndex={0} tabIndex={0}
> >
<div <div
@@ -150,7 +151,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
tabIndex={0} tabIndex={0}
> >
<img <img
alt="clear notifications image" alt="clear notifications icon"
src="" src=""
/> />
Clear Notifications Clear Notifications
@@ -173,6 +174,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
id="notificationConsoleHeader" id="notificationConsoleHeader"
onClick={[Function]} onClick={[Function]}
onKeyDown={[Function]} onKeyDown={[Function]}
role="button"
tabIndex={0} tabIndex={0}
> >
<div <div
@@ -316,7 +318,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
tabIndex={0} tabIndex={0}
> >
<img <img
alt="clear notifications image" alt="clear notifications icon"
src="" src=""
/> />
Clear Notifications Clear Notifications

View File

@@ -2,15 +2,12 @@
* Notebook container related stuff * Notebook container related stuff
*/ */
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import { ConnectionStatusType } from "../../Common/Constants";
import { getErrorMessage } from "../../Common/ErrorHandlingUtils"; import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import { ContainerConnectionInfo } from "../../Contracts/DataModels";
import { userContext } from "../../UserContext"; import { userContext } from "../../UserContext";
import { createOrUpdate, destroy } from "../../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces"; import { createOrUpdate, destroy } from "../../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces";
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils"; import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
import { NotebookUtil } from "./NotebookUtil";
import { useNotebook } from "./useNotebook"; import { useNotebook } from "./useNotebook";
export class NotebookContainerClient { export class NotebookContainerClient {
@@ -45,7 +42,7 @@ export class NotebookContainerClient {
}, delayMs); }, delayMs);
} }
public async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> { private async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
const notebookServerInfo = useNotebook.getState().notebookServerInfo; const notebookServerInfo = useNotebook.getState().notebookServerInfo;
if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) { if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) {
const error = "No server endpoint detected"; const error = "No server endpoint detected";
@@ -78,12 +75,6 @@ export class NotebookContainerClient {
freeKB: memoryUsageInfo.free, freeKB: memoryUsageInfo.free,
}; };
} }
} else if (NotebookUtil.isPhoenixEnabled()) {
const connectionStatus: ContainerConnectionInfo = {
status: ConnectionStatusType.ReConnect,
};
useNotebook.getState().resetConatinerConnection(connectionStatus);
useNotebook.getState().setIsRefreshed(true);
} }
return undefined; return undefined;
} catch (error) { } catch (error) {
@@ -93,13 +84,6 @@ export class NotebookContainerClient {
"Connection lost with Notebook server. Attempting to reconnect..." "Connection lost with Notebook server. Attempting to reconnect..."
); );
} }
if (NotebookUtil.isPhoenixEnabled()) {
const connectionStatus: ContainerConnectionInfo = {
status: ConnectionStatusType.Failed,
};
useNotebook.getState().resetConatinerConnection(connectionStatus);
useNotebook.getState().setIsRefreshed(true);
}
this.onConnectionLost(); this.onConnectionLost();
return undefined; return undefined;
} }

View File

@@ -212,7 +212,6 @@ export default class NotebookManager {
"Cancel", "Cancel",
() => reject(new Error("Commit dialog canceled")), () => reject(new Error("Commit dialog canceled")),
undefined, undefined,
undefined,
{ {
label: "Commit message", label: "Commit message",
autoAdjustHeight: true, autoAdjustHeight: true,

View File

@@ -31,13 +31,12 @@ import StatusBar from "./StatusBar";
import CellToolbar from "./Toolbar"; import CellToolbar from "./Toolbar";
export interface NotebookRendererBaseProps { export interface NotebookRendererBaseProps {
contentRef: ContentRef; contentRef: any;
} }
interface NotebookRendererDispatchProps { interface NotebookRendererDispatchProps {
storeNotebookSnapshot: (imageSrc: string, requestId: string) => void; storeNotebookSnapshot: (imageSrc: string, requestId: string) => void;
notebookSnapshotError: (error: string) => void; notebookSnapshotError: (error: string) => void;
addTransform: (transform: React.ComponentType & { MIMETYPE: string }) => void;
} }
interface StateProps { interface StateProps {
@@ -74,7 +73,7 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
componentDidMount() { componentDidMount() {
if (!userContext.features.sandboxNotebookOutputs) { if (!userContext.features.sandboxNotebookOutputs) {
loadTransform(this.props as NotebookRendererProps); loadTransform(this.props as any);
} }
} }
@@ -139,7 +138,7 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
}} }}
</CodeCell> </CodeCell>
), ),
markdown: ({ id, contentRef }: { id: CellId; contentRef: ContentRef }) => markdown: ({ id, contentRef }: { id: any; contentRef: ContentRef }) =>
decorate( decorate(
id, id,
contentRef, contentRef,
@@ -156,7 +155,7 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
</MarkdownCell> </MarkdownCell>
), ),
raw: ({ id, contentRef }: { id: CellId; contentRef: ContentRef }) => raw: ({ id, contentRef }: { id: any; contentRef: ContentRef }) =>
decorate( decorate(
id, id,
contentRef, contentRef,
@@ -203,8 +202,7 @@ export const makeMapStateToProps = (
return mapStateToProps; return mapStateToProps;
}; };
// eslint-disable-next-line @typescript-eslint/no-unused-vars const makeMapDispatchToProps = (initialDispatch: Dispatch, initialProps: NotebookRendererBaseProps) => {
const makeMapDispatchToProps = (_initialDispatch: Dispatch, _initialProps: NotebookRendererBaseProps) => {
const mapDispatchToProps = (dispatch: Dispatch) => { const mapDispatchToProps = (dispatch: Dispatch) => {
return { return {
addTransform: (transform: React.ComponentType & { MIMETYPE: string }) => addTransform: (transform: React.ComponentType & { MIMETYPE: string }) =>

View File

@@ -3,7 +3,6 @@ import { AppState, selectors } from "@nteract/core";
import domtoimage from "dom-to-image"; import domtoimage from "dom-to-image";
import Html2Canvas from "html2canvas"; import Html2Canvas from "html2canvas";
import path from "path"; import path from "path";
import { userContext } from "../../UserContext";
import * as GitHubUtils from "../../Utils/GitHubUtils"; import * as GitHubUtils from "../../Utils/GitHubUtils";
import * as StringUtils from "../../Utils/StringUtils"; import * as StringUtils from "../../Utils/StringUtils";
import { SnapshotFragment } from "./NotebookComponent/types"; import { SnapshotFragment } from "./NotebookComponent/types";
@@ -329,16 +328,4 @@ export class NotebookUtil {
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
} }
public static getNotebookBtnTitle(fileName: string): string {
if (this.isPhoenixEnabled()) {
return `Download to ${fileName}`;
} else {
return `Download to my notebooks`;
}
}
public static isPhoenixEnabled(): boolean {
return userContext.features.notebooksTemporarilyDown === false && userContext.features.phoenix === true;
}
} }

View File

@@ -2,12 +2,10 @@ import { cloneDeep } from "lodash";
import create, { UseStore } from "zustand"; import create, { UseStore } from "zustand";
import { AuthType } from "../../AuthType"; import { AuthType } from "../../AuthType";
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import { ConnectionStatusType } from "../../Common/Constants";
import { getErrorMessage } from "../../Common/ErrorHandlingUtils"; import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
import { configContext } from "../../ConfigContext"; import { configContext } from "../../ConfigContext";
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import { ContainerConnectionInfo } from "../../Contracts/DataModels";
import { IPinnedRepo } from "../../Juno/JunoClient"; import { IPinnedRepo } from "../../Juno/JunoClient";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
@@ -16,7 +14,6 @@ import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
import * as GitHubUtils from "../../Utils/GitHubUtils"; import * as GitHubUtils from "../../Utils/GitHubUtils";
import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem"; import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem";
import NotebookManager from "./NotebookManager"; import NotebookManager from "./NotebookManager";
import { NotebookUtil } from "./NotebookUtil";
interface NotebookState { interface NotebookState {
isNotebookEnabled: boolean; isNotebookEnabled: boolean;
@@ -31,10 +28,8 @@ interface NotebookState {
myNotebooksContentRoot: NotebookContentItem; myNotebooksContentRoot: NotebookContentItem;
gitHubNotebooksContentRoot: NotebookContentItem; gitHubNotebooksContentRoot: NotebookContentItem;
galleryContentRoot: NotebookContentItem; galleryContentRoot: NotebookContentItem;
connectionInfo: ContainerConnectionInfo; connectionInfo: DataModels.ContainerConnectionInfo;
notebookFolderName: string; notebookFolderName: string;
isAllocating: boolean;
isRefreshed: boolean;
setIsNotebookEnabled: (isNotebookEnabled: boolean) => void; setIsNotebookEnabled: (isNotebookEnabled: boolean) => void;
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => void; setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => void;
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => void; setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => void;
@@ -51,10 +46,7 @@ interface NotebookState {
deleteNotebookItem: (item: NotebookContentItem, isGithubTree?: boolean) => void; deleteNotebookItem: (item: NotebookContentItem, isGithubTree?: boolean) => void;
initializeNotebooksTree: (notebookManager: NotebookManager) => Promise<void>; initializeNotebooksTree: (notebookManager: NotebookManager) => Promise<void>;
initializeGitHubRepos: (pinnedRepos: IPinnedRepo[]) => void; initializeGitHubRepos: (pinnedRepos: IPinnedRepo[]) => void;
setConnectionInfo: (connectionInfo: ContainerConnectionInfo) => void; setConnectionInfo: (connectionInfo: DataModels.ContainerConnectionInfo) => void;
setIsAllocating: (isAllocating: boolean) => void;
resetConatinerConnection: (connectionStatus: ContainerConnectionInfo) => void;
setIsRefreshed: (isAllocating: boolean) => void;
} }
export const useNotebook: UseStore<NotebookState> = create((set, get) => ({ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
@@ -77,12 +69,8 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
myNotebooksContentRoot: undefined, myNotebooksContentRoot: undefined,
gitHubNotebooksContentRoot: undefined, gitHubNotebooksContentRoot: undefined,
galleryContentRoot: undefined, galleryContentRoot: undefined,
connectionInfo: { connectionInfo: undefined,
status: ConnectionStatusType.Connect,
},
notebookFolderName: undefined, notebookFolderName: undefined,
isAllocating: false,
isRefreshed: false,
setIsNotebookEnabled: (isNotebookEnabled: boolean) => set({ isNotebookEnabled }), setIsNotebookEnabled: (isNotebookEnabled: boolean) => set({ isNotebookEnabled }),
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => set({ isNotebooksEnabledForAccount }), setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => set({ isNotebooksEnabledForAccount }),
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) =>
@@ -187,7 +175,7 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
isGithubTree ? set({ gitHubNotebooksContentRoot: root }) : set({ myNotebooksContentRoot: root }); isGithubTree ? set({ gitHubNotebooksContentRoot: root }) : set({ myNotebooksContentRoot: root });
}, },
initializeNotebooksTree: async (notebookManager: NotebookManager): Promise<void> => { initializeNotebooksTree: async (notebookManager: NotebookManager): Promise<void> => {
const notebookFolderName = NotebookUtil.isPhoenixEnabled() === true ? "Temporary Notebooks" : "My Notebooks"; const notebookFolderName = userContext.features.phoenix === true ? "Temporary Notebooks" : "My Notebooks";
set({ notebookFolderName }); set({ notebookFolderName });
const myNotebooksContentRoot = { const myNotebooksContentRoot = {
name: get().notebookFolderName, name: get().notebookFolderName,
@@ -268,15 +256,5 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
set({ gitHubNotebooksContentRoot }); set({ gitHubNotebooksContentRoot });
} }
}, },
setConnectionInfo: (connectionInfo: ContainerConnectionInfo) => set({ connectionInfo }), setConnectionInfo: (connectionInfo: DataModels.ContainerConnectionInfo) => set({ connectionInfo }),
setIsAllocating: (isAllocating: boolean) => set({ isAllocating }),
resetConatinerConnection: (connectionStatus: ContainerConnectionInfo): void => {
useNotebook.getState().setConnectionInfo(connectionStatus);
useNotebook.getState().setNotebookServerInfo({
notebookServerEndpoint: undefined,
authToken: undefined,
});
useNotebook.getState().setIsAllocating(false);
},
setIsRefreshed: (isRefreshed: boolean) => set({ isRefreshed }),
})); }));

View File

@@ -173,7 +173,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-checked={this.state.createNewDatabase} aria-checked={this.state.createNewDatabase}
name="databaseType" name="databaseType"
type="radio" type="radio"
role="radio"
id="databaseCreateNew" id="databaseCreateNew"
tabIndex={0} tabIndex={0}
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)} onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
@@ -187,7 +186,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-checked={!this.state.createNewDatabase} aria-checked={!this.state.createNewDatabase}
name="databaseType" name="databaseType"
type="radio" type="radio"
role="radio"
tabIndex={0} tabIndex={0}
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)} onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
/> />
@@ -209,7 +207,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
size={40} size={40}
className="panelTextField" className="panelTextField"
aria-label="New database id" aria-label="New database id"
autoFocus
tabIndex={0} tabIndex={0}
value={this.state.newDatabaseId} value={this.state.newDatabaseId}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
@@ -320,7 +317,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-label="Turn on indexing" aria-label="Turn on indexing"
aria-checked={this.state.enableIndexing} aria-checked={this.state.enableIndexing}
type="radio" type="radio"
role="radio"
tabIndex={0} tabIndex={0}
onChange={this.onTurnOnIndexing.bind(this)} onChange={this.onTurnOnIndexing.bind(this)}
/> />
@@ -332,7 +328,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-label="Turn off indexing" aria-label="Turn off indexing"
aria-checked={!this.state.enableIndexing} aria-checked={!this.state.enableIndexing}
type="radio" type="radio"
role="radio"
tabIndex={0} tabIndex={0}
onChange={this.onTurnOffIndexing.bind(this)} onChange={this.onTurnOffIndexing.bind(this)}
/> />
@@ -375,7 +370,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-checked={!this.state.isSharded} aria-checked={!this.state.isSharded}
name="unsharded" name="unsharded"
type="radio" type="radio"
role="radio"
id="unshardedOption" id="unshardedOption"
tabIndex={0} tabIndex={0}
onChange={this.onUnshardedRadioBtnChange.bind(this)} onChange={this.onUnshardedRadioBtnChange.bind(this)}
@@ -389,7 +383,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-checked={this.state.isSharded} aria-checked={this.state.isSharded}
name="sharded" name="sharded"
type="radio" type="radio"
role="radio"
id="shardedOption" id="shardedOption"
tabIndex={0} tabIndex={0}
onChange={this.onShardedRadioBtnChange.bind(this)} onChange={this.onShardedRadioBtnChange.bind(this)}
@@ -515,7 +508,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
: "Comma separated paths e.g. /firstName,/address/zipCode" : "Comma separated paths e.g. /firstName,/address/zipCode"
} }
className="panelTextField" className="panelTextField"
autoFocus
value={uniqueKey} value={uniqueKey}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => { onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => { const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => {
@@ -574,7 +566,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-checked={this.state.enableAnalyticalStore} aria-checked={this.state.enableAnalyticalStore}
name="analyticalStore" name="analyticalStore"
type="radio" type="radio"
role="radio"
id="enableAnalyticalStoreBtn" id="enableAnalyticalStoreBtn"
tabIndex={0} tabIndex={0}
onChange={this.onEnableAnalyticalStoreRadioBtnChange.bind(this)} onChange={this.onEnableAnalyticalStoreRadioBtnChange.bind(this)}
@@ -589,7 +580,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
aria-checked={!this.state.enableAnalyticalStore} aria-checked={!this.state.enableAnalyticalStore}
name="analyticalStore" name="analyticalStore"
type="radio" type="radio"
role="radio"
id="disableAnalyticalStoreBtn" id="disableAnalyticalStoreBtn"
tabIndex={0} tabIndex={0}
onChange={this.onDisableAnalyticalStoreRadioBtnChange.bind(this)} onChange={this.onDisableAnalyticalStoreRadioBtnChange.bind(this)}

View File

@@ -210,7 +210,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
placeholder={databaseIdPlaceHolder} placeholder={databaseIdPlaceHolder}
value={databaseId} value={databaseId}
onChange={handleonChangeDBId} onChange={handleonChangeDBId}
autoFocus
styles={getTextFieldStyles()} styles={getTextFieldStyles()}
/> />

View File

@@ -33,7 +33,6 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = `
aria-label="Database id" aria-label="Database id"
aria-required="true" aria-required="true"
autoComplete="off" autoComplete="off"
autoFocus={true}
id="database-id" id="database-id"
onChange={[Function]} onChange={[Function]}
pattern="[^/?#\\\\\\\\]*[^/?# \\\\\\\\]" pattern="[^/?#\\\\\\\\]*[^/?# \\\\\\\\]"

View File

@@ -169,7 +169,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
aria-label="Create new keyspace" aria-label="Create new keyspace"
checked={keyspaceCreateNew} checked={keyspaceCreateNew}
type="radio" type="radio"
role="radio"
tabIndex={0} tabIndex={0}
onChange={() => { onChange={() => {
setKeyspaceCreateNew(true); setKeyspaceCreateNew(true);
@@ -184,7 +183,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
aria-label="Use existing keyspace" aria-label="Use existing keyspace"
checked={!keyspaceCreateNew} checked={!keyspaceCreateNew}
type="radio" type="radio"
role="radio"
tabIndex={0} tabIndex={0}
onChange={() => { onChange={() => {
setKeyspaceCreateNew(false); setKeyspaceCreateNew(false);
@@ -208,7 +206,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
value={newKeyspaceId} value={newKeyspaceId}
onChange={(e, newValue) => setNewKeyspaceId(newValue)} onChange={(e, newValue) => setNewKeyspaceId(newValue)}
ariaLabel="Keyspace id" ariaLabel="Keyspace id"
autoFocus
/> />
{!isServerlessAccount() && ( {!isServerlessAccount() && (

View File

@@ -77,7 +77,7 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
selectedLocation.repo selectedLocation.repo
)} - ${selectedLocation.branch}`; )} - ${selectedLocation.branch}`;
} else if (selectedLocation.type === "MyNotebooks" && userContext.features.phoenix) { } else if (selectedLocation.type === "MyNotebooks" && userContext.features.phoenix) {
destination = useNotebook.getState().notebookFolderName; destination = "My Notebooks Scratch";
} }
clearMessage = NotificationConsoleUtils.logConsoleProgress(`Copying ${name} to ${destination}`); clearMessage = NotificationConsoleUtils.logConsoleProgress(`Copying ${name} to ${destination}`);

View File

@@ -119,7 +119,6 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
<Text variant="small">Confirm by typing the {collectionName.toLowerCase()} id</Text> <Text variant="small">Confirm by typing the {collectionName.toLowerCase()} id</Text>
<TextField <TextField
id="confirmCollectionId" id="confirmCollectionId"
autoFocus
value={inputCollectionName} value={inputCollectionName}
styles={{ fieldGroup: { width: 300 } }} styles={{ fieldGroup: { width: 300 } }}
onChange={(event, newInput?: string) => { onChange={(event, newInput?: string) => {

View File

@@ -41,7 +41,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
</Text> </Text>
<StyledTextFieldBase <StyledTextFieldBase
ariaLabel="Confirm by typing the container id" ariaLabel="Confirm by typing the container id"
autoFocus={true}
id="confirmCollectionId" id="confirmCollectionId"
onChange={[Function]} onChange={[Function]}
styles={ styles={
@@ -55,7 +54,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
> >
<TextFieldBase <TextFieldBase
ariaLabel="Confirm by typing the container id" ariaLabel="Confirm by typing the container id"
autoFocus={true}
deferredValidationTime={200} deferredValidationTime={200}
id="confirmCollectionId" id="confirmCollectionId"
onChange={[Function]} onChange={[Function]}
@@ -349,7 +347,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
<input <input
aria-invalid={false} aria-invalid={false}
aria-label="Confirm by typing the container id" aria-label="Confirm by typing the container id"
autoFocus={true}
className="ms-TextField-field field-57" className="ms-TextField-field field-57"
id="confirmCollectionId" id="confirmCollectionId"
onBlur={[Function]} onBlur={[Function]}

View File

@@ -129,7 +129,6 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
<Text variant="small">Confirm by typing the database id</Text> <Text variant="small">Confirm by typing the database id</Text>
<TextField <TextField
id="confirmDatabaseId" id="confirmDatabaseId"
autoFocus
styles={{ fieldGroup: { width: 300 } }} styles={{ fieldGroup: { width: 300 } }}
onChange={(event, newInput?: string) => { onChange={(event, newInput?: string) => {
setDatabaseInput(newInput); setDatabaseInput(newInput);

View File

@@ -69,25 +69,11 @@ export const InputParameter: FunctionComponent<InputParameterProps> = ({
/> />
{isAddRemoveVisible && ( {isAddRemoveVisible && (
<> <>
<div tabIndex={0}> <div tabIndex={0} onClick={onDeleteParamKeyPress} role="button" onKeyPress={onDeleteParamKeyPress}>
<Image <Image {...imageProps} src={EntityCancelIcon} alt="Delete param" id="deleteparam" />
{...imageProps}
src={EntityCancelIcon}
alt="Delete param"
id="deleteparam"
role="button"
onClick={onDeleteParamKeyPress}
/>
</div> </div>
<div tabIndex={0}> <div tabIndex={0} onClick={onAddNewParamKeyPress} role="button" onKeyPress={onAddNewParamKeyPress}>
<Image <Image {...imageProps} src={AddPropertyIcon} alt="Add param" id="addparam" />
{...imageProps}
src={AddPropertyIcon}
alt="Add param"
id="addparam"
role="button"
onClick={onAddNewParamKeyPress}
/>
</div> </div>
</> </>
)} )}

View File

@@ -4328,6 +4328,9 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
</TextFieldBase> </TextFieldBase>
</StyledTextFieldBase> </StyledTextFieldBase>
<div <div
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex={0} tabIndex={0}
> >
<StyledImageBase <StyledImageBase
@@ -4335,8 +4338,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
className="addRemoveIconLabel" className="addRemoveIconLabel"
height={30} height={30}
id="deleteparam" id="deleteparam"
onClick={[Function]}
role="button"
src="" src=""
width={20} width={20}
> >
@@ -4345,8 +4346,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
className="addRemoveIconLabel" className="addRemoveIconLabel"
height={30} height={30}
id="deleteparam" id="deleteparam"
onClick={[Function]}
role="button"
src="" src=""
styles={[Function]} styles={[Function]}
theme={ theme={
@@ -4638,10 +4637,8 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87" className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
id="deleteparam" id="deleteparam"
key="fabricImage" key="fabricImage"
onClick={[Function]}
onError={[Function]} onError={[Function]}
onLoad={[Function]} onLoad={[Function]}
role="button"
src="" src=""
/> />
</div> </div>
@@ -4649,6 +4646,9 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
</StyledImageBase> </StyledImageBase>
</div> </div>
<div <div
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex={0} tabIndex={0}
> >
<StyledImageBase <StyledImageBase
@@ -4656,8 +4656,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
className="addRemoveIconLabel" className="addRemoveIconLabel"
height={30} height={30}
id="addparam" id="addparam"
onClick={[Function]}
role="button"
src="" src=""
width={20} width={20}
> >
@@ -4666,8 +4664,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
className="addRemoveIconLabel" className="addRemoveIconLabel"
height={30} height={30}
id="addparam" id="addparam"
onClick={[Function]}
role="button"
src="" src=""
styles={[Function]} styles={[Function]}
theme={ theme={
@@ -4959,10 +4955,8 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87" className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
id="addparam" id="addparam"
key="fabricImage" key="fabricImage"
onClick={[Function]}
onError={[Function]} onError={[Function]}
onLoad={[Function]} onLoad={[Function]}
role="button"
src="" src=""
/> />
</div> </div>

View File

@@ -92,7 +92,6 @@ export const LoadQueryPane: FunctionComponent = (): JSX.Element => {
id="confirmCollectionId" id="confirmCollectionId"
label="Select a query document" label="Select a query document"
value={selectedFileName} value={selectedFileName}
autoFocus
readOnly readOnly
styles={{ fieldGroup: { width: 300 } }} styles={{ fieldGroup: { width: 300 } }}
/> />

View File

@@ -17,7 +17,6 @@ exports[`Load Query Pane should render Default properly 1`] = `
horizontal={true} horizontal={true}
> >
<StyledTextFieldBase <StyledTextFieldBase
autoFocus={true}
id="confirmCollectionId" id="confirmCollectionId"
label="Select a query document" label="Select a query document"
readOnly={true} readOnly={true}

View File

@@ -48,9 +48,15 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
)} )}
</Text> </Text>
{showErrorDetails && ( {showErrorDetails && (
<a className="paneErrorLink" role="link" onClick={expandConsole}> <span
className="paneErrorLink moreOption"
role="link"
onClick={expandConsole}
onKeyPress={expandConsole}
tabIndex={0}
>
More details More details
</a> </span>
)} )}
</span> </span>
</Stack> </Stack>

View File

@@ -3,6 +3,6 @@ import LoadingIndicator_3Squares from "../../../images/LoadingIndicator_3Squares
export const PanelLoadingScreen: React.FunctionComponent = () => ( export const PanelLoadingScreen: React.FunctionComponent = () => (
<div className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer"> <div className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer">
<img className="dataExplorerLoader" src={LoadingIndicator_3Squares} /> <img className="dataExplorerLoader" src={LoadingIndicator_3Squares} alt="loading indicator" />
</div> </div>
); );

View File

@@ -146,7 +146,6 @@ export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({ explorer
<TextField <TextField
id="saveQueryInput" id="saveQueryInput"
label="Name" label="Name"
autoFocus
styles={{ fieldGroup: { width: 300 } }} styles={{ fieldGroup: { width: 300 } }}
onChange={(event, newInput?: string) => { onChange={(event, newInput?: string) => {
setQueryName(newInput); setQueryName(newInput);

View File

@@ -97,7 +97,6 @@ export const StringInputPane: FunctionComponent<StringInputPanelProps> = ({
label={inputLabel} label={inputLabel}
name="collectionIdConfirmation" name="collectionIdConfirmation"
value={stringInput} value={stringInput}
autoFocus
required required
onChange={(event: FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => onChange={(event: FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) =>
setStringInput(newValue) setStringInput(newValue)

View File

@@ -56,7 +56,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
> >
<StyledTextFieldBase <StyledTextFieldBase
aria-label="Enter new directory name" aria-label="Enter new directory name"
autoFocus={true}
label="Enter new directory name" label="Enter new directory name"
name="collectionIdConfirmation" name="collectionIdConfirmation"
onChange={[Function]} onChange={[Function]}
@@ -65,7 +64,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
> >
<TextFieldBase <TextFieldBase
aria-label="Enter new directory name" aria-label="Enter new directory name"
autoFocus={true}
deferredValidationTime={200} deferredValidationTime={200}
label="Enter new directory name" label="Enter new directory name"
name="collectionIdConfirmation" name="collectionIdConfirmation"
@@ -655,7 +653,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
<input <input
aria-invalid={false} aria-invalid={false}
aria-labelledby="TextFieldLabel2" aria-labelledby="TextFieldLabel2"
autoFocus={true}
className="ms-TextField-field field-56" className="ms-TextField-field field-56"
id="TextField0" id="TextField0"
name="collectionIdConfirmation" name="collectionIdConfirmation"

View File

@@ -368,7 +368,6 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
</Text> </Text>
<StyledTextFieldBase <StyledTextFieldBase
ariaLabel="Confirm by typing the database id" ariaLabel="Confirm by typing the database id"
autoFocus={true}
id="confirmDatabaseId" id="confirmDatabaseId"
onChange={[Function]} onChange={[Function]}
styles={ styles={
@@ -381,7 +380,6 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
> >
<TextFieldBase <TextFieldBase
ariaLabel="Confirm by typing the database id" ariaLabel="Confirm by typing the database id"
autoFocus={true}
deferredValidationTime={200} deferredValidationTime={200}
id="confirmDatabaseId" id="confirmDatabaseId"
onChange={[Function]} onChange={[Function]}
@@ -674,7 +672,6 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
<input <input
aria-invalid={false} aria-invalid={false}
aria-label="Confirm by typing the database id" aria-label="Confirm by typing the database id"
autoFocus={true}
className="ms-TextField-field field-60" className="ms-TextField-field field-60"
id="confirmDatabaseId" id="confirmDatabaseId"
onBlur={[Function]} onBlur={[Function]}

View File

@@ -108,7 +108,8 @@
} }
.oneLineContent { .oneLineContent {
margin-top: 4px; margin-top: 6px;
margin-left: 6px;
} }
.twoLineContent { .twoLineContent {
@@ -133,12 +134,12 @@
.flex-display(); .flex-display();
.flex-direction(); .flex-direction();
>.title { .title {
color: @BaseDark; color: @BaseDark;
padding: 0px; padding: 0px;
font-size: 12px; font-size: 12px;
} }
>.description { .description {
color: @BaseDark; color: @BaseDark;
} }

View File

@@ -128,9 +128,8 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
<div className="title">Common Tasks</div> <div className="title">Common Tasks</div>
<ul> <ul>
{commonTaskItems.map((item) => ( {commonTaskItems.map((item) => (
<li <li className="focusable" key={`${item.title}${item.description}`}>
className="focusable" <div
key={`${item.title}${item.description}`}
onClick={item.onClick} onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)} onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0} tabIndex={0}
@@ -140,6 +139,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
<span className="oneLineContent" title={item.info}> <span className="oneLineContent" title={item.info}>
{item.title} {item.title}
</span> </span>
</div>
</li> </li>
))} ))}
</ul> </ul>
@@ -165,22 +165,23 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
<div className="title">Tips</div> <div className="title">Tips</div>
<ul> <ul>
{tipsItems.map((item) => ( {tipsItems.map((item) => (
<li <li className="tipContainer focusable" key={`${item.title}${item.description}`}>
className="tipContainer focusable" <div
key={`${item.title}${item.description}`}
onClick={item.onClick} onClick={item.onClick}
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)} onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
tabIndex={0} tabIndex={0}
role="link" role="button"
className="tipsWrapper"
> >
<div className="title" title={item.info}> <div className="title" title={item.info}>
{item.title} {item.title}
</div> </div>
<div className="description">{item.description}</div> <div className="description">{item.description}</div>
</div>
</li> </li>
))} ))}
<li> <li>
<a role="link" href={SplashScreen.seeMoreItemUrl} rel="noreferrer" target="_blank" tabIndex={0}> <a href={SplashScreen.seeMoreItemUrl} rel="noreferrer" target="_blank" tabIndex={0}>
{SplashScreen.seeMoreItemTitle} {SplashScreen.seeMoreItemTitle}
</a> </a>
</li> </li>

View File

@@ -966,10 +966,15 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
<> <>
<span className="queryResultDivider">|</span> <span className="queryResultDivider">|</span>
<span className="queryResultNextEnable"> <span className="queryResultNextEnable">
<a onClick={this.onFetchNextPageClick.bind(this)}> <div
<span>Load more</span> onClick={this.onFetchNextPageClick.bind(this)}
role="button"
tabIndex={0}
onKeyPress={this.onFetchNextPageClick.bind(this)}
>
<span className="moreOption">Load more</span>
<img className="queryResultnextImg" src={QueryEditorNext} alt="Fetch next page" /> <img className="queryResultnextImg" src={QueryEditorNext} alt="Fetch next page" />
</a> </div>
</span> </span>
</> </>
)} )}
@@ -1015,7 +1020,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
</div> </div>
{this.state.isQueryMetricsEnabled && ( {this.state.isQueryMetricsEnabled && (
<div className="downloadMetricsLinkContainer"> <div className="downloadMetricsLinkContainer">
<a <span
id="downloadMetricsLink" id="downloadMetricsLink"
role="button" role="button"
tabIndex={0} tabIndex={0}
@@ -1030,7 +1035,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
alt="download query metrics csv" alt="download query metrics csv"
/> />
<span>Per-partition query metrics (CSV)</span> <span>Per-partition query metrics (CSV)</span>
</a> </span>
</div> </div>
)} )}
</div> </div>
@@ -1044,7 +1049,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
<div className="errorContent"> <div className="errorContent">
<span className="errorMessage">{this.state.error}</span> <span className="errorMessage">{this.state.error}</span>
<span className="errorDetailsLink"> <span className="errorDetailsLink">
<a <span
onClick={() => this.onErrorDetailsClick()} onClick={() => this.onErrorDetailsClick()}
onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) => onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) =>
this.onErrorDetailsKeyPress(event) this.onErrorDetailsKeyPress(event)
@@ -1052,9 +1057,11 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
id="error-display" id="error-display"
tabIndex={0} tabIndex={0}
aria-label="Error details link" aria-label="Error details link"
role="button"
className="moreOption"
> >
More details More details
</a> </span>
</span> </span>
</div> </div>
</div> </div>

View File

@@ -579,13 +579,16 @@ export default class StoredProcedureTabComponent extends React.Component<
<div className="errorContent"> <div className="errorContent">
<span className="errorMessage">{this.state.error}</span> <span className="errorMessage">{this.state.error}</span>
<span className="errorDetailsLink"> <span className="errorDetailsLink">
<a <span
role="button"
tabIndex={0}
className="moreOption"
aria-label="Error details link" aria-label="Error details link"
onClick={() => this.onErrorDetailsClick()} onClick={() => this.onErrorDetailsClick()}
onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) => this.onErrorDetailsKeyPress(event)} onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) => this.onErrorDetailsKeyPress(event)}
> >
More details More details
</a> </span>
</span> </span>
</div> </div>
</div> </div>

View File

@@ -53,6 +53,7 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
tabIndex={0} tabIndex={0}
role="tab" role="tab"
ref={focusTab} ref={focusTab}
onFocus={() => setHovering(true)}
> >
<span className="tabNavContentContainer"> <span className="tabNavContentContainer">
<a data-toggle="tab" href={"#" + tab.tabId} tabIndex={-1}> <a data-toggle="tab" href={"#" + tab.tabId} tabIndex={-1}>

View File

@@ -295,8 +295,6 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
className="trigger-field" className="trigger-field"
label="Trigger Id" label="Trigger Id"
id="entityTimeId" id="entityTimeId"
autoFocus
required
type="text" type="text"
pattern="[^/?#\\]*[^/?# \\]" pattern="[^/?#\\]*[^/?# \\]"
placeholder="Enter the new trigger id" placeholder="Enter the new trigger id"

View File

@@ -276,7 +276,6 @@ export default class UserDefinedFunctionTabContent extends Component<
className="trigger-field" className="trigger-field"
label="User Defined Function Id" label="User Defined Function Id"
id="entityTimeId" id="entityTimeId"
autoFocus
required required
readOnly={!isUdfIdEditable} readOnly={!isUdfIdEditable}
type="text" type="text"

View File

@@ -128,12 +128,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
notebooksTree.children.push(buildGalleryNotebooksTree()); notebooksTree.children.push(buildGalleryNotebooksTree());
} }
if ( if (myNotebooksContentRoot && useNotebook.getState().connectionInfo.status == ConnectionStatusType.Connected) {
myNotebooksContentRoot &&
((NotebookUtil.isPhoenixEnabled() &&
useNotebook.getState().connectionInfo.status === ConnectionStatusType.Connected) ||
userContext.features.phoenix === false)
) {
notebooksTree.children.push(buildMyNotebooksTree()); notebooksTree.children.push(buildMyNotebooksTree());
} }
if (container.notebookManager?.gitHubOAuthService.isLoggedIn()) { if (container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
@@ -167,11 +162,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
myNotebooksContentRoot, myNotebooksContentRoot,
(item: NotebookContentItem) => { (item: NotebookContentItem) => {
container.openNotebook(item).then((hasOpened) => { container.openNotebook(item).then((hasOpened) => {
if ( if (hasOpened) {
hasOpened &&
userContext.features.notebooksTemporarilyDown === false &&
userContext.features.phoenix === false
) {
mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item); mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item);
} }
}); });
@@ -190,11 +181,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
gitHubNotebooksContentRoot, gitHubNotebooksContentRoot,
(item: NotebookContentItem) => { (item: NotebookContentItem) => {
container.openNotebook(item).then((hasOpened) => { container.openNotebook(item).then((hasOpened) => {
if ( if (hasOpened) {
hasOpened &&
userContext.features.notebooksTemporarilyDown === false &&
userContext.features.phoenix === false
) {
mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item); mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item);
} }
}); });
@@ -226,7 +213,23 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
}, },
}, },
]; ];
gitHubNotebooksTree.contextMenu = manageGitContextMenu; const connectGitContextMenu: TreeNodeMenuItem[] = [
{
label: "Connect to GitHub",
onClick: () =>
useSidePanel
.getState()
.openSidePanel(
"Connect to GitHub",
<GitHubReposPanel
explorer={container}
gitHubClientProp={container.notebookManager.gitHubClient}
junoClientProp={container.notebookManager.junoClient}
/>
),
},
];
gitHubNotebooksTree.contextMenu = isConnected ? manageGitContextMenu : connectGitContextMenu;
gitHubNotebooksTree.isExpanded = true; gitHubNotebooksTree.isExpanded = true;
gitHubNotebooksTree.isAlphaSorted = true; gitHubNotebooksTree.isAlphaSorted = true;

View File

@@ -45,6 +45,7 @@ import UserDefinedFunction from "./UserDefinedFunction";
export class ResourceTreeAdapter implements ReactAdapter { export class ResourceTreeAdapter implements ReactAdapter {
public static readonly MyNotebooksTitle = "My Notebooks"; public static readonly MyNotebooksTitle = "My Notebooks";
public static readonly MyNotebooksScratchTitle = "My Notebooks Scratch";
public static readonly GitHubReposTitle = "GitHub repos"; public static readonly GitHubReposTitle = "GitHub repos";
private static readonly DataTitle = "DATA"; private static readonly DataTitle = "DATA";

View File

@@ -1,9 +1,9 @@
import { Octokit } from "@octokit/rest"; import { Octokit } from "@octokit/rest";
import { HttpStatusCodes } from "../Common/Constants"; import { HttpStatusCodes } from "../Common/Constants";
import { getErrorMessage } from "../Common/ErrorHandlingUtils";
import * as Logger from "../Common/Logger"; import * as Logger from "../Common/Logger";
import * as UrlUtility from "../Common/UrlUtility"; import * as UrlUtility from "../Common/UrlUtility";
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil"; import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
import { getErrorMessage } from "../Common/ErrorHandlingUtils";
export interface IGitHubPageInfo { export interface IGitHubPageInfo {
endCursor: string; endCursor: string;
@@ -225,7 +225,7 @@ export class GitHubClient {
private static readonly SelfErrorCode = 599; private static readonly SelfErrorCode = 599;
private ocktokit: Octokit; private ocktokit: Octokit;
constructor(private errorCallback: (error: Error) => void) { constructor(private errorCallback: (error: any) => void) {
this.initOctokit(); this.initOctokit();
} }
@@ -501,11 +501,10 @@ export class GitHubClient {
this.ocktokit = new Octokit({ this.ocktokit = new Octokit({
auth: token, auth: token,
log: { log: {
// eslint-disable-next-line @typescript-eslint/no-empty-function
debug: () => {}, debug: () => {},
info: (message?: string) => GitHubClient.log(Logger.logInfo, message), info: (message?: any) => GitHubClient.log(Logger.logInfo, message),
warn: (message?: string) => GitHubClient.log(Logger.logWarning, message), warn: (message?: any) => GitHubClient.log(Logger.logWarning, message),
error: (error?: Error) => Logger.logError(getErrorMessage(error), "GitHubClient.Octokit"), error: (error?: any) => Logger.logError(getErrorMessage(error), "GitHubClient.Octokit"),
}, },
}); });
@@ -515,7 +514,7 @@ export class GitHubClient {
}); });
} }
private static log(logger: (message: string, area: string) => void, message?: string) { private static log(logger: (message: string, area: string) => void, message?: any) {
if (message) { if (message) {
message = typeof message === "string" ? message : JSON.stringify(message); message = typeof message === "string" ? message : JSON.stringify(message);
logger(message, "GitHubClient.Octokit"); logger(message, "GitHubClient.Octokit");

View File

@@ -89,6 +89,8 @@ const App: React.FunctionComponent = () => {
onClick={() => window.open("https://portal.azure.com", "_blank")} onClick={() => window.open("https://portal.azure.com", "_blank")}
tabIndex={0} tabIndex={0}
title="Go to Azure Portal" title="Go to Azure Portal"
role="button"
onKeyDown={() => window.open("https://portal.azure.com", "_blank")}
> >
Microsoft Azure Microsoft Azure
</span> </span>

View File

@@ -33,13 +33,23 @@ const Index = (): JSX.Element => {
<div <div
id="Quickstart" id="Quickstart"
onClick={quickstart_click} onClick={quickstart_click}
onKeyPress={quickstart_click}
role="button"
tabIndex={0}
className={navigationSelection === "quickstart" ? "topSelected" : ""} className={navigationSelection === "quickstart" ? "topSelected" : ""}
> >
<img id="imgiconwidth1" src={Quickstart} alt="Open Quick Start" /> <img id="imgiconwidth1" src={Quickstart} alt="Open Quick Start" />
<span className="menuQuickStart">Quickstart</span> <span className="menuQuickStart">Quickstart</span>
</div> </div>
<div id="Explorer" onClick={explorer_click} className={navigationSelection === "explorer" ? "topSelected" : ""}> <div
id="Explorer"
onClick={explorer_click}
className={navigationSelection === "explorer" ? "topSelected" : ""}
role="button"
tabIndex={0}
onKeyPress={explorer_click}
>
<img id="imgiconwidth1" src={Explorer} alt="Open Data Explorer" /> <img id="imgiconwidth1" src={Explorer} alt="Open Data Explorer" />
<span className="menuExplorer">Explorer</span> <span className="menuExplorer">Explorer</span>
</div> </div>
@@ -53,11 +63,11 @@ const Index = (): JSX.Element => {
</nav> </nav>
{navigationSelection === "quickstart" && ( {navigationSelection === "quickstart" && (
<iframe name="quickstart" className="iframe" src="quickstart.html"></iframe> <iframe name="quickstart" className="iframe" src="quickstart.html" title="Quick Start"></iframe>
)} )}
{navigationSelection === "explorer" && ( {navigationSelection === "explorer" && (
<iframe name="explorer" className="iframe" src="explorer.html?platform=Emulator"></iframe> <iframe name="explorer" className="iframe" src="explorer.html?platform=Emulator" title="Explorer"></iframe>
)} )}
</React.Fragment> </React.Fragment>
); );

View File

@@ -1,5 +1,7 @@
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants"; import { ConnectionStatusType, HttpHeaders, HttpStatusCodes } from "../Common/Constants";
import { configContext } from "../ConfigContext"; import { configContext } from "../ConfigContext";
import { ContainerConnectionInfo } from "../Contracts/DataModels";
import { useNotebook } from "../Explorer/Notebook/useNotebook";
import { userContext } from "../UserContext"; import { userContext } from "../UserContext";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
@@ -13,6 +15,7 @@ export interface IPhoenixConnectionInfoResult {
} }
export interface IProvosionData { export interface IProvosionData {
cosmosEndpoint: string; cosmosEndpoint: string;
resourceId: string;
dbAccountName: string; dbAccountName: string;
aadToken: string; aadToken: string;
resourceGroup: string; resourceGroup: string;
@@ -23,7 +26,11 @@ export class PhoenixClient {
provisionData: IProvosionData provisionData: IProvosionData
): Promise<IPhoenixResponse<IPhoenixConnectionInfoResult>> { ): Promise<IPhoenixResponse<IPhoenixConnectionInfoResult>> {
try { try {
const response = await window.fetch(`${this.getPhoenixContainerPoolingEndPoint()}/allocate`, { const connectionStatus: ContainerConnectionInfo = {
status: ConnectionStatusType.Connecting,
};
useNotebook.getState().setConnectionInfo(connectionStatus);
const response = await window.fetch(`${this.getPhoenixContainerPoolingEndPoint()}/provision`, {
method: "POST", method: "POST",
headers: PhoenixClient.getHeaders(), headers: PhoenixClient.getHeaders(),
body: JSON.stringify(provisionData), body: JSON.stringify(provisionData),
@@ -31,20 +38,31 @@ export class PhoenixClient {
let data: IPhoenixConnectionInfoResult; let data: IPhoenixConnectionInfoResult;
if (response.status === HttpStatusCodes.OK) { if (response.status === HttpStatusCodes.OK) {
data = await response.json(); data = await response.json();
if (data && data.notebookServerUrl) {
connectionStatus.status = ConnectionStatusType.Connected;
useNotebook.getState().setConnectionInfo(connectionStatus);
} }
} else {
connectionStatus.status = ConnectionStatusType.Failed;
useNotebook.getState().setConnectionInfo(connectionStatus);
}
return { return {
status: response.status, status: response.status,
data, data,
}; };
} catch (error) { } catch (error) {
const connectionStatus: ContainerConnectionInfo = {
status: ConnectionStatusType.Failed,
};
useNotebook.getState().setConnectionInfo(connectionStatus);
console.error(error); console.error(error);
throw error; throw error;
} }
} }
public static getPhoenixEndpoint(): string { public static getPhoenixEndpoint(): string {
const phoenixEndpoint = const phoenixEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
if (configContext.allowedJunoOrigins.indexOf(new URL(phoenixEndpoint).origin) === -1) { if (configContext.allowedJunoOrigins.indexOf(new URL(phoenixEndpoint).origin) === -1) {
const error = `${phoenixEndpoint} not allowed as juno endpoint`; const error = `${phoenixEndpoint} not allowed as juno endpoint`;
console.error(error); console.error(error);
@@ -55,7 +73,7 @@ export class PhoenixClient {
} }
public getPhoenixContainerPoolingEndPoint(): string { public getPhoenixContainerPoolingEndPoint(): string {
return `${PhoenixClient.getPhoenixEndpoint()}/api/controlplane/toolscontainer`; return `${PhoenixClient.getPhoenixEndpoint()}/api/containerpooling`;
} }
private static getHeaders(): HeadersInit { private static getHeaders(): HeadersInit {
const authorizationHeader = getAuthorizationHeader(); const authorizationHeader = getAuthorizationHeader();

View File

@@ -77,16 +77,16 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
<p className="connectExplorerContent"> <p className="connectExplorerContent">
<input className="filterbtnstyle" type="submit" value="Connect" /> <input className="filterbtnstyle" type="submit" value="Connect" />
</p> </p>
<p className="switchConnectTypeText" onClick={login}> <div className="switchConnectTypeText" onClick={login} onKeyDown={login} role="button" tabIndex={0}>
Sign In with Azure Account Sign In with Azure Account
</p> </div>
</form> </form>
) : ( ) : (
<div id="connectWithAad"> <div id="connectWithAad">
<input className="filterbtnstyle" type="button" value="Sign In" onClick={login} /> <input className="filterbtnstyle" type="button" value="Sign In" onClick={login} />
<p className="switchConnectTypeText" onClick={showForm}> <div className="switchConnectTypeText" onClick={showForm} onKeyDown={showForm} role="button" tabIndex={0}>
Connect to your account with connection string Connect to your account with connection string
</p> </div>
</div> </div>
)} )}
</div> </div>

View File

@@ -20,7 +20,6 @@ export type Features = {
readonly enableKoResourceTree: boolean; readonly enableKoResourceTree: boolean;
readonly hostedDataExplorer: boolean; readonly hostedDataExplorer: boolean;
readonly junoEndpoint?: string; readonly junoEndpoint?: string;
readonly phoenixEndpoint?: string;
readonly livyEndpoint?: string; readonly livyEndpoint?: string;
readonly notebookBasePath?: string; readonly notebookBasePath?: string;
readonly notebookServerToken?: string; readonly notebookServerToken?: string;
@@ -69,7 +68,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
mongoProxyEndpoint: get("mongoproxyendpoint"), mongoProxyEndpoint: get("mongoproxyendpoint"),
mongoProxyAPIs: get("mongoproxyapis"), mongoProxyAPIs: get("mongoproxyapis"),
junoEndpoint: get("junoendpoint"), junoEndpoint: get("junoendpoint"),
phoenixEndpoint: get("phoenixendpoint"),
livyEndpoint: get("livyendpoint"), livyEndpoint: get("livyendpoint"),
notebookBasePath: get("notebookbasepath"), notebookBasePath: get("notebookbasepath"),
notebookServerToken: get("notebookservertoken"), notebookServerToken: get("notebookservertoken"),

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
if (window.parent !== window) { if (window.parent !== window) {
(window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ = (window.parent as any).__REACT_DEVTOOLS_GLOBAL_HOOK__; (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ = (window.parent as any).__REACT_DEVTOOLS_GLOBAL_HOOK__;
} }

View File

@@ -10,7 +10,6 @@ import {
SortBy, SortBy,
} from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent"; } from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent";
import Explorer from "../Explorer/Explorer"; import Explorer from "../Explorer/Explorer";
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
import { useNotebook } from "../Explorer/Notebook/useNotebook"; import { useNotebook } from "../Explorer/Notebook/useNotebook";
import { IGalleryItem, JunoClient } from "../Juno/JunoClient"; import { IGalleryItem, JunoClient } from "../Juno/JunoClient";
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
@@ -226,38 +225,11 @@ export function downloadItem(
const name = data.name; const name = data.name;
useDialog.getState().showOkCancelModalDialog( useDialog.getState().showOkCancelModalDialog(
`Download to ${useNotebook.getState().notebookFolderName}`, `Download to ${useNotebook.getState().notebookFolderName}`,
undefined, `Download ${name} from gallery as a copy to your notebooks to run and/or edit the notebook.`,
"Download", "Download",
async () => { async () => {
if (NotebookUtil.isPhoenixEnabled()) {
await container.allocateContainer();
}
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
if (notebookServerInfo && notebookServerInfo.notebookServerEndpoint !== undefined) {
downloadNotebookItem(name, data, junoClient, container, onComplete);
} else {
useDialog
.getState()
.showOkModalDialog(
"Failed to Connect",
"Failed to connect to temporary workspace. Please refresh the page and try again."
);
}
},
"Cancel",
undefined,
container.getDownloadModalConent(name)
);
}
export async function downloadNotebookItem(
fileName: string,
data: IGalleryItem,
junoClient: JunoClient,
container: Explorer,
onComplete: (item: IGalleryItem) => void
) {
const clearInProgressMessage = logConsoleProgress( const clearInProgressMessage = logConsoleProgress(
`Downloading ${fileName} to ${useNotebook.getState().notebookFolderName}` `Downloading ${name} to ${useNotebook.getState().notebookFolderName}`
); );
const startKey = traceStart(Action.NotebooksGalleryDownload, { const startKey = traceStart(Action.NotebooksGalleryDownload, {
notebookId: data.id, notebookId: data.id,
@@ -280,7 +252,7 @@ export async function downloadNotebookItem(
} }
await container.importAndOpenContent(data.name, JSON.stringify(notebook)); await container.importAndOpenContent(data.name, JSON.stringify(notebook));
logConsoleInfo(`Successfully downloaded ${data.name} to ${useNotebook.getState().notebookFolderName}`); logConsoleInfo(`Successfully downloaded ${name} to My Notebooks`);
const increaseDownloadResponse = await junoClient.increaseNotebookDownloadCount(data.id); const increaseDownloadResponse = await junoClient.increaseNotebookDownloadCount(data.id);
if (increaseDownloadResponse.data) { if (increaseDownloadResponse.data) {
@@ -308,7 +280,12 @@ export async function downloadNotebookItem(
} }
clearInProgressMessage(); clearInProgressMessage();
},
"Cancel",
undefined
);
} }
export const removeNotebookViewerLink = (notebook: Notebook, newCellId: string): void => { export const removeNotebookViewerLink = (notebook: Notebook, newCellId: string): void => {
if (!newCellId) { if (!newCellId) {
return; return;

View File

@@ -8,6 +8,7 @@
"noUnusedParameters": true "noUnusedParameters": true
}, },
"files": [ "files": [
"./src/SelfServe/GraphAPICompute/GraphAPICompute.types.ts",
"./src/AuthType.ts", "./src/AuthType.ts",
"./src/Bindings/ReactBindingHandler.ts", "./src/Bindings/ReactBindingHandler.ts",
"./src/Common/ArrayHashMap.ts", "./src/Common/ArrayHashMap.ts",