Compare commits

...

20 Commits

Author SHA1 Message Date
vaidankarswapnil
f296c00a1c Fixed graph style panel close issue (#858) 2021-06-07 10:38:13 -05:00
victor-meng
7d0be7d355 Show 10k RU instead of unlimited as max RU for unsharded collection (#845) 2021-05-28 20:11:31 -05:00
Steve Faulkner
04b3ef051a Revert "Upgrade Monaco Editor (#847)" (#850)
This reverts commit 5e2b8d7df0.
2021-05-28 15:49:29 -05:00
Steve Faulkner
b875407d49 Pure React Command Bar (#828) 2021-05-28 15:20:59 -05:00
Steve Faulkner
18ce8749ed Fix Enable Synapse Link (#849) 2021-05-28 15:20:19 -05:00
Steve Faulkner
5e2b8d7df0 Upgrade Monaco Editor (#847) 2021-05-28 13:58:35 -05:00
Steve Faulkner
da13a2b3cf Change CI cleanup to once per day 2021-05-28 09:16:36 -05:00
Zachary Foster
69b8196cf0 Removes feature flag from passing masterKey to SDK (#843)
* Remove Feature flag from master key usage

* Adds flag to fallback

* format
2021-05-28 08:12:33 -04:00
Steve Faulkner
5417e1e120 Enable Preview for Hosted Mode (#844) 2021-05-27 22:13:18 -05:00
Steve Faulkner
481ff9e7fe Migrate SidePanel state to Zustand (#799)
Co-authored-by: hardiknai-techm <HN00734461@TechMahindra.com>
2021-05-27 16:07:07 -05:00
Zachary Foster
e41b52e265 Redo user endpoint dynamic token (#827)
* Redo user endpoint dynamic token

* Fixes aad endpoint race condition, tenant switching, and account permissions

* Export const msalInstance

* Format

* fix import

* format

* Redo getMsalInstance

* format again

* Check for doc endpoint
2021-05-27 16:18:44 -04:00
Steve Faulkner
75d01f655f Show "Open Query" for SQL only (#830) 2021-05-26 15:12:36 -05:00
Hardikkumar Nai
50f83cde87 Remove Explorer.collectionCreationDefaults (#840)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-26 15:11:47 -05:00
Tanuj Mittal
6d03cec139 Disable caching for cellOutputViewer.html (#829) 2021-05-27 01:31:28 +05:30
Tanuj Mittal
cb1d60cc90 Hide hosted shells and schema analyzer if VNET, Firewall or Private endpoints is enabled (#826)
* Disable Schema Analyzer if VNET or Firewall is enabled

* Add support for private endpoint connections

* Fix lint warning
2021-05-27 01:31:13 +05:30
Steve Faulkner
0201e6ff92 Remove unused KO dynamic-list component (#838) 2021-05-25 22:40:53 -05:00
Sunil Kumar Yadav
1bcb4246f6 Migration Expand/Collapse Resource Tree to React (#815)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-25 15:26:36 -05:00
Steve Faulkner
e7e15c54b3 Cleanup Synapse+Spark Logic (#813) 2021-05-25 14:46:52 -05:00
Sunil Kumar Yadav
522fdc69ab Remove Explorer collection/database text properties (#821)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
2021-05-25 08:32:40 -05:00
Steve Faulkner
bfdeae56d9 Upload to master commit SHA for preview (#823) 2021-05-25 07:42:40 -05:00
124 changed files with 709 additions and 8232 deletions

View File

@@ -111,9 +111,6 @@ src/Explorer/OpenActionsStubs.ts
src/Explorer/Panes/AddDatabasePane.ts
src/Explorer/Panes/AddDatabasePane.test.ts
src/Explorer/Panes/BrowseQueriesPane.ts
src/Explorer/Panes/ContextualPaneBase.ts
# src/Explorer/Panes/GraphStylingPane.ts
# src/Explorer/Panes/NewVertexPane.ts
src/Explorer/Panes/RenewAdHocAccessPane.ts
src/Explorer/Panes/SetupNotebooksPane.ts
src/Explorer/Panes/SwitchDirectoryPane.ts

View File

@@ -92,11 +92,11 @@ jobs:
name: dist
path: dist/
- name: Upload build to preview blob storage
run: az storage blob upload-batch -d '$web' -s 'dist' --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --destination-path "${{github.event.pull_request.head.sha}}" --account-key="${PREVIEW_STORAGE_KEY}"
run: az storage blob upload-batch -d '$web' -s 'dist' --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --destination-path "${{github.event.pull_request.head.sha || github.sha}}" --account-key="${PREVIEW_STORAGE_KEY}"
env:
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
- name: Upload preview config to blob storage
run: az storage blob upload -c '$web' -f ./preview/config.json --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --name "${{github.event.pull_request.head.sha}}/config.json" --account-key="${PREVIEW_STORAGE_KEY}"
run: az storage blob upload -c '$web' -f ./preview/config.json --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --name "${{github.event.pull_request.head.sha || github.sha}}/config.json" --account-key="${PREVIEW_STORAGE_KEY}"
env:
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
endtoendemulator:

View File

@@ -7,7 +7,7 @@ on:
workflow_dispatch:
schedule:
# Once every hour
- cron: "0 * * * *"
- cron: "0 15 * * *"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:

View File

@@ -3085,3 +3085,7 @@ settings-pane {
padding-left: @SmallSpace;
}
}
.hiddenMain {
display: none;
height: 0px;
}

View File

@@ -3,6 +3,7 @@
.resourceTree {
height: 100%;
width: 20%;
flex: 0 0 auto;
.main {
height: 100%;

View File

@@ -1,3 +1,4 @@
{
"PROXY_PATH": "/proxy"
"PROXY_PATH": "/proxy",
"msalRedirectURI": "https://cosmos-explorer-preview.azurewebsites.net/"
}

View File

@@ -62,6 +62,17 @@ app.get("/pull/:pr(\\d+)", (req, res) => {
})
.catch(() => res.sendStatus(500));
});
app.get("/", (req, res) => {
fetch("https://api.github.com/repos/Azure/cosmos-explorer/branches/master")
.then((response) => response.json())
.then(({ commit: { sha } }) => {
const explorer = new URL(
"https://cosmos-explorer-preview.azurewebsites.net/commit/" + sha + "/hostedExplorer.html"
);
return res.redirect(explorer.href);
})
.catch(() => res.sendStatus(500));
});
app.listen(port, () => {
console.log(`Example app listening on port: ${port}`);

View File

@@ -0,0 +1,36 @@
import React, { FunctionComponent } from "react";
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
import { userContext } from "../UserContext";
export interface CollapsedResourceTreeProps {
toggleLeftPaneExpanded: () => void;
isLeftPaneExpanded: boolean;
}
export const CollapsedResourceTree: FunctionComponent<CollapsedResourceTreeProps> = ({
toggleLeftPaneExpanded,
isLeftPaneExpanded,
}: CollapsedResourceTreeProps): JSX.Element => {
return (
<div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}>
<div className="main-nav nav">
<ul className="nav">
<li
className="resourceTreeCollapse"
id="collapseToggleLeftPaneButton"
role="button"
tabIndex={0}
aria-label="Expand Tree"
>
<span className="leftarrowCollapsed" onClick={toggleLeftPaneExpanded}>
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
</span>
<span className="collectionCollapsed" onClick={toggleLeftPaneExpanded}>
<span>{userContext.apiType} API</span>
</span>
</li>
</ul>
</div>
</div>
);
};

View File

@@ -83,7 +83,7 @@ export function client(): Cosmos.CosmosClient {
if (_client) return _client;
const options: Cosmos.CosmosClientOptions = {
endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
...(!userContext.features.enableAadDataPlane && { key: userContext.masterKey }),
key: userContext.masterKey,
tokenProvider,
connectionPolicy: {
enableEndpointDiscovery: false,

View File

@@ -0,0 +1,17 @@
import { userContext } from "../UserContext";
function isVirtualNetworkFilterEnabled() {
return userContext.databaseAccount?.properties?.isVirtualNetworkFilterEnabled;
}
function isIpRulesEnabled() {
return userContext.databaseAccount?.properties?.ipRules?.length > 0;
}
function isPrivateEndpointConnectionsEnabled() {
return userContext.databaseAccount?.properties?.privateEndpointConnections?.length > 0;
}
export function isPublicInternetAccessAllowed(): boolean {
return !isVirtualNetworkFilterEnabled() && !isIpRulesEnabled() && !isPrivateEndpointConnectionsEnabled();
}

View File

@@ -0,0 +1,59 @@
import React, { FunctionComponent } from "react";
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
import refreshImg from "../../images/refresh-cosmos.svg";
import { AuthType } from "../AuthType";
import { userContext } from "../UserContext";
export interface ResourceTreeProps {
toggleLeftPaneExpanded: () => void;
isLeftPaneExpanded: boolean;
}
export const ResourceTree: FunctionComponent<ResourceTreeProps> = ({
toggleLeftPaneExpanded,
isLeftPaneExpanded,
}: ResourceTreeProps): JSX.Element => {
return (
<div id="main" className={isLeftPaneExpanded ? "main" : "hiddenMain"}>
{/* Collections Window - - Start */}
<div id="mainslide" className="flexContainer">
{/* Collections Window Title/Command Bar - Start */}
<div className="collectiontitle">
<div className="coltitle">
<span className="titlepadcol">{userContext.apiType} API</span>
<div className="float-right">
<span
className="padimgcolrefresh"
data-test="refreshTree"
role="button"
data-bind="click: onRefreshResourcesClick, clickBubble: false, event: { keypress: onRefreshDatabasesKeyPress }"
tabIndex={0}
aria-label="Refresh tree"
title="Refresh tree"
>
<img className="refreshcol" src={refreshImg} alt="Refresh Tree" />
</span>
<span
className="padimgcolrefresh1"
id="expandToggleLeftPaneButton"
role="button"
onClick={toggleLeftPaneExpanded}
tabIndex={0}
aria-label="Collapse Tree"
title="Collapse Tree"
>
<img className="refreshcol1" src={arrowLeftImg} alt="Hide" />
</span>
</div>
</div>
</div>
{userContext.authType === AuthType.ResourceToken ? (
<div style={{ overflowY: "auto" }} data-bind="react:resourceTreeForResourceToken" />
) : (
<div style={{ overflowY: "auto" }} data-bind="react:resourceTree" />
)}
</div>
{/* Collections Window - End */}
</div>
);
};

View File

@@ -28,6 +28,7 @@ export interface ConfigContext {
armAPIVersion?: string;
allowedJunoOrigins: string[];
enableSchemaAnalyzer: boolean;
msalRedirectURI?: string;
}
// Default configuration

View File

@@ -22,6 +22,7 @@ export interface DatabaseAccountExtendedProperties {
enableAnalyticalStorage?: boolean;
isVirtualNetworkFilterEnabled?: boolean;
ipRules?: IpRule[];
privateEndpointConnections?: unknown[];
}
export interface DatabaseAccountResponseLocation {
@@ -391,16 +392,6 @@ export interface GeospatialConfig {
type: string;
}
export interface GatewayDatabaseAccount {
MediaLink: string;
DatabasesLink: string;
MaxMediaStorageUsageInMB: number;
CurrentMediaStorageUsageInMB: number;
EnableMultipleWriteLocations?: boolean;
WritableLocations: RegionEndpoint[];
ReadableLocations: RegionEndpoint[];
}
export interface RegionEndpoint {
name: string;
documentAccountEndpoint: string;
@@ -421,13 +412,6 @@ export interface AccountKeys {
secondaryReadonlyMasterKey: string;
}
export interface AfecFeature {
id: string;
name: string;
properties: { state: string };
type: string;
}
export interface OperationStatus {
status: string;
id?: string;
@@ -507,91 +491,6 @@ export interface MongoParameters extends RpParameters {
analyticalStorageTtl?: number;
}
export interface SparkClusterLibrary {
name: string;
}
export interface Library extends SparkClusterLibrary {
properties: {
kind: "Jar";
source: {
kind: "HttpsUri";
uri: string;
libraryFileName: string;
};
};
}
export interface LibraryFeedResponse {
value: Library[];
}
export interface ArmResource {
id: string;
location: string;
name: string;
type: string;
tags: { [key: string]: string };
}
export interface ArcadiaWorkspaceIdentity {
type: string;
principalId: string;
tenantId: string;
}
export interface ArcadiaWorkspaceProperties {
managedResourceGroupName: string;
provisioningState: string;
sqlAdministratorLogin: string;
connectivityEndpoints: {
artifacts: string;
dev: string;
spark: string;
sql: string;
web: string;
};
defaultDataLakeStorage: {
accountUrl: string;
filesystem: string;
};
}
export interface ArcadiaWorkspaceFeedResponse {
value: ArcadiaWorkspace[];
}
export interface ArcadiaWorkspace extends ArmResource {
identity: ArcadiaWorkspaceIdentity;
properties: ArcadiaWorkspaceProperties;
}
export interface SparkPoolFeedResponse {
value: SparkPool[];
}
export interface SparkPoolProperties {
creationDate: string;
sparkVersion: string;
nodeCount: number;
nodeSize: string;
nodeSizeFamily: string;
provisioningState: string;
autoScale: {
enabled: boolean;
minNodeCount: number;
maxNodeCount: number;
};
autoPause: {
enabled: boolean;
delayInMinutes: number;
};
}
export interface SparkPool extends ArmResource {
properties: SparkPoolProperties;
}
export interface MemoryUsageInfo {
freeKB: number;
totalKB: number;

View File

@@ -5,7 +5,6 @@ import {
TriggerDefinition,
UserDefinedFunctionDefinition,
} from "@azure/cosmos";
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
import Explorer from "../Explorer/Explorer";
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient";
@@ -15,6 +14,7 @@ import StoredProcedure from "../Explorer/Tree/StoredProcedure";
import Trigger from "../Explorer/Tree/Trigger";
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
import { SelfServeType } from "../SelfServe/SelfServeUtils";
import { CollectionCreationDefaults } from "../UserContext";
import { SqlTriggerResource } from "../Utils/arm/generatedClients/cosmos/types";
import * as DataModels from "./DataModels";
import { SubscriptionType } from "./SubscriptionType";
@@ -276,7 +276,6 @@ export interface TabOptions {
title: string;
tabPath: string;
hashLocation: string;
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]) => void;
isTabsContentExpanded?: ko.Observable<boolean>;
onLoadStartKey?: number;
@@ -411,25 +410,6 @@ export interface SelfServeFrameInputs {
flights?: readonly string[];
}
export interface CollectionCreationDefaults {
storage: string;
throughput: ThroughputDefaults;
}
export interface ThroughputDefaults {
fixed: number;
unlimited:
| number
| {
collectionThreshold: number;
lessThanOrEqualToThreshold: number;
greatThanThreshold: number;
};
unlimitedmax: number;
unlimitedmin: number;
shared: number;
}
export class MonacoEditorSettings {
public readonly language: string;
public readonly readOnly: boolean;

View File

@@ -1,14 +0,0 @@
jest.mock("monaco-editor");
import * as ko from "knockout";
import "./ComponentRegisterer";
describe("Component Registerer", () => {
it("should register json-editor component", () => {
expect(ko.components.isRegistered("json-editor")).toBe(true);
});
it("should register dynamic-list component", () => {
expect(ko.components.isRegistered("dynamic-list")).toBe(true);
});
});

View File

@@ -1,12 +1,8 @@
import * as ko from "knockout";
import { DiffEditorComponent } from "./Controls/DiffEditor/DiffEditorComponent";
import { DynamicListComponent } from "./Controls/DynamicList/DynamicListComponent";
import { EditorComponent } from "./Controls/Editor/EditorComponent";
import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent";
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
ko.components.register("editor", new EditorComponent());
ko.components.register("json-editor", new JsonEditorComponent());
ko.components.register("diff-editor", new DiffEditorComponent());
ko.components.register("dynamic-list", DynamicListComponent);
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);

View File

@@ -11,12 +11,12 @@ import DeleteUDFIcon from "../../images/DeleteUDF.svg";
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
import * as ViewModels from "../Contracts/ViewModels";
import { userContext } from "../UserContext";
import { getCollectionName, getDatabaseName } from "../Utils/APITypeUtils";
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
import Explorer from "./Explorer";
import StoredProcedure from "./Tree/StoredProcedure";
import Trigger from "./Tree/Trigger";
import UserDefinedFunction from "./Tree/UserDefinedFunction";
export interface CollectionContextMenuButtonParams {
databaseId: string;
collectionId: string;
@@ -34,7 +34,7 @@ export class ResourceTreeContextMenuButtonFactory {
{
iconSrc: AddCollectionIcon,
onClick: () => container.onNewCollectionClicked(databaseId),
label: container.addCollectionText(),
label: `New ${getCollectionName()}`,
},
];
@@ -42,7 +42,7 @@ export class ResourceTreeContextMenuButtonFactory {
items.push({
iconSrc: DeleteDatabaseIcon,
onClick: () => container.openDeleteDatabaseConfirmationPane(),
label: container.deleteDatabaseText(),
label: `Delete ${getDatabaseName()}`,
styleClass: "deleteDatabaseMenuItem",
});
}
@@ -115,7 +115,7 @@ export class ResourceTreeContextMenuButtonFactory {
items.push({
iconSrc: DeleteCollectionIcon,
onClick: () => container.openDeleteCollectionConfirmationPane(),
label: container.deleteCollectionText(),
label: `Delete ${getCollectionName()}`,
styleClass: "deleteCollectionMenuItem",
});

View File

@@ -1,142 +0,0 @@
import { DefaultButton, IButtonStyles, IContextualMenuItem, IContextualMenuProps } from "@fluentui/react";
import * as React from "react";
import { getErrorMessage } from "../../../Common/ErrorHandlingUtils";
import * as Logger from "../../../Common/Logger";
import { ArcadiaWorkspace, SparkPool } from "../../../Contracts/DataModels";
export interface ArcadiaMenuPickerProps {
selectText?: string;
disableSubmenu?: boolean;
selectedSparkPool: string;
workspaces: ArcadiaWorkspaceItem[];
onSparkPoolSelect: (
e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
item: IContextualMenuItem
) => boolean | void;
onCreateNewWorkspaceClicked: () => boolean | void;
onCreateNewSparkPoolClicked: (workspaceResourceId: string) => boolean | void;
}
interface ArcadiaMenuPickerStates {
selectedSparkPool: string;
}
export interface ArcadiaWorkspaceItem extends ArcadiaWorkspace {
sparkPools: SparkPool[];
}
export class ArcadiaMenuPicker extends React.Component<ArcadiaMenuPickerProps, ArcadiaMenuPickerStates> {
constructor(props: ArcadiaMenuPickerProps) {
super(props);
this.state = {
selectedSparkPool: props.selectedSparkPool,
};
}
private _onSparkPoolClicked = (
e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
item: IContextualMenuItem
): boolean | void => {
try {
this.props.onSparkPoolSelect(e, item);
this.setState({
selectedSparkPool: item.text,
});
} catch (error) {
Logger.logError(getErrorMessage(error), "ArcadiaMenuPicker/_onSparkPoolClicked");
throw error;
}
};
private _onCreateNewWorkspaceClicked = (
e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
item: IContextualMenuItem
): boolean | void => {
this.props.onCreateNewWorkspaceClicked();
};
private _onCreateNewSparkPoolClicked = (
e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
item: IContextualMenuItem
): boolean | void => {
this.props.onCreateNewSparkPoolClicked(item.key);
};
public render() {
const { workspaces } = this.props;
let workspaceMenuItems: IContextualMenuItem[] = workspaces.map((workspace) => {
let sparkPoolsMenuProps: IContextualMenuProps = {
items: workspace.sparkPools.map(
(sparkpool): IContextualMenuItem => ({
key: sparkpool.id,
text: sparkpool.name,
onClick: this._onSparkPoolClicked,
})
),
};
if (!sparkPoolsMenuProps.items.length) {
sparkPoolsMenuProps.items.push({
key: workspace.id,
text: "Create new spark pool",
onClick: this._onCreateNewSparkPoolClicked,
});
}
return {
key: workspace.id,
text: workspace.name,
subMenuProps: this.props.disableSubmenu ? undefined : sparkPoolsMenuProps,
};
});
if (!workspaceMenuItems.length) {
workspaceMenuItems.push({
key: "create_workspace",
text: "Create new workspace",
onClick: this._onCreateNewWorkspaceClicked,
});
}
const dropdownStyle: IButtonStyles = {
root: {
backgroundColor: "transparent",
margin: "auto 5px",
padding: "0",
border: "0",
},
rootHovered: {
backgroundColor: "transparent",
},
rootChecked: {
backgroundColor: "transparent",
},
rootFocused: {
backgroundColor: "transparent",
},
rootExpanded: {
backgroundColor: "transparent",
},
flexContainer: {
height: "30px",
border: "1px solid #a6a6a6",
padding: "0 8px",
},
label: {
fontWeight: "400",
fontSize: "12px",
},
};
return (
<DefaultButton
text={this.state.selectedSparkPool || this.props.selectText || "Select a Spark pool"}
persistMenu={true}
className="arcadia-menu-picker"
menuProps={{
items: workspaceMenuItems,
}}
styles={dropdownStyle}
/>
);
}
}

View File

@@ -1,15 +1,12 @@
import * as StringUtils from "../../../Utils/StringUtils";
import { KeyCodes } from "../../../Common/Constants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import CollapseChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
/**
* React component for Command button component.
*/
import * as React from "react";
import { ArcadiaMenuPickerProps } from "../Arcadia/ArcadiaMenuPicker";
import CollapseChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
import { KeyCodes } from "../../../Common/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import * as StringUtils from "../../../Utils/StringUtils";
/**
* Options for this component
@@ -114,15 +111,6 @@ export interface CommandButtonComponentProps {
* Aria-label for the button
*/
ariaLabel: string;
//TODO: generalize customized command bar
/**
* If set to true, will render arcadia picker
*/
isArcadiaPicker?: boolean;
/**
* props to render arcadia picker
*/
arcadiaProps?: ArcadiaMenuPickerProps;
}
export class CommandButtonComponent extends React.Component<CommandButtonComponentProps> {

View File

@@ -1,64 +0,0 @@
import * as ko from "knockout";
import { DynamicListComponent, DynamicListParams, DynamicListItem } from "./DynamicListComponent";
const $ = (selector: string) => document.querySelector(selector) as HTMLElement;
function buildComponent(buttonOptions: any) {
document.body.innerHTML = DynamicListComponent.template as any;
const vm = new DynamicListComponent.viewModel(buttonOptions);
ko.applyBindings(vm);
}
describe("Dynamic List Component", () => {
const mockPlaceHolder = "Write here";
const mockButton = "Add something";
const mockValue = "/someText";
const mockAriaLabel = "Add ariaLabel";
const items: ko.ObservableArray<DynamicListItem> = ko.observableArray<DynamicListItem>();
function buildListOptions(
items: ko.ObservableArray<DynamicListItem>,
placeholder?: string,
mockButton?: string
): DynamicListParams {
return {
placeholder: placeholder,
listItems: items,
buttonText: mockButton,
ariaLabel: mockAriaLabel,
};
}
afterEach(() => {
ko.cleanNode(document);
});
describe("Rendering", () => {
it("should display button text", () => {
const params = buildListOptions(items, mockPlaceHolder, mockButton);
buildComponent(params);
expect($(".dynamicListItemAdd").textContent).toContain(mockButton);
});
});
describe("Behavior", () => {
it("should add items to the list", () => {
const params = buildListOptions(items, mockPlaceHolder, mockButton);
buildComponent(params);
$(".dynamicListItemAdd").click();
expect(items().length).toBe(1);
const input = document.getElementsByClassName("dynamicListItem").item(0).children[0];
input.setAttribute("value", mockValue);
input.dispatchEvent(new Event("change"));
input.dispatchEvent(new Event("blur"));
expect(items()[0].value()).toBe(mockValue);
});
it("should remove items from the list", () => {
const params = buildListOptions(items, mockPlaceHolder);
buildComponent(params);
$(".dynamicListItemDelete").click();
expect(items().length).toBe(0);
});
});
});

View File

@@ -1,59 +0,0 @@
@import "../../../../less/Common/Constants";
.dynamicList {
width: 100%;
.dynamicListContainer {
.dynamicListItem {
justify-content: space-around;
margin-bottom: @MediumSpace;
input {
width: @newCollectionPaneInputWidth;
margin: auto;
font-size: @mediumFontSize;
padding: @SmallSpace @DefaultSpace;
color: @BaseDark;
}
.dynamicListItemDelete {
padding: @SmallSpace @SmallSpace @DefaultSpace;
margin-left: @SmallSpace;
&:hover {
.hover();
}
&:active {
.active();
}
img {
.dataExplorerIcons();
}
}
}
}
.dynamicListItemNew {
margin-top: @LargeSpace;
.dynamicListItemAdd {
padding: @DefaultSpace;
cursor: pointer;
&:hover {
.hover();
}
&:active {
.active();
}
img {
.dataExplorerIcons();
margin: 0px @SmallSpace @SmallSpace 0px;
}
}
}
}

View File

@@ -1,117 +0,0 @@
/**
* Dynamic list:
*
* Creates a list of dynamic inputs that can be populated and deleted.
*
* How to use in your markup:
* <dynamic-list params="{ listItems: anObservableArrayOfDynamicListItem, placeholder: 'Text to display in placeholder', ariaLabel: 'Text for aria-label', buttonText: 'Add item' }">
* </dynamic-list>
*
*/
import * as ko from "knockout";
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
import { KeyCodes } from "../../../Common/Constants";
import template from "./dynamic-list.html";
/**
* Parameters for this component
*/
export interface DynamicListParams {
/**
* Observable list of items to update
*/
listItems: ko.ObservableArray<DynamicListItem>;
/**
* Placeholder text to use on inputs
*/
placeholder?: string;
/**
* Text to use as aria-label
*/
ariaLabel: string;
/**
* Text for the button to add items
*/
buttonText?: string;
/**
* Callback triggered when the template is bound to the component (for testing purposes)
*/
onTemplateReady?: () => void;
}
/**
* Item in the dynamic list
*/
export interface DynamicListItem {
value: ko.Observable<string>;
}
export class DynamicListViewModel extends WaitsForTemplateViewModel {
public placeholder: string;
public ariaLabel: string;
public buttonText: string;
public newItem: ko.Observable<string>;
public isTemplateReady: ko.Observable<boolean>;
public listItems: ko.ObservableArray<DynamicListItem>;
public constructor(options: DynamicListParams) {
super();
super.onTemplateReady((isTemplateReady: boolean) => {
if (isTemplateReady && options.onTemplateReady) {
options.onTemplateReady();
}
});
const params: DynamicListParams = options;
const paramsPlaceholder: string = params.placeholder;
const paramsButtonText: string = params.buttonText;
this.placeholder = paramsPlaceholder || "Write a value";
this.ariaLabel = "Unique keys";
this.buttonText = paramsButtonText || "Add item";
this.listItems = params.listItems || ko.observableArray<DynamicListItem>();
this.newItem = ko.observable("");
}
public removeItem = (data: any, event: MouseEvent | KeyboardEvent): void => {
const context = ko.contextFor(event.target as Node);
this.listItems.splice(context.$index(), 1);
document.getElementById("addUniqueKeyBtn").focus();
};
public onRemoveItemKeyPress = (data: any, event: KeyboardEvent, source: any): boolean => {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.removeItem(data, event);
(document.querySelector(".dynamicListItem:last-of-type input") as HTMLElement).focus();
event.stopPropagation();
return false;
}
return true;
};
public addItem(): void {
this.listItems.push({ value: ko.observable("") });
(document.querySelector(".dynamicListItem:last-of-type input") as HTMLElement).focus();
}
public onAddItemKeyPress = (source: any, event: KeyboardEvent): boolean => {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.addItem();
event.stopPropagation();
return false;
}
return true;
};
}
/**
* Helper class for ko component registration
*/
export const DynamicListComponent = {
viewModel: DynamicListViewModel,
template,
};

View File

@@ -1,34 +0,0 @@
<div class="dynamicList" data-bind="setTemplateReady: true">
<div class="dynamicListContainer" data-bind="foreach: listItems">
<div class="dynamicListItem">
<input
id="uniqueKeyItems"
type="text"
autocomplete="off"
data-bind="value: value, attr: {placeholder: $parent.placeholder, 'aria-label': $parent.ariaLabel}"
/>
<span
class="dynamicListItemDelete"
title="Remove item"
role="button"
aria-label="Remove item"
tabindex="0"
data-bind="click: $parent.removeItem, event: { keydown: $parent.onRemoveItemKeyPress }"
>
<img src="/delete.svg" alt="Remove item" />
</span>
</div>
</div>
<div class="dynamicListItemNew">
<span
class="dynamicListItemAdd"
id="addUniqueKeyBtn"
role="button"
aria-label="Add unique key"
tabindex="0"
data-bind="click: addItem, event: { keydown: onAddItemKeyPress }"
>
<img src="/Add-property.svg" data-bind="attr: {alt: buttonText}" /> <span data-bind="text: buttonText"></span>
</span>
</div>
</div>

View File

@@ -39,7 +39,6 @@ describe("SettingsComponent", () => {
tabPath: "",
node: undefined,
hashLocation: "settings",
onUpdateTabsButtons: undefined,
}),
};

View File

@@ -18,6 +18,7 @@ import { MongoDBCollectionResource, MongoIndex } from "../../../Utils/arm/genera
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer";
import { useCommandBar } from "../../Menus/CommandBar/CommandBarComponentAdapter";
import { SettingsTabV2 } from "../../Tabs/SettingsTabV2";
import "./SettingsComponent.less";
import { mongoIndexingPolicyAADError } from "./SettingsRenderUtils";
@@ -222,13 +223,13 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
this.setAutoPilotStates();
this.setBaseline();
if (this.props.settingsTab.isActive()) {
this.props.settingsTab.getContainer().onUpdateTabsButtons(this.getTabsButtons());
useCommandBar.getState().setContextButtons(this.getTabsButtons());
}
}
componentDidUpdate(): void {
if (this.props.settingsTab.isActive()) {
this.props.settingsTab.getContainer().onUpdateTabsButtons(this.getTabsButtons());
useCommandBar.getState().setContextButtons(this.getTabsButtons());
}
}

View File

@@ -4,7 +4,7 @@ import { ThroughputInput } from "./ThroughputInput";
const props = {
isDatabase: false,
showFreeTierExceedThroughputTooltip: true,
isSharded: false,
isSharded: true,
setThroughputValue: () => jest.fn(),
setIsAutoscale: () => jest.fn(),
onCostAcknowledgeChange: () => jest.fn(),

View File

@@ -41,9 +41,16 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
throughputHeaderText = AutoPilotUtils.getAutoPilotHeaderText().toLocaleLowerCase();
} else {
const minRU: string = SharedConstants.CollectionCreation.DefaultCollectionRUs400.toLocaleString();
const maxRU: string = userContext.isTryCosmosDBSubscription
? Constants.TryCosmosExperience.maxRU.toLocaleString()
: "unlimited";
let maxRU: string;
if (userContext.isTryCosmosDBSubscription) {
maxRU = Constants.TryCosmosExperience.maxRU.toLocaleString();
} else if (!isSharded) {
maxRU = "10000";
} else {
maxRU = "unlimited";
}
throughputHeaderText = `throughput (${minRU} - ${maxRU} RU/s)`;
}
return `${isDatabase ? "Database" : getCollectionName()} ${throughputHeaderText}`;

View File

@@ -1,308 +0,0 @@
import * as ko from "knockout";
import { KeyCodes } from "../../../Common/Constants";
import * as ViewModels from "../../../Contracts/ViewModels";
import { FreeTierLimits } from "../../../Shared/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
import ThroughputInputComponentAutoscaleV3 from "./ThroughputInputComponentAutoscaleV3.html";
/**
* Throughput Input:
*
* Creates a set of controls to input, sanitize and increase/decrease throughput
*
* How to use in your markup:
* <throughput-input params="{ value: anObservableToHoldTheValue, minimum: anObservableWithMinimum, maximum: anObservableWithMaximum }">
* </throughput-input>
*
*/
/**
* Parameters for this component
*/
export interface ThroughputInputParams {
/**
* Callback triggered when the template is bound to the component (for testing purposes)
*/
onTemplateReady?: () => void;
/**
* Observable to bind the Throughput value to
*/
value: ViewModels.Editable<number>;
/**
* Text to use as id for testing
*/
testId: string;
/**
* Text to use as aria-label
*/
ariaLabel?: ko.Observable<string>;
/**
* Minimum value in the range
*/
minimum: ko.Observable<number>;
/**
* Maximum value in the range
*/
maximum: ko.Observable<number>;
/**
* Step value for increase/decrease
*/
step?: number;
/**
* Observable to bind the Throughput enabled status
*/
isEnabled?: ko.Observable<boolean>;
/**
* Should show pricing controls
*/
costsVisible: ko.Observable<boolean>;
/**
* RU price
*/
requestUnitsUsageCost: ko.Computed<string>; // Our code assigns to ko.Computed, but unit test assigns to ko.Observable
/**
* State of the spending acknowledge checkbox
*/
spendAckChecked?: ko.Observable<boolean>;
/**
* id of the spending acknowledge checkbox
*/
spendAckId?: ko.Observable<string>;
/**
* spending acknowledge text
*/
spendAckText?: ko.Observable<string>;
/**
* Show spending acknowledge controls
*/
spendAckVisible?: ko.Observable<boolean>;
/**
* Display * to the left of the label
*/
showAsMandatory: boolean;
/**
* If true, it will display a text to prompt users to use unlimited collections to go beyond max for fixed
*/
isFixed: boolean;
/**
* Label of the provisioned throughut control
*/
label: ko.Observable<string>;
/**
* Text of the info bubble for provisioned throughut control
*/
infoBubbleText?: ko.Observable<string>;
/**
* Computed value that decides if value can exceed maximum allowable value
*/
canExceedMaximumValue?: ko.Computed<boolean>;
/**
* CSS classes to apply on input element
*/
cssClass?: string;
isAutoPilotSelected: ko.Observable<boolean>;
throughputAutoPilotRadioId: string;
throughputProvisionedRadioId: string;
throughputModeRadioName: string;
maxAutoPilotThroughputSet: ViewModels.Editable<number>;
autoPilotUsageCost: ko.Computed<string>;
overrideWithAutoPilotSettings: ko.Observable<boolean>;
overrideWithProvisionedThroughputSettings: ko.Observable<boolean>;
freeTierExceedThroughputTooltip?: ko.Observable<string>;
freeTierExceedThroughputWarning?: ko.Observable<string>;
}
export class ThroughputInputViewModel extends WaitsForTemplateViewModel {
public ariaLabel: ko.Observable<string>;
public canExceedMaximumValue: ko.Computed<boolean>;
public step: ko.Computed<number>;
public testId: string;
public value: ViewModels.Editable<number>;
public minimum: ko.Observable<number>;
public maximum: ko.Observable<number>;
public isEnabled: ko.Observable<boolean>;
public cssClass: string;
public decreaseButtonAriaLabel: string;
public increaseButtonAriaLabel: string;
public costsVisible: ko.Observable<boolean>;
public requestUnitsUsageCost: ko.Computed<string>;
public spendAckChecked: ko.Observable<boolean>;
public spendAckId: ko.Observable<string>;
public spendAckText: ko.Observable<string>;
public spendAckVisible: ko.Observable<boolean>;
public showAsMandatory: boolean;
public infoBubbleText: string | ko.Observable<string>;
public label: ko.Observable<string>;
public isFixed: boolean;
public isAutoPilotSelected: ko.Observable<boolean>;
public throughputAutoPilotRadioId: string;
public throughputProvisionedRadioId: string;
public throughputModeRadioName: string;
public maxAutoPilotThroughputSet: ko.Observable<number>;
public autoPilotUsageCost: ko.Computed<string>;
public minAutoPilotThroughput: ko.Observable<number>;
public overrideWithAutoPilotSettings: ko.Observable<boolean>;
public overrideWithProvisionedThroughputSettings: ko.Observable<boolean>;
public isManualThroughputInputFieldRequired: ko.Computed<boolean>;
public isAutoscaleThroughputInputFieldRequired: ko.Computed<boolean>;
public freeTierExceedThroughputTooltip: ko.Observable<string>;
public freeTierExceedThroughputWarning: ko.Observable<string>;
public showFreeTierExceedThroughputTooltip: ko.Computed<boolean>;
public showFreeTierExceedThroughputWarning: ko.Computed<boolean>;
public constructor(options: ThroughputInputParams) {
super();
super.onTemplateReady((isTemplateReady: boolean) => {
if (isTemplateReady && options.onTemplateReady) {
options.onTemplateReady();
}
});
const params: ThroughputInputParams = options;
this.testId = params.testId || "ThroughputValue";
this.ariaLabel = ko.observable((params.ariaLabel && params.ariaLabel()) || "");
this.canExceedMaximumValue = params.canExceedMaximumValue || ko.computed(() => false);
this.isEnabled = params.isEnabled || ko.observable(true);
this.cssClass = params.cssClass || "textfontclr collid migration";
this.minimum = params.minimum;
this.maximum = params.maximum;
this.value = params.value;
this.costsVisible = options.costsVisible;
this.requestUnitsUsageCost = options.requestUnitsUsageCost;
this.spendAckChecked = options.spendAckChecked || ko.observable<boolean>(false);
this.spendAckId = options.spendAckId || ko.observable<string>();
this.spendAckText = options.spendAckText || ko.observable<string>();
this.spendAckVisible = options.spendAckVisible || ko.observable<boolean>(false);
this.showAsMandatory = !!options.showAsMandatory;
this.isFixed = !!options.isFixed;
this.infoBubbleText = options.infoBubbleText || ko.observable<string>();
this.label = options.label || ko.observable<string>();
this.isAutoPilotSelected = options.isAutoPilotSelected || ko.observable<boolean>(false);
this.isAutoPilotSelected.subscribe((value) => {
TelemetryProcessor.trace(Action.ToggleAutoscaleSetting, ActionModifiers.Mark, {
changedSelectedValueTo: value ? ActionModifiers.ToggleAutoscaleOn : ActionModifiers.ToggleAutoscaleOff,
dataExplorerArea: "Scale Tab V1",
});
});
this.throughputAutoPilotRadioId = options.throughputAutoPilotRadioId;
this.throughputProvisionedRadioId = options.throughputProvisionedRadioId;
this.throughputModeRadioName = options.throughputModeRadioName;
this.overrideWithAutoPilotSettings = options.overrideWithAutoPilotSettings || ko.observable<boolean>(false);
this.overrideWithProvisionedThroughputSettings =
options.overrideWithProvisionedThroughputSettings || ko.observable<boolean>(false);
this.maxAutoPilotThroughputSet =
options.maxAutoPilotThroughputSet || ko.observable<number>(AutoPilotUtils.minAutoPilotThroughput);
this.autoPilotUsageCost = options.autoPilotUsageCost;
this.minAutoPilotThroughput = ko.observable<number>(AutoPilotUtils.minAutoPilotThroughput);
this.step = ko.pureComputed(() => {
if (this.isAutoPilotSelected()) {
return AutoPilotUtils.autoPilotIncrementStep;
}
return params.step || ThroughputInputViewModel._defaultStep;
});
this.decreaseButtonAriaLabel = "Decrease throughput by " + this.step().toString();
this.increaseButtonAriaLabel = "Increase throughput by " + this.step().toString();
this.isManualThroughputInputFieldRequired = ko.pureComputed(() => this.isEnabled() && !this.isAutoPilotSelected());
this.isAutoscaleThroughputInputFieldRequired = ko.pureComputed(
() => this.isEnabled() && this.isAutoPilotSelected()
);
this.freeTierExceedThroughputTooltip = options.freeTierExceedThroughputTooltip || ko.observable<string>();
this.freeTierExceedThroughputWarning = options.freeTierExceedThroughputWarning || ko.observable<string>();
this.showFreeTierExceedThroughputTooltip = ko.pureComputed<boolean>(
() => !!this.freeTierExceedThroughputTooltip() && this.value() > FreeTierLimits.RU
);
this.showFreeTierExceedThroughputWarning = ko.pureComputed<boolean>(
() => !!this.freeTierExceedThroughputWarning() && this.value() > FreeTierLimits.RU
);
}
public decreaseThroughput() {
let offerThroughput: number = this._getSanitizedValue();
if (offerThroughput > this.minimum()) {
offerThroughput -= this.step();
if (offerThroughput < this.minimum()) {
offerThroughput = this.minimum();
}
this.value(offerThroughput);
}
}
public increaseThroughput() {
let offerThroughput: number = this._getSanitizedValue();
if (offerThroughput < this.maximum() || this.canExceedMaximumValue()) {
offerThroughput += this.step();
if (offerThroughput > this.maximum() && !this.canExceedMaximumValue()) {
offerThroughput = this.maximum();
}
this.value(offerThroughput);
}
}
public onIncreaseKeyDown = (source: any, event: KeyboardEvent): boolean => {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.increaseThroughput();
event.stopPropagation();
return false;
}
return true;
};
public onDecreaseKeyDown = (source: any, event: KeyboardEvent): boolean => {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.decreaseThroughput();
event.stopPropagation();
return false;
}
return true;
};
private _getSanitizedValue(): number {
let throughput = this.value();
if (this.isAutoPilotSelected()) {
throughput = this.maxAutoPilotThroughputSet();
}
return isNaN(throughput) ? 0 : Number(throughput);
}
private static _defaultStep: number = 100;
}
export const ThroughputInputComponentAutoPilotV3 = {
viewModel: ThroughputInputViewModel,
template: ThroughputInputComponentAutoscaleV3,
};

View File

@@ -1,194 +0,0 @@
<div>
<div>
<p class="pkPadding">
<!-- ko if: showAsMandatory -->
<span class="mandatoryStar">*</span>
<!-- /ko -->
<span data-bind="text: label"></span>
<!-- ko if: infoBubbleText -->
<span class="infoTooltip" role="tooltip" tabindex="0">
<img class="infoImg" src="../../../../images/info-bubble.svg" alt="More information" />
<span data-bind="text: infoBubbleText" class="tooltiptext throughputRuInfo"></span>
</span>
<!-- /ko -->
</p>
</div>
<!-- ko if: !isFixed -->
<div class="throughputModeContainer">
<input
class="throughputModeRadio"
aria-label="Autopilot mode"
type="radio"
role="radio"
tabindex="0"
data-bind="
checked: isAutoPilotSelected,
checkedValue: true,
attr: {
id: throughputAutoPilotRadioId,
name: throughputModeRadioName,
'aria-checked': isAutoPilotSelected() ? 'true' : 'false'
}"
/>
<span
class="throughputModeSpace"
data-bind="
attr: {
for: throughputAutoPilotRadioId
}"
>Autoscale
</span>
<input
class="throughputModeRadio nonFirstRadio"
aria-label="Manual mode"
type="radio"
role="radio"
tabindex="0"
data-bind="
checked: isAutoPilotSelected,
checkedValue: false,
attr: {
id: throughputProvisionedRadioId,
name: throughputModeRadioName,
'aria-checked': !isAutoPilotSelected() ? 'true' : 'false'
}"
/>
<span
class="throughputModeSpace"
data-bind="attr: {
for: throughputProvisionedRadioId
}"
>Manual
</span>
</div>
<!-- /ko -->
<div data-bind="visible: isAutoPilotSelected">
<p>
<span
>Provision maximum RU/s required by this resource. Estimate your required RU/s with
<a target="_blank" href="https://cosmos.azure.com/capacitycalculator/">capacity calculator</a>.</span
>
</p>
<p>
<span>Max RU/s</span>
</p>
<div data-bind="setTemplateReady: true">
<input
data-bind="textInput: overrideWithProvisionedThroughputSettings() ? '' : maxAutoPilotThroughputSet, attr:{
disabled: overrideWithProvisionedThroughputSettings(),
step: step,
'class':'migration collid select-font-size',
min: minAutoPilotThroughput,
'aria-label': 'Max request units per second',
type: isAutoscaleThroughputInputFieldRequired() ? 'number' : 'hidden',
css: {
dirty: maxAutoPilotThroughputSet.editableIsDirty
}
}"
/>
</div>
<p data-bind="visible: overrideWithProvisionedThroughputSettings && !overrideWithProvisionedThroughputSettings()">
<span
data-bind="
html: autoPilotUsageCost"
></span>
</p>
<p
data-bind="visible: costsVisible && overrideWithProvisionedThroughputSettings && !overrideWithProvisionedThroughputSettings()"
>
<span data-bind="html: requestUnitsUsageCost"></span>
</p>
<!-- ko if: spendAckVisible -->
<p class="pkPadding">
<input
type="checkbox"
aria-label="acknowledge spend throughput"
data-bind="
attr: {
title: spendAckText,
id: spendAckId
},
checked: spendAckChecked"
/>
<span data-bind="text: spendAckText, attr: { for: spendAckId }"></span>
</p>
<!-- /ko -->
<!-- ko if: isFixed -->
<p>Choose unlimited storage capacity for more than 10,000 RU/s.</p>
<!-- /ko -->
</div>
<div data-bind="visible: !isAutoPilotSelected()">
<p>
<span
>Estimate your required throughput with
<a target="_blank" href="https://cosmos.azure.com/capacitycalculator/">capacity calculator</a></span
>
</p>
<div class="inputTooltip">
<span
data-bind="text: freeTierExceedThroughputTooltip, visible: showFreeTierExceedThroughputTooltip"
class="inputTooltipText"
></span>
</div>
<div data-bind="setTemplateReady: true">
<input
data-bind="
textInput: overrideWithAutoPilotSettings() ? maxAutoPilotThroughputSet : value,
css: {
dirty: value.editableIsDirty
},
enable: isEnabled,
attr:{
type: isManualThroughputInputFieldRequired() ? 'number' : 'hidden',
'data-test': testId,
'class': cssClass,
step: step,
min: minimum,
max: canExceedMaximumValue() ? null : maximum,
'aria-label': ariaLabel,
disabled: overrideWithAutoPilotSettings(),
required: isManualThroughputInputFieldRequired()
}"
/>
</div>
<div class="freeTierInlineWarning" data-bind="visible: showFreeTierExceedThroughputWarning">
<span class="freeTierWarningIcon"><img src="/warning.svg" alt="Warning" /></span>
<span class="freeTierWarningMessage" data-bind="text: freeTierExceedThroughputWarning"></span>
</div>
<p data-bind="visible: costsVisible">
<span data-bind="html: requestUnitsUsageCost"></span>
</p>
<!-- ko if: spendAckVisible -->
<p class="pkPadding">
<input
type="checkbox"
aria-label="acknowledge spend throughput"
data-bind="
attr: {
title: spendAckText,
id: spendAckId
},
checked: spendAckChecked"
/>
<span data-bind="text: spendAckText, attr: { for: spendAckId }"></span>
</p>
<!-- /ko -->
<!-- ko if: isFixed -->
<p>Choose unlimited storage capacity for more than 10,000 RU/s.</p>
<!-- /ko -->
</div>
</div>

View File

@@ -3,7 +3,7 @@
exports[`ThroughputInput Pane should render Default properly 1`] = `
<ThroughputInput
isDatabase={false}
isSharded={false}
isSharded={true}
onCostAcknowledgeChange={[Function]}
setIsAutoscale={[Function]}
setThroughputValue={[Function]}

View File

@@ -14,7 +14,6 @@ describe("ContainerSampleGenerator", () => {
const createExplorerStub = (database: ViewModels.Database): Explorer => {
const explorerStub = {} as Explorer;
explorerStub.databases = ko.observableArray<ViewModels.Database>([database]);
explorerStub.canExceedMaximumValue = ko.computed<boolean>(() => false);
explorerStub.findDatabaseWithId = () => database;
explorerStub.refreshAllDatabases = () => Q.resolve();
return explorerStub;

View File

@@ -6,44 +6,38 @@ import _ from "underscore";
import { AuthType } from "../AuthType";
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
import * as Constants from "../Common/Constants";
import { ExplorerMetrics, HttpStatusCodes } from "../Common/Constants";
import { ExplorerMetrics } from "../Common/Constants";
import { readCollection } from "../Common/dataAccess/readCollection";
import { readDatabases } from "../Common/dataAccess/readDatabases";
import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility";
import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHandlingUtils";
import * as Logger from "../Common/Logger";
import { sendCachedDataMessage } from "../Common/MessageHandler";
import { QueriesClient } from "../Common/QueriesClient";
import { Splitter, SplitterBounds, SplitterDirection } from "../Common/Splitter";
import { configContext, Platform } from "../ConfigContext";
import * as DataModels from "../Contracts/DataModels";
import { MessageTypes } from "../Contracts/ExplorerContracts";
import * as ViewModels from "../Contracts/ViewModels";
import { GitHubClient } from "../GitHub/GitHubClient";
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
import { useSidePanel } from "../hooks/useSidePanel";
import { IGalleryItem, JunoClient } from "../Juno/JunoClient";
import { NotebookWorkspaceManager } from "../NotebookWorkspaceManager/NotebookWorkspaceManager";
import { ResourceProviderClientFactory } from "../ResourceProvider/ResourceProviderClientFactory";
import { RouteHandler } from "../RouteHandlers/RouteHandler";
import { trackEvent } from "../Shared/appInsights";
import * as SharedConstants from "../Shared/Constants";
import { ExplorerSettings } from "../Shared/ExplorerSettings";
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
import { ArcadiaResourceManager } from "../SparkClusterManager/ArcadiaResourceManager";
import { updateUserContext, userContext } from "../UserContext";
import { userContext } from "../UserContext";
import { getCollectionName, getDatabaseName, getUploadName } from "../Utils/APITypeUtils";
import { decryptJWTToken, getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { update } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { stringToBlob } from "../Utils/BlobUtils";
import { isCapabilityEnabled } from "../Utils/CapabilityUtils";
import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils";
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../Utils/NotificationConsoleUtils";
import * as ComponentRegisterer from "./ComponentRegisterer";
import { ArcadiaWorkspaceItem } from "./Controls/Arcadia/ArcadiaMenuPicker";
import { CommandButtonComponentProps } from "./Controls/CommandButton/CommandButtonComponent";
import { DialogProps, TextFieldProps, useDialog } from "./Controls/Dialog";
import { GalleryTab as GalleryTabKind } from "./Controls/NotebookGallery/GalleryViewerComponent";
import { CommandBarComponentAdapter } from "./Menus/CommandBar/CommandBarComponentAdapter";
import { useCommandBar } from "./Menus/CommandBar/CommandBarComponentAdapter";
import { ConsoleData } from "./Menus/NotificationConsole/NotificationConsoleComponent";
import * as FileSystemUtil from "./Notebook/FileSystemUtil";
import { SnapshotRequest } from "./Notebook/NotebookComponent/types";
@@ -55,12 +49,10 @@ import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
import { AddDatabasePanel } from "./Panes/AddDatabasePanel/AddDatabasePanel";
import { BrowseQueriesPane } from "./Panes/BrowseQueriesPane/BrowseQueriesPane";
import { CassandraAddCollectionPane } from "./Panes/CassandraAddCollectionPane/CassandraAddCollectionPane";
import { ContextualPaneBase } from "./Panes/ContextualPaneBase";
import { DeleteCollectionConfirmationPane } from "./Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane";
import { DeleteDatabaseConfirmationPanel } from "./Panes/DeleteDatabaseConfirmationPanel";
import { ExecuteSprocParamsPane } from "./Panes/ExecuteSprocParamsPane/ExecuteSprocParamsPane";
import { GitHubReposPanel } from "./Panes/GitHubReposPanel/GitHubReposPanel";
import { LoadQueryPane } from "./Panes/LoadQueryPane/LoadQueryPane";
import { SaveQueryPane } from "./Panes/SaveQueryPane/SaveQueryPane";
import { SettingsPane } from "./Panes/SettingsPane/SettingsPane";
import { SetupNoteBooksPanel } from "./Panes/SetupNotebooksPanel/SetupNotebooksPanel";
@@ -88,48 +80,29 @@ BindingHandlersRegisterer.registerBindingHandlers();
var tmp = ComponentRegisterer;
export interface ExplorerParams {
setIsNotificationConsoleExpanded: (isExpanded: boolean) => void;
setNotificationConsoleData: (consoleData: ConsoleData) => void;
setInProgressConsoleDataIdToBeDeleted: (id: string) => void;
openSidePanel: (headerText: string, panelContent: JSX.Element, onClose?: () => void) => void;
closeSidePanel: () => void;
tabsManager: TabsManager;
}
export default class Explorer {
public addCollectionText: ko.Observable<string>;
public collectionTitle: ko.Observable<string>;
public deleteCollectionText: ko.Observable<string>;
public deleteDatabaseText: ko.Observable<string>;
public collectionTreeNodeAltText: ko.Observable<string>;
public refreshTreeTitle: ko.Observable<string>;
public collapsedResourceTreeWidth: number = ExplorerMetrics.CollapsedResourceTreeWidth;
public collectionCreationDefaults: ViewModels.CollectionCreationDefaults = SharedConstants.CollectionCreationDefaults;
public isFixedCollectionWithSharedThroughputSupported: ko.Computed<boolean>;
public isServerlessEnabled: ko.Computed<boolean>;
public isAccountReady: ko.Observable<boolean>;
public canSaveQueries: ko.Computed<boolean>;
public features: ko.Observable<any>;
public queriesClient: QueriesClient;
public tableDataClient: TableDataClient;
public splitter: Splitter;
// Notification Console
private setIsNotificationConsoleExpanded: (isExpanded: boolean) => void;
private setNotificationConsoleData: (consoleData: ConsoleData) => void;
private setInProgressConsoleDataIdToBeDeleted: (id: string) => void;
// Panes
public contextPanes: ContextualPaneBase[];
public openSidePanel: (headerText: string, panelContent: JSX.Element, onClose?: () => void) => void;
public closeSidePanel: () => void;
// Resource Tree
public databases: ko.ObservableArray<ViewModels.Database>;
public selectedDatabaseId: ko.Computed<string>;
public selectedCollectionId: ko.Computed<string>;
public isLeftPaneExpanded: ko.Observable<boolean>;
public selectedNode: ko.Observable<ViewModels.TreeNode>;
private resourceTree: ResourceTreeAdapter;
@@ -145,16 +118,10 @@ export default class Explorer {
public isTabsContentExpanded: ko.Observable<boolean>;
public tabsManager: TabsManager;
// Contextual panes
private gitHubClient: GitHubClient;
public gitHubOAuthService: GitHubOAuthService;
public junoClient: JunoClient;
// features
public isPublishNotebookPaneEnabled: ko.Observable<boolean>;
public isHostedDataExplorerEnabled: ko.Computed<boolean>;
public isMongoIndexingEnabled: ko.Observable<boolean>;
public canExceedMaximumValue: ko.Computed<boolean>;
public isSchemaEnabled: ko.Computed<boolean>;
// Notebooks
@@ -163,11 +130,6 @@ export default class Explorer {
public notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>;
public notebookWorkspaceManager: NotebookWorkspaceManager;
public sparkClusterConnectionInfo: ko.Observable<DataModels.SparkClusterConnectionInfo>;
public isSparkEnabled: ko.Observable<boolean>;
public isSparkEnabledForAccount: ko.Observable<boolean>;
public arcadiaToken: ko.Observable<string>;
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
public isSynapseLinkUpdating: ko.Observable<boolean>;
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
public notebookManager?: NotebookManager;
@@ -176,54 +138,25 @@ export default class Explorer {
private _isInitializingNotebooks: boolean;
private notebookBasePath: ko.Observable<string>;
private _arcadiaManager: ArcadiaResourceManager;
private notebookToImport: {
name: string;
content: string;
};
// React adapters
private commandBarComponentAdapter: CommandBarComponentAdapter;
private static readonly MaxNbDatabasesToAutoExpand = 5;
constructor(params?: ExplorerParams) {
this.gitHubClient = new GitHubClient(this.onGitHubClientError);
this.junoClient = new JunoClient();
this.setIsNotificationConsoleExpanded = params?.setIsNotificationConsoleExpanded;
this.setNotificationConsoleData = params?.setNotificationConsoleData;
this.setInProgressConsoleDataIdToBeDeleted = params?.setInProgressConsoleDataIdToBeDeleted;
this.openSidePanel = params?.openSidePanel;
this.closeSidePanel = params?.closeSidePanel;
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
dataExplorerArea: Constants.Areas.ResourceTree,
});
this.addCollectionText = ko.observable<string>("New Collection");
this.collectionTitle = ko.observable<string>("Collections");
this.collectionTreeNodeAltText = ko.observable<string>("Collection");
this.deleteCollectionText = ko.observable<string>("Delete Collection");
this.deleteDatabaseText = ko.observable<string>("Delete Database");
this.refreshTreeTitle = ko.observable<string>("Refresh collections");
this.isAccountReady = ko.observable<boolean>(false);
this._isInitializingNotebooks = false;
this.arcadiaToken = ko.observable<string>();
this.arcadiaToken.subscribe((token: string) => {
if (token) {
const notebookTabs = this.tabsManager.getTabs(ViewModels.CollectionTabKind.NotebookV2);
(notebookTabs || []).forEach((tab: NotebookV2Tab) => {
tab.reconfigureServiceEndpoints();
});
}
});
this.isShellEnabled = ko.observable(false);
this.isNotebooksEnabledForAccount = ko.observable(false);
this.isNotebooksEnabledForAccount.subscribe((isEnabledForAccount: boolean) => this.refreshCommandBarButtons());
this.isSparkEnabledForAccount = ko.observable(false);
this.isSparkEnabledForAccount.subscribe((isEnabledForAccount: boolean) => this.refreshCommandBarButtons());
this.hasStorageAnalyticsAfecFeature = ko.observable(false);
this.hasStorageAnalyticsAfecFeature.subscribe((enabled: boolean) => this.refreshCommandBarButtons());
this.isSynapseLinkUpdating = ko.observable<boolean>(false);
this.isAccountReady.subscribe(async (isAccountReady: boolean) => {
if (isAccountReady) {
@@ -232,63 +165,26 @@ export default class Explorer {
: this.refreshAllDatabases(true);
RouteHandler.getInstance().initHandler();
this.notebookWorkspaceManager = new NotebookWorkspaceManager();
this.arcadiaWorkspaces = ko.observableArray();
this._arcadiaManager = new ArcadiaResourceManager();
this._isAfecFeatureRegistered(Constants.AfecFeatures.StorageAnalytics).then((isRegistered) =>
this.hasStorageAnalyticsAfecFeature(isRegistered)
await this._refreshNotebooksEnabledStateForAccount();
this.isNotebookEnabled(
userContext.authType !== AuthType.ResourceToken &&
((await this._containsDefaultNotebookWorkspace(userContext.databaseAccount)) ||
userContext.features.enableNotebooks)
);
Promise.all([this._refreshNotebooksEnabledStateForAccount(), this._refreshSparkEnabledStateForAccount()]).then(
async () => {
this.isNotebookEnabled(
userContext.authType !== AuthType.ResourceToken &&
((await this._containsDefaultNotebookWorkspace(userContext.databaseAccount)) ||
userContext.features.enableNotebooks)
);
this.isShellEnabled(
this.isNotebookEnabled() &&
!userContext.databaseAccount.properties.isVirtualNetworkFilterEnabled &&
userContext.databaseAccount.properties.ipRules.length === 0
);
TelemetryProcessor.trace(Action.NotebookEnabled, ActionModifiers.Mark, {
isNotebookEnabled: this.isNotebookEnabled(),
dataExplorerArea: Constants.Areas.Notebook,
});
this.isShellEnabled(this.isNotebookEnabled() && isPublicInternetAccessAllowed());
if (this.isNotebookEnabled()) {
await this.initNotebooks(userContext.databaseAccount);
const workspaces = await this._getArcadiaWorkspaces();
this.arcadiaWorkspaces(workspaces);
} else if (this.notebookToImport) {
// if notebooks is not enabled but the user is trying to do a quickstart setup with notebooks, open the SetupNotebooksPane
this._openSetupNotebooksPaneForQuickstart();
}
TelemetryProcessor.trace(Action.NotebookEnabled, ActionModifiers.Mark, {
isNotebookEnabled: this.isNotebookEnabled(),
dataExplorerArea: Constants.Areas.Notebook,
});
this.isSparkEnabled(
(this.isNotebookEnabled() &&
this.isSparkEnabledForAccount() &&
this.arcadiaWorkspaces() &&
this.arcadiaWorkspaces().length > 0) ||
userContext.features.enableSpark
);
if (this.isSparkEnabled()) {
trackEvent(
{ name: "LoadedWithSparkEnabled" },
{
subscriptionId: userContext.subscriptionId,
accountName: userContext.databaseAccount?.name,
accountId: userContext.databaseAccount?.id,
platform: configContext.platform,
}
);
const pollArcadiaTokenRefresh = async () => {
this.arcadiaToken(await this.getArcadiaToken());
setTimeout(() => pollArcadiaTokenRefresh(), this.getTokenRefreshInterval(this.arcadiaToken()));
};
await pollArcadiaTokenRefresh();
}
}
);
if (this.isNotebookEnabled()) {
await this.initNotebooks(userContext.databaseAccount);
} else if (this.notebookToImport) {
// if notebooks is not enabled but the user is trying to do a quickstart setup with notebooks, open the SetupNotebooksPane
this._openSetupNotebooksPaneForQuickstart();
}
}
});
this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>();
@@ -299,11 +195,6 @@ export default class Explorer {
this.resourceTokenCollectionId = ko.observable<string>();
this.resourceTokenCollection = ko.observable<ViewModels.CollectionBase>();
this.resourceTokenPartitionKey = ko.observable<string>();
this.isMongoIndexingEnabled = ko.observable<boolean>(false);
this.isPublishNotebookPaneEnabled = ko.observable<boolean>(false);
this.canExceedMaximumValue = ko.computed<boolean>(() => userContext.features.canExceedMaximumValue);
this.isSchemaEnabled = ko.computed<boolean>(() => userContext.features.enableSchema);
this.databases = ko.observableArray<ViewModels.Database>();
@@ -326,7 +217,6 @@ export default class Explorer {
}
return true;
});
this.isLeftPaneExpanded = ko.observable<boolean>(true);
this.selectedNode = ko.observable<ViewModels.TreeNode>();
this.selectedNode.subscribe((nodeSelected: ViewModels.TreeNode) => {
// Make sure switching tabs restores tabs display
@@ -401,7 +291,7 @@ export default class Explorer {
this.tabsManager.openedTabs.subscribe((tabs) => {
if (tabs.length === 0) {
this.selectedNode(undefined);
this.onUpdateTabsButtons([]);
useCommandBar.getState().setContextButtons([]);
}
});
@@ -420,52 +310,14 @@ export default class Explorer {
});
switch (userContext.apiType) {
case "SQL":
this.addCollectionText("New Container");
this.collectionTitle("SQL API");
this.collectionTreeNodeAltText("Container");
this.deleteCollectionText("Delete Container");
this.deleteDatabaseText("Delete Database");
this.refreshTreeTitle("Refresh containers");
break;
case "Mongo":
this.addCollectionText("New Collection");
this.collectionTitle("Collections");
this.collectionTreeNodeAltText("Collection");
this.deleteCollectionText("Delete Collection");
this.deleteDatabaseText("Delete Database");
this.refreshTreeTitle("Refresh collections");
break;
case "Gremlin":
this.addCollectionText("New Graph");
this.deleteCollectionText("Delete Graph");
this.deleteDatabaseText("Delete Database");
this.collectionTitle("Gremlin API");
this.collectionTreeNodeAltText("Graph");
this.refreshTreeTitle("Refresh graphs");
break;
case "Tables":
this.addCollectionText("New Table");
this.deleteCollectionText("Delete Table");
this.deleteDatabaseText("Delete Database");
this.collectionTitle("Azure Table API");
this.collectionTreeNodeAltText("Table");
this.refreshTreeTitle("Refresh tables");
this.tableDataClient = new TablesAPIDataClient();
break;
case "Cassandra":
this.addCollectionText("New Table");
this.deleteCollectionText("Delete Table");
this.deleteDatabaseText("Delete Keyspace");
this.collectionTitle("Cassandra API");
this.collectionTreeNodeAltText("Table");
this.refreshTreeTitle("Refresh tables");
this.tableDataClient = new CassandraAPIDataClient();
break;
}
this.commandBarComponentAdapter = new CommandBarComponentAdapter(this);
this._initSettings();
TelemetryProcessor.traceSuccess(
@@ -494,8 +346,6 @@ export default class Explorer {
this.refreshNotebookList();
});
this.isSparkEnabled = ko.observable(false);
this.isSparkEnabled.subscribe((isEnabled: boolean) => this.refreshCommandBarButtons());
this.resourceTree = new ResourceTreeAdapter(this);
this.resourceTreeForResourceToken = new ResourceTreeAdapterForResourceToken(this);
this.notebookServerInfo = ko.observable<DataModels.NotebookWorkspaceConnectionInfo>({
@@ -539,23 +389,6 @@ export default class Explorer {
}
}
private onGitHubClientError = (error: any): void => {
Logger.logError(getErrorMessage(error), "NotebookManager/onGitHubClientError");
if (error.status === HttpStatusCodes.Unauthorized) {
this.gitHubOAuthService.resetToken();
this.showOkCancelModalDialog(
undefined,
"Cosmos DB cannot access your Github account anymore. Please connect to GitHub again.",
"Connect to GitHub",
() => this.openGitHubReposPanel("Connect to GitHub"),
"Cancel",
undefined
);
}
};
public openEnableSynapseLinkDialog(): void {
const addSynapseLinkDialogProps: DialogProps = {
linkProps: {
@@ -577,22 +410,17 @@ export default class Explorer {
this.isSynapseLinkUpdating(true);
useDialog.getState().closeDialog();
const resourceProviderClient = new ResourceProviderClientFactory().getOrCreate(userContext.databaseAccount.id);
try {
const databaseAccount: DataModels.DatabaseAccount = await resourceProviderClient.patchAsync(
userContext.databaseAccount.id,
"2019-12-12",
{
properties: {
enableAnalyticalStorage: true,
},
}
);
await update(userContext.subscriptionId, userContext.resourceGroup, userContext.databaseAccount.name, {
properties: {
enableAnalyticalStorage: true,
},
});
clearInProgressMessage();
logConsoleInfo("Enabled Azure Synapse Link for this account");
TelemetryProcessor.traceSuccess(Action.EnableAzureSynapseLink, {}, startTime);
updateUserContext({ databaseAccount });
userContext.databaseAccount.properties.enableAnalyticalStorage = true;
} catch (error) {
clearInProgressMessage();
logConsoleError(`Enabling Azure Synapse Link for this account failed. ${getErrorMessage(error)}`);
@@ -637,22 +465,6 @@ export default class Explorer {
this.setInProgressConsoleDataIdToBeDeleted(id);
}
public expandConsole(): void {
this.setIsNotificationConsoleExpanded(true);
}
public toggleLeftPaneExpanded() {
this.isLeftPaneExpanded(!this.isLeftPaneExpanded());
if (this.isLeftPaneExpanded()) {
document.getElementById("expandToggleLeftPaneButton").focus();
this.splitter.expandLeft();
} else {
document.getElementById("collapseToggleLeftPaneButton").focus();
this.splitter.collapseLeft();
}
}
public refreshDatabaseForResourceToken(): Q.Promise<any> {
const databaseId = this.resourceTokenDatabaseId();
const collectionId = this.resourceTokenCollectionId();
@@ -769,65 +581,11 @@ export default class Explorer {
this.refreshNotebookList();
};
public toggleLeftPaneExpandedKeyPress = (source: any, event: KeyboardEvent): boolean => {
if (event.keyCode === Constants.KeyCodes.Space || event.keyCode === Constants.KeyCodes.Enter) {
this.toggleLeftPaneExpanded();
return false;
}
return true;
};
// Facade
public provideFeedbackEmail = () => {
window.open(Constants.Urls.feedbackEmail, "_blank");
};
public async getArcadiaToken(): Promise<string> {
return new Promise<string>((resolve: (token: string) => void, reject: (error: any) => void) => {
sendCachedDataMessage<string>(MessageTypes.GetArcadiaToken, undefined /** params **/).then(
(token: string) => {
resolve(token);
},
(error: any) => {
Logger.logError(getErrorMessage(error), "Explorer/getArcadiaToken");
resolve(undefined);
}
);
});
}
private async _getArcadiaWorkspaces(): Promise<ArcadiaWorkspaceItem[]> {
try {
const workspaces = await this._arcadiaManager.listWorkspacesAsync([userContext.subscriptionId]);
let workspaceItems: ArcadiaWorkspaceItem[] = new Array(workspaces.length);
const sparkPromises: Promise<void>[] = [];
workspaces.forEach((workspace, i) => {
let promise = this._arcadiaManager.listSparkPoolsAsync(workspaces[i].id).then(
(sparkpools) => {
workspaceItems[i] = { ...workspace, sparkPools: sparkpools };
},
(error) => {
Logger.logError(getErrorMessage(error), "Explorer/this._arcadiaManager.listSparkPoolsAsync");
}
);
sparkPromises.push(promise);
});
return Promise.all(sparkPromises).then(() => workspaceItems);
} catch (error) {
handleError(error, "Explorer/this._arcadiaManager.listWorkspacesAsync", "Get Arcadia workspaces failed");
return Promise.resolve([]);
}
}
public async createWorkspace(): Promise<string> {
return sendCachedDataMessage(MessageTypes.CreateWorkspace, undefined /** params **/);
}
public async createSparkPool(workspaceId: string): Promise<string> {
return sendCachedDataMessage(MessageTypes.CreateSparkPool, [workspaceId]);
}
public async initNotebooks(databaseAccount: DataModels.DatabaseAccount): Promise<void> {
if (!databaseAccount) {
throw new Error("No database account specified");
@@ -1004,9 +762,6 @@ export default class Explorer {
if (process.env.NODE_ENV === "development") {
sessionStorage.setItem("portalDataExplorerInitMessage", JSON.stringify(inputs));
}
if (inputs.defaultCollectionThroughput) {
this.collectionCreationDefaults = inputs.defaultCollectionThroughput;
}
this.isAccountReady(true);
}
}
@@ -1025,10 +780,6 @@ export default class Explorer {
);
}
public onUpdateTabsButtons(buttons: CommandButtonComponentProps[]): void {
this.commandBarComponentAdapter.onUpdateTabsButtons(buttons);
}
private refreshAndExpandNewDatabases(newDatabases: ViewModels.Database[]): Q.Promise<void> {
// we reload collections for all databases so the resource tree reflects any collection-level changes
// i.e addition of stored procedures, etc.
@@ -1227,7 +978,6 @@ export default class Explorer {
onTakeSnapshot,
onClosePanel
);
this.isPublishNotebookPaneEnabled(true);
}
}
@@ -1321,7 +1071,6 @@ export default class Explorer {
hashLocation: "notebooks",
isTabsContentExpanded: ko.observable(true),
onLoadStartKey: null,
onUpdateTabsButtons: this.onUpdateTabsButtons,
container: this,
notebookContentItem,
};
@@ -1356,12 +1105,12 @@ export default class Explorer {
if (openedNotebookTabs.length > 0) {
this.showOkModalDialog("Unable to rename file", "This file is being edited. Please close the tab and try again.");
} else {
this.openSidePanel(
useSidePanel.getState().openSidePanel(
"Rename Notebook",
<StringInputPane
explorer={this}
closePanel={() => {
this.closeSidePanel();
useSidePanel.getState().closeSidePanel();
this.resourceTree.triggerRender();
}}
inputLabel="Enter new notebook name"
@@ -1387,12 +1136,12 @@ export default class Explorer {
throw new Error(error);
}
this.openSidePanel(
useSidePanel.getState().openSidePanel(
"Create new directory",
<StringInputPane
explorer={this}
closePanel={() => {
this.closeSidePanel();
useSidePanel.getState().closeSidePanel();
this.resourceTree.triggerRender();
}}
errorMessage="Could not create directory "
@@ -1506,57 +1255,6 @@ export default class Explorer {
}
}
public _refreshSparkEnabledStateForAccount = async (): Promise<void> => {
const { subscriptionId, authType } = userContext;
const armEndpoint = configContext.ARM_ENDPOINT;
if (!subscriptionId || !armEndpoint || authType === AuthType.EncryptedToken) {
// explorer is not aware of the database account yet
this.isSparkEnabledForAccount(false);
return;
}
const featureUri = `subscriptions/${subscriptionId}/providers/Microsoft.Features/providers/Microsoft.DocumentDb/features/${Constants.AfecFeatures.Spark}`;
const resourceProviderClient = new ResourceProviderClientFactory().getOrCreate(featureUri);
try {
const sparkNotebooksFeature: DataModels.AfecFeature = await resourceProviderClient.getAsync(
featureUri,
Constants.ArmApiVersions.armFeatures
);
const isEnabled =
(sparkNotebooksFeature &&
sparkNotebooksFeature.properties &&
sparkNotebooksFeature.properties.state === "Registered") ||
false;
this.isSparkEnabledForAccount(isEnabled);
} catch (error) {
Logger.logError(getErrorMessage(error), "Explorer/isSparkEnabledForAccount");
this.isSparkEnabledForAccount(false);
}
};
public _isAfecFeatureRegistered = async (featureName: string): Promise<boolean> => {
const { subscriptionId, authType } = userContext;
const armEndpoint = configContext.ARM_ENDPOINT;
if (!featureName || !subscriptionId || !armEndpoint || authType === AuthType.EncryptedToken) {
// explorer is not aware of the database account yet
return false;
}
const featureUri = `subscriptions/${subscriptionId}/providers/Microsoft.Features/providers/Microsoft.DocumentDb/features/${featureName}`;
const resourceProviderClient = new ResourceProviderClientFactory().getOrCreate(featureUri);
try {
const featureStatus: DataModels.AfecFeature = await resourceProviderClient.getAsync(
featureUri,
Constants.ArmApiVersions.armFeatures
);
const isEnabled =
(featureStatus && featureStatus.properties && featureStatus.properties.state === "Registered") || false;
return isEnabled;
} catch (error) {
Logger.logError(getErrorMessage(error), "Explorer/isSparkEnabledForAccount");
return false;
}
};
private refreshNotebookList = async (): Promise<void> => {
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
return;
@@ -1707,7 +1405,6 @@ export default class Explorer {
hashLocation: `${hashLocation} ${index}`,
isTabsContentExpanded: ko.observable(true),
onLoadStartKey: null,
onUpdateTabsButtons: this.onUpdateTabsButtons,
container: this,
kind: kind,
});
@@ -1738,7 +1435,6 @@ export default class Explorer {
title: title,
tabPath: title,
hashLocation: hashLocation,
onUpdateTabsButtons: this.onUpdateTabsButtons,
onLoadStartKey: null,
isTabsContentExpanded: ko.observable(true),
},
@@ -1769,31 +1465,7 @@ export default class Explorer {
if (activeTab) {
activeTab.onActivate(); // TODO only update tabs buttons?
} else {
this.onUpdateTabsButtons([]);
}
}
private getTokenRefreshInterval(token: string): number {
let tokenRefreshInterval = Constants.ClientDefaults.arcadiaTokenRefreshInterval;
if (!token) {
return tokenRefreshInterval;
}
try {
const tokenPayload = decryptJWTToken(this.arcadiaToken());
if (tokenPayload && tokenPayload.hasOwnProperty("exp")) {
const expirationTime = tokenPayload.exp as number; // seconds since unix epoch
const now = new Date().getTime() / 1000;
const tokenExpirationIntervalInMs = (expirationTime - now) * 1000;
if (tokenExpirationIntervalInMs < tokenRefreshInterval) {
tokenRefreshInterval =
tokenExpirationIntervalInMs - Constants.ClientDefaults.arcadiaTokenRefreshIntervalPaddingMs;
}
}
return tokenRefreshInterval;
} catch (error) {
Logger.logError(getErrorMessage(error), "Explorer/getTokenRefreshInterval");
return tokenRefreshInterval;
useCommandBar.getState().setContextButtons([]);
}
}
@@ -1828,11 +1500,6 @@ export default class Explorer {
}
}
public async loadSelectedDatabaseOffer(): Promise<void> {
const database = this.findSelectedDatabase();
await database?.loadOffer();
}
public async loadDatabaseOffers(): Promise<void> {
await Promise.all(
this.databases()?.map(async (database: ViewModels.Database) => {
@@ -1861,160 +1528,115 @@ export default class Explorer {
return false;
});
}
public openDeleteCollectionConfirmationPane(): void {
this.openSidePanel(
"Delete " + getCollectionName(),
<DeleteCollectionConfirmationPane explorer={this} closePanel={this.closeSidePanel} />
);
useSidePanel
.getState()
.openSidePanel("Delete " + getCollectionName(), <DeleteCollectionConfirmationPane explorer={this} />);
}
public openDeleteDatabaseConfirmationPane(): void {
this.openSidePanel(
"Delete " + getDatabaseName(),
<DeleteDatabaseConfirmationPanel
explorer={this}
openNotificationConsole={() => this.expandConsole()}
closePanel={this.closeSidePanel}
selectedDatabase={this.findSelectedDatabase()}
/>
);
useSidePanel
.getState()
.openSidePanel(
"Delete " + getDatabaseName(),
<DeleteDatabaseConfirmationPanel explorer={this} selectedDatabase={this.findSelectedDatabase()} />
);
}
public openUploadItemsPanePane(): void {
this.openSidePanel("Upload " + getUploadName(), <UploadItemsPane explorer={this} />);
useSidePanel.getState().openSidePanel("Upload " + getUploadName(), <UploadItemsPane explorer={this} />);
}
public openSettingPane(): void {
this.openSidePanel(
"Setting",
<SettingsPane expandConsole={() => this.expandConsole()} closePanel={this.closeSidePanel} />
);
}
public openExecuteSprocParamsPanel(storedProcedure: StoredProcedure): void {
this.openSidePanel(
"Input parameters",
<ExecuteSprocParamsPane
storedProcedure={storedProcedure}
expandConsole={() => this.expandConsole()}
closePanel={() => this.closeSidePanel()}
/>
);
useSidePanel
.getState()
.openSidePanel("Input parameters", <ExecuteSprocParamsPane storedProcedure={storedProcedure} />);
}
public async openAddCollectionPanel(databaseId?: string): Promise<void> {
await this.loadDatabaseOffers();
this.openSidePanel(
"New " + getCollectionName(),
<AddCollectionPanel
explorer={this}
closePanel={() => this.closeSidePanel()}
openNotificationConsole={() => this.expandConsole()}
databaseId={databaseId}
/>
);
useSidePanel
.getState()
.openSidePanel("New " + getCollectionName(), <AddCollectionPanel explorer={this} databaseId={databaseId} />);
}
public openAddDatabasePane(): void {
this.openSidePanel(
"New " + getDatabaseName(),
<AddDatabasePanel
explorer={this}
openNotificationConsole={() => this.expandConsole()}
closePanel={this.closeSidePanel}
/>
);
useSidePanel.getState().openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={this} />);
}
public openBrowseQueriesPanel(): void {
this.openSidePanel("Open Saved Queries", <BrowseQueriesPane explorer={this} closePanel={this.closeSidePanel} />);
}
public openLoadQueryPanel(): void {
this.openSidePanel("Load Query", <LoadQueryPane explorer={this} closePanel={() => this.closeSidePanel()} />);
useSidePanel.getState().openSidePanel("Open Saved Queries", <BrowseQueriesPane explorer={this} />);
}
public openSaveQueryPanel(): void {
this.openSidePanel("Save Query", <SaveQueryPane explorer={this} closePanel={() => this.closeSidePanel()} />);
useSidePanel.getState().openSidePanel("Save Query", <SaveQueryPane explorer={this} />);
}
public openUploadFilePanel(parent?: NotebookContentItem): void {
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.openSidePanel(
"Upload file to notebook server",
<UploadFilePane
expandConsole={() => this.expandConsole()}
closePanel={this.closeSidePanel}
uploadFile={(name: string, content: string) => this.uploadFile(name, content, parent)}
/>
);
useSidePanel
.getState()
.openSidePanel(
"Upload file to notebook server",
<UploadFilePane uploadFile={(name: string, content: string) => this.uploadFile(name, content, parent)} />
);
}
public openCassandraAddCollectionPane(): void {
this.openSidePanel(
"Add Table",
<CassandraAddCollectionPane
explorer={this}
closePanel={() => this.closeSidePanel()}
cassandraApiClient={new CassandraAPIDataClient()}
/>
);
useSidePanel
.getState()
.openSidePanel(
"Add Table",
<CassandraAddCollectionPane explorer={this} cassandraApiClient={new CassandraAPIDataClient()} />
);
}
public openGitHubReposPanel(header: string, junoClient?: JunoClient): void {
this.openSidePanel(
header,
<GitHubReposPanel
explorer={this}
closePanel={this.closeSidePanel}
gitHubClientProp={this.notebookManager.gitHubClient}
junoClientProp={junoClient}
openNotificationConsole={() => this.expandConsole()}
/>
);
useSidePanel
.getState()
.openSidePanel(
header,
<GitHubReposPanel
explorer={this}
gitHubClientProp={this.notebookManager.gitHubClient}
junoClientProp={junoClient}
/>
);
}
public openAddTableEntityPanel(queryTablesTab: QueryTablesTab, tableEntityListViewModel: TableListViewModal): void {
this.openSidePanel(
"Add Table Entity",
<AddTableEntityPanel
explorer={this}
closePanel={this.closeSidePanel}
queryTablesTab={queryTablesTab}
tableEntityListViewModel={tableEntityListViewModel}
cassandraApiClient={new CassandraAPIDataClient()}
/>
);
useSidePanel
.getState()
.openSidePanel(
"Add Table Entity",
<AddTableEntityPanel
tableDataClient={this.tableDataClient}
queryTablesTab={queryTablesTab}
tableEntityListViewModel={tableEntityListViewModel}
cassandraApiClient={new CassandraAPIDataClient()}
/>
);
}
public openSetupNotebooksPanel(title: string, description: string): void {
this.openSidePanel(
title,
<SetupNoteBooksPanel
explorer={this}
closePanel={this.closeSidePanel}
openNotificationConsole={() => this.expandConsole()}
panelTitle={title}
panelDescription={description}
/>
);
useSidePanel
.getState()
.openSidePanel(title, <SetupNoteBooksPanel explorer={this} panelTitle={title} panelDescription={description} />);
}
public openEditTableEntityPanel(queryTablesTab: QueryTablesTab, tableEntityListViewModel: TableListViewModal): void {
this.openSidePanel(
"Edit Table Entity",
<EditTableEntityPanel
explorer={this}
closePanel={this.closeSidePanel}
queryTablesTab={queryTablesTab}
tableEntityListViewModel={tableEntityListViewModel}
cassandraApiClient={new CassandraAPIDataClient()}
/>
);
useSidePanel
.getState()
.openSidePanel(
"Edit Table Entity",
<EditTableEntityPanel
tableDataClient={this.tableDataClient}
queryTablesTab={queryTablesTab}
tableEntityListViewModel={tableEntityListViewModel}
cassandraApiClient={new CassandraAPIDataClient()}
/>
);
}
public openTableSelectQueryPanel(queryViewModal: QueryViewModel): void {
this.openSidePanel(
"Select Column",
<TableQuerySelectPanel explorer={this} closePanel={this.closeSidePanel} queryViewModel={queryViewModal} />
);
useSidePanel.getState().openSidePanel("Select Column", <TableQuerySelectPanel queryViewModel={queryViewModal} />);
}
public openSettingPane(): void {
useSidePanel.getState().openSidePanel("Settings", <SettingsPane />);
}
}

View File

@@ -3,103 +3,71 @@
* If the component signals a change through the callback passed in the properties, it must render the React component when appropriate
* and update any knockout observables passed from the parent.
*/
import { CommandBar, ICommandBarItemProps } from "@fluentui/react";
import * as ko from "knockout";
import { CommandBar as FluentCommandBar, ICommandBarItemProps } from "@fluentui/react";
import * as React from "react";
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
import create, { UseStore } from "zustand";
import { StyleConstants } from "../../../Common/Constants";
import * as ViewModels from "../../../Contracts/ViewModels";
import { userContext } from "../../../UserContext";
import { useObservable } from "../../../hooks/useObservable";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer";
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
import * as CommandBarUtil from "./CommandBarUtil";
export class CommandBarComponentAdapter implements ReactAdapter {
public parameters: ko.Observable<number>;
public container: Explorer;
private tabsButtons: CommandButtonComponentProps[];
private isNotebookTabActive: ko.Computed<boolean>;
constructor(container: Explorer) {
this.container = container;
this.tabsButtons = [];
this.isNotebookTabActive = ko.computed(
() => container.tabsManager.activeTab()?.tabKind === ViewModels.CollectionTabKind.NotebookV2
);
// These are the parameters watched by the react binding that will trigger a renderComponent() if one of the ko mutates
const toWatch = [
container.deleteCollectionText,
container.deleteDatabaseText,
container.addCollectionText,
container.isDatabaseNodeOrNoneSelected,
container.isDatabaseNodeSelected,
container.isNoneSelected,
container.isResourceTokenCollectionNodeSelected,
container.isHostedDataExplorerEnabled,
container.isSynapseLinkUpdating,
userContext?.databaseAccount,
this.isNotebookTabActive,
container.isServerlessEnabled,
];
ko.computed(() => ko.toJSON(toWatch)).subscribe(() => this.triggerRender());
this.parameters = ko.observable(Date.now());
}
public onUpdateTabsButtons(buttons: CommandButtonComponentProps[]): void {
this.tabsButtons = buttons;
this.triggerRender();
}
public renderComponent(): JSX.Element {
const backgroundColor = StyleConstants.BaseLight;
const staticButtons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(this.container);
const contextButtons = (this.tabsButtons || []).concat(
CommandBarComponentButtonFactory.createContextCommandBarButtons(this.container)
);
const controlButtons = CommandBarComponentButtonFactory.createControlCommandBarButtons(this.container);
const uiFabricStaticButtons = CommandBarUtil.convertButton(staticButtons, backgroundColor);
if (this.tabsButtons && this.tabsButtons.length > 0) {
uiFabricStaticButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
}
const uiFabricTabsButtons: ICommandBarItemProps[] = CommandBarUtil.convertButton(contextButtons, backgroundColor);
if (uiFabricTabsButtons.length > 0) {
uiFabricStaticButtons.push(CommandBarUtil.createDivider("commandBarDivider"));
}
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
if (this.isNotebookTabActive()) {
uiFabricControlButtons.unshift(
CommandBarUtil.createMemoryTracker("memoryTracker", this.container.memoryUsageInfo)
);
}
return (
<React.Fragment>
<div className="commandBarContainer">
<CommandBar
ariaLabel="Use left and right arrow keys to navigate between commands"
items={uiFabricStaticButtons.concat(uiFabricTabsButtons)}
farItems={uiFabricControlButtons}
styles={{
root: { backgroundColor: backgroundColor },
}}
overflowButtonProps={{ ariaLabel: "More commands" }}
/>
</div>
</React.Fragment>
);
}
private triggerRender() {
window.requestAnimationFrame(() => this.parameters(Date.now()));
}
interface Props {
container: Explorer;
}
export interface CommandBarStore {
contextButtons: CommandButtonComponentProps[];
setContextButtons: (contextButtons: CommandButtonComponentProps[]) => void;
}
export const useCommandBar: UseStore<CommandBarStore> = create((set) => ({
contextButtons: [],
setContextButtons: (contextButtons: CommandButtonComponentProps[]) => set((state) => ({ ...state, contextButtons })),
}));
export const CommandBar: React.FC<Props> = ({ container }: Props) => {
useObservable(container.selectedNode);
const buttons = useCommandBar((state) => state.contextButtons);
const backgroundColor = StyleConstants.BaseLight;
const staticButtons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(container);
const contextButtons = (buttons || []).concat(
CommandBarComponentButtonFactory.createContextCommandBarButtons(container)
);
const controlButtons = CommandBarComponentButtonFactory.createControlCommandBarButtons(container);
const uiFabricStaticButtons = CommandBarUtil.convertButton(staticButtons, backgroundColor);
if (buttons && buttons.length > 0) {
uiFabricStaticButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
}
const uiFabricTabsButtons: ICommandBarItemProps[] = CommandBarUtil.convertButton(contextButtons, backgroundColor);
if (uiFabricTabsButtons.length > 0) {
uiFabricStaticButtons.push(CommandBarUtil.createDivider("commandBarDivider"));
}
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
if (container.tabsManager.activeTab()?.tabKind === ViewModels.CollectionTabKind.NotebookV2) {
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker", container.memoryUsageInfo));
}
return (
<div className="commandBarContainer">
<FluentCommandBar
ariaLabel="Use left and right arrow keys to navigate between commands"
items={uiFabricStaticButtons.concat(uiFabricTabsButtons)}
farItems={uiFabricControlButtons}
styles={{
root: { backgroundColor: backgroundColor },
}}
overflowButtonProps={{ ariaLabel: "More commands" }}
/>
</div>
);
};

View File

@@ -15,7 +15,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
beforeAll(() => {
mockExplorer = {} as Explorer;
mockExplorer.addCollectionText = ko.observable("mockText");
updateUserContext({
databaseAccount: {
properties: {
@@ -23,7 +22,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
},
} as DatabaseAccount,
});
mockExplorer.isSparkEnabled = ko.observable(true);
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
@@ -58,7 +56,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
beforeAll(() => {
mockExplorer = {} as Explorer;
mockExplorer.addCollectionText = ko.observable("mockText");
updateUserContext({
databaseAccount: {
properties: {
@@ -67,7 +64,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
} as DatabaseAccount,
});
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
mockExplorer.isSparkEnabled = ko.observable(true);
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
@@ -126,7 +122,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
beforeAll(() => {
mockExplorer = {} as Explorer;
mockExplorer.addCollectionText = ko.observable("mockText");
updateUserContext({
databaseAccount: {
properties: {
@@ -134,7 +129,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
},
} as DatabaseAccount,
});
mockExplorer.isSparkEnabled = ko.observable(true);
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
@@ -226,7 +220,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
beforeAll(() => {
mockExplorer = {} as Explorer;
mockExplorer.addCollectionText = ko.observable("mockText");
updateUserContext({
databaseAccount: {
properties: {
@@ -235,7 +228,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
} as DatabaseAccount,
});
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
mockExplorer.isSparkEnabled = ko.observable(true);
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
mockExplorer.isServerlessEnabled = ko.computed<boolean>(() => false);
@@ -318,7 +310,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
beforeAll(() => {
mockExplorer = {} as Explorer;
mockExplorer.addCollectionText = ko.observable("mockText");
updateUserContext({
databaseAccount: {
properties: {
@@ -328,7 +319,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
});
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
mockExplorer.isSparkEnabled = ko.observable(true);
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
@@ -380,7 +370,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
describe("Resource token", () => {
beforeAll(() => {
mockExplorer = {} as Explorer;
mockExplorer.addCollectionText = ko.observable("mockText");
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
mockExplorer.isResourceTokenCollectionNodeSelected = ko.computed(() => true);
mockExplorer.isServerlessEnabled = ko.computed<boolean>(() => false);

View File

@@ -21,11 +21,13 @@ import { AuthType } from "../../../AuthType";
import * as Constants from "../../../Common/Constants";
import { configContext, Platform } from "../../../ConfigContext";
import * as ViewModels from "../../../Contracts/ViewModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { userContext } from "../../../UserContext";
import { getDatabaseName } from "../../../Utils/APITypeUtils";
import { getCollectionName, getDatabaseName } from "../../../Utils/APITypeUtils";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer";
import { OpenFullScreen } from "../../OpenFullScreen";
import { LoadQueryPane } from "../../Panes/LoadQueryPane/LoadQueryPane";
let counter = 0;
@@ -152,7 +154,7 @@ export function createControlCommandBarButtons(container: Explorer): CommandButt
{
iconSrc: SettingsIcon,
iconAlt: "Settings",
onCommandClick: () => container.openSettingPane(),
onCommandClick: container.openSettingPane,
commandButtonLabel: undefined,
ariaLabel: "Settings",
tooltipText: "Settings",
@@ -167,7 +169,7 @@ export function createControlCommandBarButtons(container: Explorer): CommandButt
iconSrc: OpenInTabIcon,
iconAlt: label,
onCommandClick: () => {
container.openSidePanel("Open Full Screen", <OpenFullScreen />);
useSidePanel.getState().openSidePanel("Open Full Screen", <OpenFullScreen />);
},
commandButtonLabel: undefined,
ariaLabel: label,
@@ -215,7 +217,7 @@ function areScriptsSupported(): boolean {
}
function createNewCollectionGroup(container: Explorer): CommandButtonComponentProps {
const label = container.addCollectionText();
const label = `New ${getCollectionName()}`;
return {
iconSrc: AddCollectionIcon,
iconAlt: label,
@@ -408,7 +410,7 @@ function createOpenQueryFromDiskButton(container: Explorer): CommandButtonCompon
return {
iconSrc: OpenQueryFromDiskIcon,
iconAlt: label,
onCommandClick: () => container.openLoadQueryPanel(),
onCommandClick: () => useSidePanel.getState().openSidePanel("Load Query", <LoadQueryPane explorer={container} />),
commandButtonLabel: label,
ariaLabel: label,
hasPopup: true,

View File

@@ -14,7 +14,6 @@ import { StyleConstants } from "../../../Common/Constants";
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import { MemoryTrackerComponent } from "./MemoryTrackerComponent";
@@ -168,10 +167,6 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
};
}
if (btn.isArcadiaPicker && btn.arcadiaProps) {
result.commandBarButtonAs = () => <ArcadiaMenuPicker {...btn.arcadiaProps} />;
}
return result;
}
);

View File

@@ -15,6 +15,7 @@ import LoadingIcon from "../../../../images/loading.svg";
import ChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
import ChevronUpIcon from "../../../../images/QueryBuilder/CollapseChevronUp_16x.png";
import { ClientDefaults, KeyCodes } from "../../../Common/Constants";
import { useNotificationConsole } from "../../../hooks/useNotificationConsole";
import { userContext } from "../../../UserContext";
/**
@@ -321,3 +322,23 @@ const PrPreview = (props: { pr: string }) => {
</>
);
};
export const NotificationConsole: React.FC<
Pick<NotificationConsoleComponentProps, "consoleData" | "inProgressConsoleDataIdToBeDeleted">
> = ({
consoleData,
inProgressConsoleDataIdToBeDeleted,
}: Pick<NotificationConsoleComponentProps, "consoleData" | "inProgressConsoleDataIdToBeDeleted">) => {
const setIsExpanded = useNotificationConsole((state) => state.setIsExpanded);
const isExpanded = useNotificationConsole((state) => state.isExpanded);
// TODO Refactor NotificationConsoleComponent into a functional component and remove this wrapper
// This component only exists so we can use hooks and pass them down to a non-functional component
return (
<NotificationConsoleComponent
consoleData={consoleData}
inProgressConsoleDataIdToBeDeleted={inProgressConsoleDataIdToBeDeleted}
isConsoleExpanded={isExpanded}
setIsConsoleExpanded={setIsExpanded}
/>
);
};

View File

@@ -36,7 +36,6 @@ import * as Constants from "../../../Common/Constants";
import { Areas } from "../../../Common/Constants";
import { Action as TelemetryAction, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { decryptJWTToken } from "../../../Utils/AuthorizationUtils";
import { logConsoleError, logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
import * as FileSystemUtil from "../FileSystemUtil";
import * as cdbActions from "../NotebookComponent/actions";
@@ -105,11 +104,6 @@ const formWebSocketURL = (serverConfig: NotebookServiceConfig, kernelId: string,
params.append("session_id", sessionId);
}
const userId = getUserPuid();
if (userId) {
params.append("user_id", userId);
}
const q = params.toString();
const suffix = q !== "" ? `?${q}` : "";
@@ -289,7 +283,6 @@ export const launchWebSocketKernelEpic = (
return EMPTY;
}
const serverConfig: NotebookServiceConfig = selectors.serverConfig(host);
serverConfig.userPuid = getUserPuid();
const {
payload: { kernelSpecName, cwd, kernelRef, contentRef },
@@ -766,25 +759,6 @@ const executeFocusedCellAndFocusNextEpic = (
);
};
function getUserPuid(): string {
const arcadiaToken = window.dataExplorer && window.dataExplorer.arcadiaToken();
if (!arcadiaToken) {
return undefined;
}
let userPuid;
try {
const tokenPayload = decryptJWTToken(arcadiaToken);
if (tokenPayload && tokenPayload.hasOwnProperty("puid")) {
userPuid = tokenPayload.puid;
}
} catch (error) {
// ignore
}
return userPuid;
}
/**
* Close tab if mimetype not supported
* @param action$

View File

@@ -14,13 +14,13 @@ import { MemoryUsageInfo } from "../../Contracts/DataModels";
import { GitHubClient } from "../../GitHub/GitHubClient";
import { GitHubContentProvider } from "../../GitHub/GitHubContentProvider";
import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService";
import { useSidePanel } from "../../hooks/useSidePanel";
import { JunoClient } from "../../Juno/JunoClient";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import { getFullName } from "../../Utils/UserUtils";
import Explorer from "../Explorer";
import { ContextualPaneBase } from "../Panes/ContextualPaneBase";
import { CopyNotebookPane } from "../Panes/CopyNotebookPane/CopyNotebookPane";
import { PublishNotebookPane } from "../Panes/PublishNotebookPane/PublishNotebookPane";
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
@@ -56,8 +56,6 @@ export default class NotebookManager {
public gitHubOAuthService: GitHubOAuthService;
public gitHubClient: GitHubClient;
public gitHubReposPane: ContextualPaneBase;
public initialize(params: NotebookManagerOptions): void {
this.params = params;
this.junoClient = new JunoClient();
@@ -98,7 +96,7 @@ export default class NotebookManager {
this.gitHubOAuthService.getTokenObservable().subscribe((token) => {
this.gitHubClient.setToken(token?.access_token);
if (this?.gitHubOAuthService.isLoggedIn()) {
this.params.container.closeSidePanel();
useSidePanel.getState().closeSidePanel();
this.params.container.openGitHubReposPanel("Manager GitHub settings", this.junoClient);
}
@@ -127,37 +125,37 @@ export default class NotebookManager {
onTakeSnapshot: (request: SnapshotRequest) => void,
onClosePanel: () => void
): Promise<void> {
const explorer = this.params.container;
explorer.openSidePanel(
"Publish Notebook",
<PublishNotebookPane
explorer={this.params.container}
junoClient={this.junoClient}
closePanel={this.params.container.closeSidePanel}
openNotificationConsole={this.params.container.expandConsole}
name={name}
author={getFullName()}
notebookContent={content}
notebookContentRef={notebookContentRef}
onTakeSnapshot={onTakeSnapshot}
/>,
onClosePanel
);
useSidePanel
.getState()
.openSidePanel(
"Publish Notebook",
<PublishNotebookPane
explorer={this.params.container}
junoClient={this.junoClient}
name={name}
author={getFullName()}
notebookContent={content}
notebookContentRef={notebookContentRef}
onTakeSnapshot={onTakeSnapshot}
/>,
onClosePanel
);
}
public openCopyNotebookPane(name: string, content: string): void {
const { container } = this.params;
container.openSidePanel(
"Copy Notebook",
<CopyNotebookPane
container={container}
closePanel={container.closeSidePanel}
junoClient={this.junoClient}
gitHubOAuthService={this.gitHubOAuthService}
name={name}
content={content}
/>
);
useSidePanel
.getState()
.openSidePanel(
"Copy Notebook",
<CopyNotebookPane
container={container}
junoClient={this.junoClient}
gitHubOAuthService={this.gitHubOAuthService}
name={name}
content={content}
/>
);
}
// Octokit's error handler uses any

View File

@@ -20,6 +20,7 @@ import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils"
import { configContext, Platform } from "../../ConfigContext";
import * as DataModels from "../../Contracts/DataModels";
import { SubscriptionType } from "../../Contracts/SubscriptionType";
import { useSidePanel } from "../../hooks/useSidePanel";
import { CollectionCreation } from "../../Shared/Constants";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
@@ -36,8 +37,6 @@ import { PanelLoadingScreen } from "./PanelLoadingScreen";
export interface AddCollectionPanelProps {
explorer: Explorer;
closePanel: () => void;
openNotificationConsole: () => void;
databaseId?: string;
}
@@ -133,7 +132,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
message={this.state.errorMessage}
messageType="error"
showErrorDetails={this.state.showErrorDetails}
openNotificationConsole={this.props.openNotificationConsole}
/>
)}
@@ -142,7 +140,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
message={getUpsellMessage(userContext.portalEnv, true, this.props.explorer.isFirstResourceCreated(), true)}
messageType="info"
showErrorDetails={false}
openNotificationConsole={this.props.openNotificationConsole}
link={Constants.Urls.freeTierInformation}
linkText="Learn more"
/>
@@ -862,8 +859,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
case "SQL":
case "Mongo":
return true;
case "Cassandra":
return this.props.explorer.hasStorageAnalyticsAfecFeature();
default:
return false;
}
@@ -1064,7 +1059,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
this.setState({ isExecuting: false });
this.props.explorer.refreshAllDatabases();
TelemetryProcessor.traceSuccess(Action.CreateCollection, telemetryData, startKey);
this.props.closePanel();
useSidePanel.getState().closeSidePanel();
} catch (error) {
const errorMessage: string = getErrorMessage(error);
this.setState({ isExecuting: false, errorMessage, showErrorDetails: true });

View File

@@ -6,6 +6,7 @@ import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUti
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
import * as DataModels from "../../../Contracts/DataModels";
import { SubscriptionType } from "../../../Contracts/SubscriptionType";
import { useSidePanel } from "../../../hooks/useSidePanel";
import * as SharedConstants from "../../../Shared/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
@@ -20,15 +21,12 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
export interface AddDatabasePaneProps {
explorer: Explorer;
closePanel: () => void;
openNotificationConsole: () => void;
}
export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
explorer: container,
closePanel,
openNotificationConsole,
}: AddDatabasePaneProps) => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
let throughput: number;
let isAutoscaleSelected: boolean;
let isCostAcknowledged: boolean;
@@ -114,7 +112,7 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
const _onCreateDatabaseSuccess = (offerThroughput: number, startKey: number): void => {
setIsExecuting(false);
closePanel();
closeSidePanel();
container.refreshAllDatabases();
const addDatabasePaneSuccessMessage = {
...addDatabasePaneMessage,
@@ -163,7 +161,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
);
const props: RightPaneFormProps = {
expandConsole: openNotificationConsole,
formError: formErrors,
isExecuting,
submitButtonText: "OK",
@@ -177,7 +174,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
message={getUpsellMessage(userContext.portalEnv, true, container.isFirstResourceCreated(), true)}
messageType="info"
showErrorDetails={false}
openNotificationConsole={openNotificationConsole}
link={Constants.Urls.freeTierInformation}
linkText="Learn more"
/>

View File

@@ -2,7 +2,6 @@
exports[`AddDatabasePane Pane should render Default properly 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -3,6 +3,7 @@ import { Areas } from "../../../Common/Constants";
import { logError } from "../../../Common/Logger";
import { Query } from "../../../Contracts/DataModels";
import { Collection } from "../../../Contracts/ViewModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import { trace } from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext";
@@ -15,13 +16,12 @@ import QueryTab from "../../Tabs/QueryTab";
interface BrowseQueriesPaneProps {
explorer: Explorer;
closePanel: () => void;
}
export const BrowseQueriesPane: FunctionComponent<BrowseQueriesPaneProps> = ({
explorer,
closePanel,
}: BrowseQueriesPaneProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const loadSavedQuery = (savedQuery: Query): void => {
const selectedCollection: Collection = explorer && explorer.findSelectedCollection();
if (!selectedCollection) {
@@ -43,7 +43,7 @@ export const BrowseQueriesPane: FunctionComponent<BrowseQueriesPaneProps> = ({
queryName: savedQuery.queryName,
paneTitle: "Open Saved Queries",
});
closePanel();
closeSidePanel();
};
const props: QueriesGridComponentProps = {

View File

@@ -6,6 +6,7 @@ import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUti
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
import * as DataModels from "../../../Contracts/DataModels";
import * as ViewModels from "../../../Contracts/ViewModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import * as AddCollectionUtility from "../../../Shared/AddCollectionUtility";
import * as SharedConstants from "../../../Shared/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
@@ -19,21 +20,20 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
export interface CassandraAddCollectionPaneProps {
explorer: Explorer;
closePanel: () => void;
cassandraApiClient: CassandraAPIDataClient;
}
export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectionPaneProps> = ({
explorer: container,
closePanel,
cassandraApiClient,
}: CassandraAddCollectionPaneProps) => {
const throughputDefaults = container.collectionCreationDefaults.throughput;
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const throughputDefaults = userContext.collectionCreationDefaults.throughput;
const [createTableQuery, setCreateTableQuery] = useState<string>("CREATE TABLE ");
const [keyspaceId, setKeyspaceId] = useState<string>("");
const [tableId, setTableId] = useState<string>("");
const [throughput, setThroughput] = useState<number>(
AddCollectionUtility.getMaxThroughput(container.collectionCreationDefaults, container)
AddCollectionUtility.getMaxThroughput(userContext.collectionCreationDefaults, container)
);
const [isAutoPilotSelected, setIsAutoPilotSelected] = useState<boolean>(userContext.features.autoscaleDefault);
@@ -241,7 +241,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
}
container.refreshAllDatabases();
setIsExecuting(false);
closePanel();
closeSidePanel();
TelemetryProcessor.traceSuccess(Action.CreateCollection, addCollectionPaneStartMessage, startKey);
} catch (error) {
@@ -261,7 +261,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
};
const props: RightPaneFormProps = {
expandConsole: () => container.expandConsole(),
formError: formErrors,
isExecuting,
submitButtonText: "Apply",

View File

@@ -2,7 +2,6 @@
exports[`CassandraAddCollectionPane Pane should render Default properly 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
onSubmit={[Function]}
submitButtonText="Apply"

View File

@@ -1,126 +0,0 @@
import * as ko from "knockout";
import * as ViewModels from "../../Contracts/ViewModels";
import * as Constants from "../../Common/Constants";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import { KeyCodes } from "../../Common/Constants";
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import Explorer from "../Explorer";
// TODO: Use specific actions for logging telemetry data
export abstract class ContextualPaneBase extends WaitsForTemplateViewModel {
private initalFocusedElement: HTMLElement | undefined;
public id: string;
public container: Explorer;
public firstFieldHasFocus: ko.Observable<boolean>;
public formErrorsDetails: ko.Observable<string>;
public formErrors: ko.Observable<string>;
public title: ko.Observable<string>;
public visible: ko.Observable<boolean>;
public isExecuting: ko.Observable<boolean>;
constructor(options: ViewModels.PaneOptions) {
super();
this.id = options.id;
this.container = options.container;
this.visible = options.visible || ko.observable(false);
this.firstFieldHasFocus = ko.observable<boolean>(false);
this.formErrors = ko.observable<string>();
this.title = ko.observable<string>();
this.formErrorsDetails = ko.observable<string>();
this.isExecuting = ko.observable<boolean>(false);
}
public cancel() {
this.close();
this.container.isAccountReady() &&
TelemetryProcessor.trace(Action.ContextualPane, ActionModifiers.Close, {
dataExplorerArea: Constants.Areas.ContextualPane,
paneTitle: this.title(),
});
}
public close() {
this.visible(false);
this.isExecuting(false);
this.resetData();
this.resetFocus();
}
public open() {
this.initalFocusedElement = document.activeElement as HTMLElement;
this.visible(true);
this.firstFieldHasFocus(true);
this.resizePane();
this.container.isAccountReady() &&
TelemetryProcessor.trace(Action.ContextualPane, ActionModifiers.Open, {
dataExplorerArea: Constants.Areas.ContextualPane,
paneTitle: this.title(),
});
}
public resetData() {
this.firstFieldHasFocus(false);
this.formErrors(null);
this.formErrorsDetails(null);
}
public showErrorDetails() {
this.container.expandConsole();
}
public submit() {
this.close();
event.stopPropagation();
this.container.isAccountReady() &&
TelemetryProcessor.trace(Action.ContextualPane, ActionModifiers.Submit, {
dataExplorerArea: Constants.Areas.ContextualPane,
paneTitle: this.title(),
});
}
public onCloseKeyPress(source: any, event: KeyboardEvent): boolean {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.close();
event.stopPropagation();
return false;
}
return true;
}
public onPaneKeyDown(source: any, event: KeyboardEvent): boolean {
if (event.keyCode === KeyCodes.Escape) {
this.close();
event.stopPropagation();
return false;
}
return true;
}
public onSubmitKeyPress(source: any, event: KeyboardEvent): boolean {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.submit();
event.stopPropagation();
return false;
}
return true;
}
private resizePane(): void {
const paneElement: HTMLElement = document.getElementById(this.id);
const notificationConsoleElement: HTMLElement = document.getElementById("explorerNotificationConsole");
const newPaneElementHeight = window.innerHeight - $(notificationConsoleElement).height();
$(paneElement).height(newPaneElementHeight);
}
private resetFocus(): void {
if (this.initalFocusedElement) {
this.initalFocusedElement.focus();
this.initalFocusedElement = undefined;
}
}
}

View File

@@ -3,6 +3,7 @@ import React, { FormEvent, FunctionComponent, useEffect, useState } from "react"
import { HttpStatusCodes } from "../../../Common/Constants";
import { getErrorMessage, handleError } from "../../../Common/ErrorHandlingUtils";
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { IPinnedRepo, JunoClient } from "../../../Juno/JunoClient";
import * as GitHubUtils from "../../../Utils/GitHubUtils";
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
@@ -26,7 +27,6 @@ export interface CopyNotebookPanelProps {
container: Explorer;
junoClient: JunoClient;
gitHubOAuthService: GitHubOAuthService;
closePanel: () => void;
}
export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
@@ -35,8 +35,8 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
container,
junoClient,
gitHubOAuthService,
closePanel,
}: CopyNotebookPanelProps) => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [isExecuting, setIsExecuting] = useState<boolean>();
const [formError, setFormError] = useState<string>("");
const [pinnedRepos, setPinnedRepos] = useState<IPinnedRepo[]>();
@@ -84,7 +84,7 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
}
NotificationConsoleUtils.logConsoleInfo(`Successfully copied ${name} to ${destination}`);
closePanel();
closeSidePanel();
} catch (error) {
const errorMessage = getErrorMessage(error);
setFormError(`Failed to copy ${name} to ${destination}`);
@@ -130,7 +130,6 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
isExecuting: isExecuting,
submitButtonText: "OK",
onSubmit: () => submit(),
expandConsole: () => container.expandConsole(),
};
const copyNotebookPaneProps: CopyNotebookPaneProps = {

View File

@@ -5,6 +5,7 @@ import { deleteCollection } from "../../../Common/dataAccess/deleteCollection";
import DeleteFeedback from "../../../Common/DeleteFeedback";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import { Collection } from "../../../Contracts/ViewModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { DefaultExperienceUtility } from "../../../Shared/DefaultExperienceUtility";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
@@ -15,13 +16,12 @@ import Explorer from "../../Explorer";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
export interface DeleteCollectionConfirmationPaneProps {
explorer: Explorer;
closePanel: () => void;
}
export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectionConfirmationPaneProps> = ({
explorer,
closePanel,
}: DeleteCollectionConfirmationPaneProps) => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [deleteCollectionFeedback, setDeleteCollectionFeedback] = useState<string>("");
const [inputCollectionName, setInputCollectionName] = useState<string>("");
const [formError, setFormError] = useState<string>("");
@@ -79,7 +79,7 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
});
}
closePanel();
closeSidePanel();
} catch (error) {
const errorMessage = getErrorMessage(error);
@@ -102,7 +102,6 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
isExecuting,
submitButtonText: "OK",
onSubmit,
expandConsole: () => explorer.expandConsole(),
};
return (
<RightPaneForm {...props}>

View File

@@ -16,7 +16,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
}
>
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -6,6 +6,7 @@ import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
import DeleteFeedback from "../../Common/DeleteFeedback";
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
import { Collection, Database } from "../../Contracts/ViewModels";
import { useSidePanel } from "../../hooks/useSidePanel";
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
@@ -17,17 +18,14 @@ import { RightPaneForm, RightPaneFormProps } from "./RightPaneForm/RightPaneForm
interface DeleteDatabaseConfirmationPanelProps {
explorer: Explorer;
closePanel: () => void;
openNotificationConsole: () => void;
selectedDatabase: Database;
}
export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseConfirmationPanelProps> = ({
explorer,
openNotificationConsole,
closePanel,
selectedDatabase,
}: DeleteDatabaseConfirmationPanelProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false);
const [formError, setFormError] = useState<string>("");
@@ -51,7 +49,7 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
try {
await deleteDatabase(selectedDatabase.id());
closePanel();
closeSidePanel();
explorer.refreshAllDatabases();
explorer.tabsManager.closeTabsByComparator((tab) => tab.node?.id() === selectedDatabase.id());
explorer.selectedNode(undefined);
@@ -111,7 +109,6 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
isExecuting: isLoading,
submitButtonText: "OK",
onSubmit: () => submit(),
expandConsole: openNotificationConsole,
};
const errorProps: PanelInfoErrorProps = {

View File

@@ -2,15 +2,14 @@ import { IDropdownOption, IImageProps, Image, Stack, Text } from "@fluentui/reac
import { useBoolean } from "@fluentui/react-hooks";
import React, { FunctionComponent, useState } from "react";
import AddPropertyIcon from "../../../../images/Add-property.svg";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
import StoredProcedure from "../../Tree/StoredProcedure";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
import { InputParameter } from "./InputParameter";
interface ExecuteSprocParamsPaneProps {
expandConsole: () => void;
storedProcedure: StoredProcedure;
closePanel: () => void;
}
const imageProps: IImageProps = {
@@ -24,10 +23,9 @@ interface UnwrappedExecuteSprocParam {
}
export const ExecuteSprocParamsPane: FunctionComponent<ExecuteSprocParamsPaneProps> = ({
expandConsole,
storedProcedure,
closePanel,
}: ExecuteSprocParamsPaneProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false);
const [paramKeyValues, setParamKeyValues] = useState<UnwrappedExecuteSprocParam[]>([{ key: "string", text: "" }]);
const [partitionValue, setPartitionValue] = useState<string>(); // Defaulting to undefined here is important. It is not the same partition key as ""
@@ -76,7 +74,7 @@ export const ExecuteSprocParamsPane: FunctionComponent<ExecuteSprocParamsPanePro
});
storedProcedure.execute(sprocParams, partitionKey === "custom" ? JSON.parse(partitionValue) : partitionValue);
setLoadingFalse();
closePanel();
closeSidePanel();
};
const deleteParamAtIndex = (indexToRemove: number): void => {
@@ -114,7 +112,6 @@ export const ExecuteSprocParamsPane: FunctionComponent<ExecuteSprocParamsPanePro
};
const props: RightPaneFormProps = {
expandConsole,
formError: formError,
isExecuting: isLoading,
submitButtonText: "Execute",

View File

@@ -7,7 +7,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
storedProcedure={Object {}}
>
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -2,6 +2,7 @@ import React from "react";
import { Areas, HttpStatusCodes } from "../../../Common/Constants";
import { handleError } from "../../../Common/ErrorHandlingUtils";
import { GitHubClient, IGitHubPageInfo, IGitHubRepo } from "../../../GitHub/GitHubClient";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { IPinnedRepo, JunoClient } from "../../../Juno/JunoClient";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
@@ -21,10 +22,8 @@ import { PanelLoadingScreen } from "../PanelLoadingScreen";
interface IGitHubReposPanelProps {
explorer: Explorer;
closePanel: () => void;
gitHubClientProp: GitHubClient;
junoClientProp: JunoClient;
openNotificationConsole: () => void;
}
interface IGitHubReposPanelState {
@@ -91,7 +90,7 @@ export class GitHubReposPanel extends React.Component<IGitHubReposPanelProps, IG
},
resetConnection: (): void => this.setup(true),
onOkClick: (): Promise<void> => this.submit(),
onCancelClick: (): void => this.props.closePanel(),
onCancelClick: (): void => useSidePanel.getState().closeSidePanel(),
},
};
this.gitHubClient = this.props.gitHubClientProp;
@@ -439,7 +438,6 @@ export class GitHubReposPanel extends React.Component<IGitHubReposPanelProps, IG
message={this.state.errorMessage}
messageType="error"
showErrorDetails={this.state.showErrorDetails}
openNotificationConsole={this.props.openNotificationConsole}
/>
)}
<div className="panelMainContent" style={ContentMainStyle}>

View File

@@ -17,837 +17,32 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
addRepoProps={
Object {
"container": Explorer {
"_isAfecFeatureRegistered": [Function],
"_isInitializingNotebooks": false,
"_refreshSparkEnabledStateForAccount": [Function],
"_resetNotebookWorkspace": [Function],
"addCollectionText": [Function],
"arcadiaToken": [Function],
"canExceedMaximumValue": [Function],
"canSaveQueries": [Function],
"closeSidePanel": undefined,
"collapsedResourceTreeWidth": 36,
"collectionCreationDefaults": Object {
"storage": "100",
"throughput": Object {
"fixed": 400,
"shared": 400,
"unlimited": 400,
"unlimitedmax": 1000000,
"unlimitedmin": 400,
},
},
"collectionTitle": [Function],
"collectionTreeNodeAltText": [Function],
"commandBarComponentAdapter": CommandBarComponentAdapter {
"container": [Circular],
"isNotebookTabActive": [Function],
"parameters": [Function],
"tabsButtons": Array [],
},
"databases": [Function],
"deleteCollectionText": [Function],
"deleteDatabaseText": [Function],
"gitHubClient": GitHubClient {
"errorCallback": [Function],
"ocktokit": OctokitWithDefaults {
"actions": Object {
"addSelectedRepoToOrgSecret": [Function],
"cancelWorkflowRun": [Function],
"createOrUpdateOrgSecret": [Function],
"createOrUpdateRepoSecret": [Function],
"createOrUpdateSecretForRepo": [Function],
"createRegistrationToken": [Function],
"createRegistrationTokenForOrg": [Function],
"createRegistrationTokenForRepo": [Function],
"createRemoveToken": [Function],
"createRemoveTokenForOrg": [Function],
"createRemoveTokenForRepo": [Function],
"deleteArtifact": [Function],
"deleteOrgSecret": [Function],
"deleteRepoSecret": [Function],
"deleteSecretFromRepo": [Function],
"deleteSelfHostedRunnerFromOrg": [Function],
"deleteSelfHostedRunnerFromRepo": [Function],
"deleteWorkflowRunLogs": [Function],
"downloadArtifact": [Function],
"downloadJobLogsForWorkflowRun": [Function],
"downloadWorkflowJobLogs": [Function],
"downloadWorkflowRunLogs": [Function],
"getArtifact": [Function],
"getJobForWorkflowRun": [Function],
"getOrgPublicKey": [Function],
"getOrgSecret": [Function],
"getPublicKey": [Function],
"getRepoPublicKey": [Function],
"getRepoSecret": [Function],
"getSecret": [Function],
"getSelfHostedRunner": [Function],
"getSelfHostedRunnerForOrg": [Function],
"getSelfHostedRunnerForRepo": [Function],
"getWorkflow": [Function],
"getWorkflowJob": [Function],
"getWorkflowRun": [Function],
"getWorkflowRunUsage": [Function],
"getWorkflowUsage": [Function],
"listArtifactsForRepo": [Function],
"listDownloadsForSelfHostedRunnerApplication": [Function],
"listJobsForWorkflowRun": [Function],
"listOrgSecrets": [Function],
"listRepoSecrets": [Function],
"listRepoWorkflowRuns": [Function],
"listRepoWorkflows": [Function],
"listRunnerApplicationsForOrg": [Function],
"listRunnerApplicationsForRepo": [Function],
"listSecretsForRepo": [Function],
"listSelectedReposForOrgSecret": [Function],
"listSelfHostedRunnersForOrg": [Function],
"listSelfHostedRunnersForRepo": [Function],
"listWorkflowJobLogs": [Function],
"listWorkflowRunArtifacts": [Function],
"listWorkflowRunLogs": [Function],
"listWorkflowRuns": [Function],
"listWorkflowRunsForRepo": [Function],
"reRunWorkflow": [Function],
"removeSelectedRepoFromOrgSecret": [Function],
"removeSelfHostedRunner": [Function],
"setSelectedReposForOrgSecret": [Function],
},
"activity": Object {
"checkRepoIsStarredByAuthenticatedUser": [Function],
"checkStarringRepo": [Function],
"deleteRepoSubscription": [Function],
"deleteThreadSubscription": [Function],
"getFeeds": [Function],
"getRepoSubscription": [Function],
"getThread": [Function],
"getThreadSubscription": [Function],
"getThreadSubscriptionForAuthenticatedUser": [Function],
"listEventsForAuthenticatedUser": [Function],
"listEventsForOrg": [Function],
"listEventsForUser": [Function],
"listFeeds": [Function],
"listNotifications": [Function],
"listNotificationsForAuthenticatedUser": [Function],
"listNotificationsForRepo": [Function],
"listOrgEventsForAuthenticatedUser": [Function],
"listPublicEvents": [Function],
"listPublicEventsForOrg": [Function],
"listPublicEventsForRepoNetwork": [Function],
"listPublicEventsForUser": [Function],
"listPublicOrgEvents": [Function],
"listReceivedEventsForUser": [Function],
"listReceivedPublicEventsForUser": [Function],
"listRepoEvents": [Function],
"listRepoNotificationsForAuthenticatedUser": [Function],
"listReposStarredByAuthenticatedUser": [Function],
"listReposStarredByUser": [Function],
"listReposWatchedByUser": [Function],
"listStargazersForRepo": [Function],
"listWatchedReposForAuthenticatedUser": [Function],
"listWatchersForRepo": [Function],
"markAsRead": [Function],
"markNotificationsAsRead": [Function],
"markNotificationsAsReadForRepo": [Function],
"markRepoNotificationsAsRead": [Function],
"markThreadAsRead": [Function],
"setRepoSubscription": [Function],
"setThreadSubscription": [Function],
"starRepo": [Function],
"starRepoForAuthenticatedUser": [Function],
"unstarRepo": [Function],
"unstarRepoForAuthenticatedUser": [Function],
},
"apps": Object {
"addRepoToInstallation": [Function],
"checkAccountIsAssociatedWithAny": [Function],
"checkAccountIsAssociatedWithAnyStubbed": [Function],
"checkToken": [Function],
"createContentAttachment": [Function],
"createFromManifest": [Function],
"createInstallationAccessToken": [Function],
"createInstallationToken": [Function],
"deleteAuthorization": [Function],
"deleteInstallation": [Function],
"deleteToken": [Function],
"getAuthenticated": [Function],
"getBySlug": [Function],
"getInstallation": [Function],
"getOrgInstallation": [Function],
"getRepoInstallation": [Function],
"getSubscriptionPlanForAccount": [Function],
"getSubscriptionPlanForAccountStubbed": [Function],
"getUserInstallation": [Function],
"listAccountsForPlan": [Function],
"listAccountsForPlanStubbed": [Function],
"listAccountsUserOrOrgOnPlan": [Function],
"listAccountsUserOrOrgOnPlanStubbed": [Function],
"listInstallationReposForAuthenticatedUser": [Function],
"listInstallations": [Function],
"listInstallationsForAuthenticatedUser": [Function],
"listMarketplacePurchasesForAuthenticatedUser": [Function],
"listMarketplacePurchasesForAuthenticatedUserStubbed": [Function],
"listPlans": [Function],
"listPlansStubbed": [Function],
"listRepos": [Function],
"listReposAccessibleToInstallation": [Function],
"listSubscriptionsForAuthenticatedUser": [Function],
"listSubscriptionsForAuthenticatedUserStubbed": [Function],
"removeRepoFromInstallation": [Function],
"resetToken": [Function],
"revokeInstallationAccessToken": [Function],
"revokeInstallationToken": [Function],
"suspendInstallation": [Function],
"unsuspendInstallation": [Function],
},
"auth": [Function],
"checks": Object {
"create": [Function],
"createSuite": [Function],
"get": [Function],
"getSuite": [Function],
"listAnnotations": [Function],
"listForRef": [Function],
"listForSuite": [Function],
"listSuitesForRef": [Function],
"rerequestSuite": [Function],
"setSuitesPreferences": [Function],
"update": [Function],
},
"codeScanning": Object {
"getAlert": [Function],
"listAlertsForRepo": [Function],
},
"codesOfConduct": Object {
"getAllCodesOfConduct": [Function],
"getConductCode": [Function],
"getForRepo": [Function],
"listConductCodes": [Function],
},
"emojis": Object {
"get": [Function],
},
"gists": Object {
"checkIsStarred": [Function],
"create": [Function],
"createComment": [Function],
"delete": [Function],
"deleteComment": [Function],
"fork": [Function],
"get": [Function],
"getComment": [Function],
"getRevision": [Function],
"list": [Function],
"listComments": [Function],
"listCommits": [Function],
"listForUser": [Function],
"listForks": [Function],
"listPublic": [Function],
"listPublicForUser": [Function],
"listStarred": [Function],
"star": [Function],
"unstar": [Function],
"update": [Function],
"updateComment": [Function],
},
"git": Object {
"createBlob": [Function],
"createCommit": [Function],
"createRef": [Function],
"createTag": [Function],
"createTree": [Function],
"deleteRef": [Function],
"getBlob": [Function],
"getCommit": [Function],
"getRef": [Function],
"getTag": [Function],
"getTree": [Function],
"listMatchingRefs": [Function],
"updateRef": [Function],
},
"gitignore": Object {
"getAllTemplates": [Function],
"getTemplate": [Function],
"listTemplates": [Function],
},
"graphql": [Function],
"hook": [Function],
"interactions": Object {
"addOrUpdateRestrictionsForOrg": [Function],
"addOrUpdateRestrictionsForRepo": [Function],
"getRestrictionsForOrg": [Function],
"getRestrictionsForRepo": [Function],
"removeRestrictionsForOrg": [Function],
"removeRestrictionsForRepo": [Function],
"setRestrictionsForOrg": [Function],
"setRestrictionsForRepo": [Function],
},
"issues": Object {
"addAssignees": [Function],
"addLabels": [Function],
"checkAssignee": [Function],
"checkUserCanBeAssigned": [Function],
"create": [Function],
"createComment": [Function],
"createLabel": [Function],
"createMilestone": [Function],
"deleteComment": [Function],
"deleteLabel": [Function],
"deleteMilestone": [Function],
"get": [Function],
"getComment": [Function],
"getEvent": [Function],
"getLabel": [Function],
"getMilestone": [Function],
"list": [Function],
"listAssignees": [Function],
"listComments": [Function],
"listCommentsForRepo": [Function],
"listEvents": [Function],
"listEventsForRepo": [Function],
"listEventsForTimeline": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listForRepo": [Function],
"listLabelsForMilestone": [Function],
"listLabelsForRepo": [Function],
"listLabelsOnIssue": [Function],
"listMilestones": [Function],
"listMilestonesForRepo": [Function],
"lock": [Function],
"removeAllLabels": [Function],
"removeAssignees": [Function],
"removeLabel": [Function],
"removeLabels": [Function],
"replaceAllLabels": [Function],
"replaceLabels": [Function],
"setLabels": [Function],
"unlock": [Function],
"update": [Function],
"updateComment": [Function],
"updateLabel": [Function],
"updateMilestone": [Function],
},
"licenses": Object {
"get": [Function],
"getAllCommonlyUsed": [Function],
"getForRepo": [Function],
"listCommonlyUsed": [Function],
},
"log": Object {
"debug": [Function],
"error": [Function],
"info": [Function],
"warn": [Function],
},
"markdown": Object {
"render": [Function],
"renderRaw": [Function],
},
"meta": Object {
"get": [Function],
},
"migrations": Object {
"cancelImport": [Function],
"deleteArchiveForAuthenticatedUser": [Function],
"deleteArchiveForOrg": [Function],
"downloadArchiveForOrg": [Function],
"getArchiveForAuthenticatedUser": [Function],
"getCommitAuthors": [Function],
"getImportProgress": [Function],
"getImportStatus": [Function],
"getLargeFiles": [Function],
"getStatusForAuthenticatedUser": [Function],
"getStatusForOrg": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listReposForOrg": [Function],
"listReposForUser": [Function],
"mapCommitAuthor": [Function],
"setLfsPreference": [Function],
"startForAuthenticatedUser": [Function],
"startForOrg": [Function],
"startImport": [Function],
"unlockRepoForAuthenticatedUser": [Function],
"unlockRepoForOrg": [Function],
"updateImport": [Function],
},
"orgs": Object {
"addOrUpdateMembership": [Function],
"blockUser": [Function],
"checkBlockedUser": [Function],
"checkMembership": [Function],
"checkMembershipForUser": [Function],
"checkPublicMembership": [Function],
"checkPublicMembershipForUser": [Function],
"concealMembership": [Function],
"convertMemberToOutsideCollaborator": [Function],
"createHook": [Function],
"createInvitation": [Function],
"createWebhook": [Function],
"deleteHook": [Function],
"deleteWebhook": [Function],
"get": [Function],
"getHook": [Function],
"getMembership": [Function],
"getMembershipForAuthenticatedUser": [Function],
"getMembershipForUser": [Function],
"getWebhook": [Function],
"list": [Function],
"listAppInstallations": [Function],
"listBlockedUsers": [Function],
"listForAuthenticatedUser": [Function],
"listForUser": [Function],
"listHooks": [Function],
"listInstallations": [Function],
"listInvitationTeams": [Function],
"listMembers": [Function],
"listMemberships": [Function],
"listMembershipsForAuthenticatedUser": [Function],
"listOutsideCollaborators": [Function],
"listPendingInvitations": [Function],
"listPublicMembers": [Function],
"listWebhooks": [Function],
"pingHook": [Function],
"pingWebhook": [Function],
"publicizeMembership": [Function],
"removeMember": [Function],
"removeMembership": [Function],
"removeMembershipForUser": [Function],
"removeOutsideCollaborator": [Function],
"removePublicMembershipForAuthenticatedUser": [Function],
"setMembershipForUser": [Function],
"setPublicMembershipForAuthenticatedUser": [Function],
"unblockUser": [Function],
"update": [Function],
"updateHook": [Function],
"updateMembership": [Function],
"updateMembershipForAuthenticatedUser": [Function],
"updateWebhook": [Function],
},
"paginate": [Function],
"projects": Object {
"addCollaborator": [Function],
"createCard": [Function],
"createColumn": [Function],
"createForAuthenticatedUser": [Function],
"createForOrg": [Function],
"createForRepo": [Function],
"delete": [Function],
"deleteCard": [Function],
"deleteColumn": [Function],
"get": [Function],
"getCard": [Function],
"getColumn": [Function],
"getPermissionForUser": [Function],
"listCards": [Function],
"listCollaborators": [Function],
"listColumns": [Function],
"listForOrg": [Function],
"listForRepo": [Function],
"listForUser": [Function],
"moveCard": [Function],
"moveColumn": [Function],
"removeCollaborator": [Function],
"reviewUserPermissionLevel": [Function],
"update": [Function],
"updateCard": [Function],
"updateColumn": [Function],
},
"pulls": Object {
"checkIfMerged": [Function],
"create": [Function],
"createComment": [Function],
"createReplyForReviewComment": [Function],
"createReview": [Function],
"createReviewComment": [Function],
"createReviewCommentReply": [Function],
"createReviewRequest": [Function],
"deleteComment": [Function],
"deletePendingReview": [Function],
"deleteReviewComment": [Function],
"deleteReviewRequest": [Function],
"dismissReview": [Function],
"get": [Function],
"getComment": [Function],
"getCommentsForReview": [Function],
"getReview": [Function],
"getReviewComment": [Function],
"list": [Function],
"listComments": [Function],
"listCommentsForRepo": [Function],
"listCommentsForReview": [Function],
"listCommits": [Function],
"listFiles": [Function],
"listRequestedReviewers": [Function],
"listReviewComments": [Function],
"listReviewCommentsForRepo": [Function],
"listReviewRequests": [Function],
"listReviews": [Function],
"merge": [Function],
"removeRequestedReviewers": [Function],
"requestReviewers": [Function],
"submitReview": [Function],
"update": [Function],
"updateBranch": [Function],
"updateComment": [Function],
"updateReview": [Function],
"updateReviewComment": [Function],
},
"rateLimit": Object {
"get": [Function],
},
"reactions": Object {
"createForCommitComment": [Function],
"createForIssue": [Function],
"createForIssueComment": [Function],
"createForPullRequestReviewComment": [Function],
"createForTeamDiscussionCommentInOrg": [Function],
"createForTeamDiscussionInOrg": [Function],
"delete": [Function],
"deleteForCommitComment": [Function],
"deleteForIssue": [Function],
"deleteForIssueComment": [Function],
"deleteForPullRequestComment": [Function],
"deleteForTeamDiscussion": [Function],
"deleteForTeamDiscussionComment": [Function],
"deleteLegacy": [Function],
"listForCommitComment": [Function],
"listForIssue": [Function],
"listForIssueComment": [Function],
"listForPullRequestReviewComment": [Function],
"listForTeamDiscussionCommentInOrg": [Function],
"listForTeamDiscussionInOrg": [Function],
},
"repos": Object {
"acceptInvitation": [Function],
"addAppAccessRestrictions": [Function],
"addCollaborator": [Function],
"addDeployKey": [Function],
"addProtectedBranchAdminEnforcement": [Function],
"addProtectedBranchAppRestrictions": [Function],
"addProtectedBranchRequiredSignatures": [Function],
"addProtectedBranchRequiredStatusChecksContexts": [Function],
"addProtectedBranchTeamRestrictions": [Function],
"addProtectedBranchUserRestrictions": [Function],
"addStatusCheckContexts": [Function],
"addTeamAccessRestrictions": [Function],
"addUserAccessRestrictions": [Function],
"checkCollaborator": [Function],
"checkVulnerabilityAlerts": [Function],
"compareCommits": [Function],
"createCommitComment": [Function],
"createCommitSignatureProtection": [Function],
"createCommitStatus": [Function],
"createDeployKey": [Function],
"createDeployment": [Function],
"createDeploymentStatus": [Function],
"createDispatchEvent": [Function],
"createForAuthenticatedUser": [Function],
"createFork": [Function],
"createHook": [Function],
"createInOrg": [Function],
"createOrUpdateFile": [Function],
"createOrUpdateFileContents": [Function],
"createPagesSite": [Function],
"createRelease": [Function],
"createStatus": [Function],
"createUsingTemplate": [Function],
"createWebhook": [Function],
"declineInvitation": [Function],
"delete": [Function],
"deleteAccessRestrictions": [Function],
"deleteAdminBranchProtection": [Function],
"deleteBranchProtection": [Function],
"deleteCommitComment": [Function],
"deleteCommitSignatureProtection": [Function],
"deleteDeployKey": [Function],
"deleteDeployment": [Function],
"deleteDownload": [Function],
"deleteFile": [Function],
"deleteHook": [Function],
"deleteInvitation": [Function],
"deletePagesSite": [Function],
"deletePullRequestReviewProtection": [Function],
"deleteRelease": [Function],
"deleteReleaseAsset": [Function],
"deleteWebhook": [Function],
"disableAutomatedSecurityFixes": [Function],
"disablePagesSite": [Function],
"disableVulnerabilityAlerts": [Function],
"downloadArchive": [Function],
"enableAutomatedSecurityFixes": [Function],
"enablePagesSite": [Function],
"enableVulnerabilityAlerts": [Function],
"get": [Function],
"getAccessRestrictions": [Function],
"getAdminBranchProtection": [Function],
"getAllStatusCheckContexts": [Function],
"getAllTopics": [Function],
"getAppsWithAccessToProtectedBranch": [Function],
"getArchiveLink": [Function],
"getBranch": [Function],
"getBranchProtection": [Function],
"getClones": [Function],
"getCodeFrequencyStats": [Function],
"getCollaboratorPermissionLevel": [Function],
"getCombinedStatusForRef": [Function],
"getCommit": [Function],
"getCommitActivityStats": [Function],
"getCommitComment": [Function],
"getCommitSignatureProtection": [Function],
"getCommunityProfileMetrics": [Function],
"getContent": [Function],
"getContents": [Function],
"getContributorsStats": [Function],
"getDeployKey": [Function],
"getDeployment": [Function],
"getDeploymentStatus": [Function],
"getDownload": [Function],
"getHook": [Function],
"getLatestPagesBuild": [Function],
"getLatestRelease": [Function],
"getPages": [Function],
"getPagesBuild": [Function],
"getParticipationStats": [Function],
"getProtectedBranchAdminEnforcement": [Function],
"getProtectedBranchPullRequestReviewEnforcement": [Function],
"getProtectedBranchRequiredSignatures": [Function],
"getProtectedBranchRequiredStatusChecks": [Function],
"getProtectedBranchRestrictions": [Function],
"getPullRequestReviewProtection": [Function],
"getPunchCardStats": [Function],
"getReadme": [Function],
"getRelease": [Function],
"getReleaseAsset": [Function],
"getReleaseByTag": [Function],
"getStatusChecksProtection": [Function],
"getTeamsWithAccessToProtectedBranch": [Function],
"getTopPaths": [Function],
"getTopReferrers": [Function],
"getUsersWithAccessToProtectedBranch": [Function],
"getViews": [Function],
"getWebhook": [Function],
"list": [Function],
"listAssetsForRelease": [Function],
"listBranches": [Function],
"listBranchesForHeadCommit": [Function],
"listCollaborators": [Function],
"listCommentsForCommit": [Function],
"listCommitComments": [Function],
"listCommitCommentsForRepo": [Function],
"listCommitStatusesForRef": [Function],
"listCommits": [Function],
"listContributors": [Function],
"listDeployKeys": [Function],
"listDeploymentStatuses": [Function],
"listDeployments": [Function],
"listDownloads": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listForUser": [Function],
"listForks": [Function],
"listHooks": [Function],
"listInvitations": [Function],
"listInvitationsForAuthenticatedUser": [Function],
"listLanguages": [Function],
"listPagesBuilds": [Function],
"listProtectedBranchRequiredStatusChecksContexts": [Function],
"listPublic": [Function],
"listPullRequestsAssociatedWithCommit": [Function],
"listReleaseAssets": [Function],
"listReleases": [Function],
"listStatusesForRef": [Function],
"listTags": [Function],
"listTeams": [Function],
"listTopics": [Function],
"listWebhooks": [Function],
"merge": [Function],
"pingHook": [Function],
"pingWebhook": [Function],
"removeAppAccessRestrictions": [Function],
"removeBranchProtection": [Function],
"removeCollaborator": [Function],
"removeDeployKey": [Function],
"removeProtectedBranchAdminEnforcement": [Function],
"removeProtectedBranchAppRestrictions": [Function],
"removeProtectedBranchPullRequestReviewEnforcement": [Function],
"removeProtectedBranchRequiredSignatures": [Function],
"removeProtectedBranchRequiredStatusChecks": [Function],
"removeProtectedBranchRequiredStatusChecksContexts": [Function],
"removeProtectedBranchRestrictions": [Function],
"removeProtectedBranchTeamRestrictions": [Function],
"removeProtectedBranchUserRestrictions": [Function],
"removeStatusCheckContexts": [Function],
"removeStatusCheckProtection": [Function],
"removeTeamAccessRestrictions": [Function],
"removeUserAccessRestrictions": [Function],
"replaceAllTopics": [Function],
"replaceProtectedBranchAppRestrictions": [Function],
"replaceProtectedBranchRequiredStatusChecksContexts": [Function],
"replaceProtectedBranchTeamRestrictions": [Function],
"replaceProtectedBranchUserRestrictions": [Function],
"replaceTopics": [Function],
"requestPageBuild": [Function],
"requestPagesBuild": [Function],
"retrieveCommunityProfileMetrics": [Function],
"setAdminBranchProtection": [Function],
"setAppAccessRestrictions": [Function],
"setStatusCheckContexts": [Function],
"setTeamAccessRestrictions": [Function],
"setUserAccessRestrictions": [Function],
"testPushHook": [Function],
"testPushWebhook": [Function],
"transfer": [Function],
"update": [Function],
"updateBranchProtection": [Function],
"updateCommitComment": [Function],
"updateHook": [Function],
"updateInformationAboutPagesSite": [Function],
"updateInvitation": [Function],
"updateProtectedBranchPullRequestReviewEnforcement": [Function],
"updateProtectedBranchRequiredStatusChecks": [Function],
"updatePullRequestReviewProtection": [Function],
"updateRelease": [Function],
"updateReleaseAsset": [Function],
"updateStatusCheckPotection": [Function],
"updateWebhook": [Function],
"uploadReleaseAsset": [Function],
},
"request": [Function],
"search": Object {
"code": [Function],
"commits": [Function],
"issuesAndPullRequests": [Function],
"labels": [Function],
"repos": [Function],
"topics": [Function],
"users": [Function],
},
"teams": Object {
"addOrUpdateMembershipForUserInOrg": [Function],
"addOrUpdateMembershipInOrg": [Function],
"addOrUpdateProjectInOrg": [Function],
"addOrUpdateProjectPermissionsInOrg": [Function],
"addOrUpdateRepoInOrg": [Function],
"addOrUpdateRepoPermissionsInOrg": [Function],
"checkManagesRepoInOrg": [Function],
"checkPermissionsForProjectInOrg": [Function],
"checkPermissionsForRepoInOrg": [Function],
"create": [Function],
"createDiscussionCommentInOrg": [Function],
"createDiscussionInOrg": [Function],
"deleteDiscussionCommentInOrg": [Function],
"deleteDiscussionInOrg": [Function],
"deleteInOrg": [Function],
"getByName": [Function],
"getDiscussionCommentInOrg": [Function],
"getDiscussionInOrg": [Function],
"getMembershipForUserInOrg": [Function],
"getMembershipInOrg": [Function],
"list": [Function],
"listChildInOrg": [Function],
"listDiscussionCommentsInOrg": [Function],
"listDiscussionsInOrg": [Function],
"listForAuthenticatedUser": [Function],
"listMembersInOrg": [Function],
"listPendingInvitationsInOrg": [Function],
"listProjectsInOrg": [Function],
"listReposInOrg": [Function],
"removeMembershipForUserInOrg": [Function],
"removeMembershipInOrg": [Function],
"removeProjectInOrg": [Function],
"removeRepoInOrg": [Function],
"reviewProjectInOrg": [Function],
"updateDiscussionCommentInOrg": [Function],
"updateDiscussionInOrg": [Function],
"updateInOrg": [Function],
},
"users": Object {
"addEmailForAuthenticated": [Function],
"addEmails": [Function],
"block": [Function],
"checkBlocked": [Function],
"checkFollowing": [Function],
"checkFollowingForUser": [Function],
"checkPersonIsFollowedByAuthenticated": [Function],
"createGpgKey": [Function],
"createGpgKeyForAuthenticated": [Function],
"createPublicKey": [Function],
"createPublicSshKeyForAuthenticated": [Function],
"deleteEmailForAuthenticated": [Function],
"deleteEmails": [Function],
"deleteGpgKey": [Function],
"deleteGpgKeyForAuthenticated": [Function],
"deletePublicKey": [Function],
"deletePublicSshKeyForAuthenticated": [Function],
"follow": [Function],
"getAuthenticated": [Function],
"getByUsername": [Function],
"getContextForUser": [Function],
"getGpgKey": [Function],
"getGpgKeyForAuthenticated": [Function],
"getPublicKey": [Function],
"getPublicSshKeyForAuthenticated": [Function],
"list": [Function],
"listBlocked": [Function],
"listBlockedByAuthenticated": [Function],
"listEmails": [Function],
"listEmailsForAuthenticated": [Function],
"listFollowedByAuthenticated": [Function],
"listFollowersForAuthenticatedUser": [Function],
"listFollowersForUser": [Function],
"listFollowingForAuthenticatedUser": [Function],
"listFollowingForUser": [Function],
"listGpgKeys": [Function],
"listGpgKeysForAuthenticated": [Function],
"listGpgKeysForUser": [Function],
"listPublicEmails": [Function],
"listPublicEmailsForAuthenticated": [Function],
"listPublicKeys": [Function],
"listPublicKeysForUser": [Function],
"listPublicSshKeysForAuthenticated": [Function],
"setPrimaryEmailVisibilityForAuthenticated": [Function],
"togglePrimaryEmailVisibility": [Function],
"unblock": [Function],
"unfollow": [Function],
"updateAuthenticated": [Function],
},
},
},
"hasStorageAnalyticsAfecFeature": [Function],
"isAccountReady": [Function],
"isFixedCollectionWithSharedThroughputSupported": [Function],
"isHostedDataExplorerEnabled": [Function],
"isLeftPaneExpanded": [Function],
"isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function],
"isPublishNotebookPaneEnabled": [Function],
"isResourceTokenCollectionNodeSelected": [Function],
"isSchemaEnabled": [Function],
"isServerlessEnabled": [Function],
"isShellEnabled": [Function],
"isSparkEnabled": [Function],
"isSparkEnabledForAccount": [Function],
"isSynapseLinkUpdating": [Function],
"isTabsContentExpanded": [Function],
"junoClient": JunoClient {
"cachedPinnedRepos": [Function],
},
"memoryUsageInfo": [Function],
"notebookBasePath": [Function],
"notebookServerInfo": [Function],
"onGitHubClientError": [Function],
"onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function],
"openSidePanel": undefined,
"provideFeedbackEmail": [Function],
"queriesClient": QueriesClient {
"container": [Circular],
},
"refreshNotebookList": [Function],
"refreshTreeTitle": [Function],
"resourceTokenCollection": [Function],
"resourceTokenCollectionId": [Function],
"resourceTokenDatabaseId": [Function],
@@ -867,7 +62,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
"selectedDatabaseId": [Function],
"selectedNode": [Function],
"setInProgressConsoleDataIdToBeDeleted": undefined,
"setIsNotificationConsoleExpanded": undefined,
"setNotificationConsoleData": undefined,
"sparkClusterConnectionInfo": [Function],
"splitter": Splitter {
@@ -886,7 +80,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
"activeTab": [Function],
"openedTabs": [Function],
},
"toggleLeftPaneExpandedKeyPress": [Function],
},
"getRepo": [Function],
"pinRepo": [Function],

View File

@@ -1,25 +1,27 @@
import React, { FunctionComponent } from "react";
import * as ViewModels from "../../../Contracts/ViewModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { GraphStyleComponent } from "../../Graph/GraphStyleComponent/GraphStyleComponent";
import { IGraphConfig } from "../../Tabs/GraphTab";
import { PanelFooterComponent } from "../PanelFooterComponent";
interface GraphStylingProps {
closePanel: () => void;
igraphConfigUiData: ViewModels.IGraphConfigUiData;
igraphConfig: IGraphConfig;
getValues: (igraphConfig?: IGraphConfig) => void;
}
export const GraphStylingPanel: FunctionComponent<GraphStylingProps> = ({
closePanel,
igraphConfigUiData,
igraphConfig,
getValues,
}: GraphStylingProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const buttonLabel = "Ok";
const submit = () => {
closePanel();
const submit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
closeSidePanel();
};
return (

View File

@@ -4,6 +4,7 @@ import React, { FunctionComponent, useState } from "react";
import folderIcon from "../../../../images/folder_16x16.svg";
import { logError } from "../../../Common/Logger";
import { Collection } from "../../../Contracts/ViewModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { userContext } from "../../../UserContext";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
import Explorer from "../../Explorer";
@@ -12,13 +13,10 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
interface LoadQueryPaneProps {
explorer: Explorer;
closePanel: () => void;
}
export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({
explorer,
closePanel,
}: LoadQueryPaneProps): JSX.Element => {
export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({ explorer }: LoadQueryPaneProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false);
const [formError, setFormError] = useState<string>("");
const [selectedFileName, setSelectedFileName] = useState<string>("");
@@ -51,7 +49,7 @@ export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({
try {
await loadQueryFromFile(file);
logConsoleInfo(`Successfully loaded query from file ${file.name}`);
closePanel();
closeSidePanel();
setLoadingFalse();
} catch (error) {
setLoadingFalse();
@@ -89,7 +87,6 @@ export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({
isExecuting: isLoading,
submitButtonText: "Load",
onSubmit: () => submit(),
expandConsole: () => explorer.expandConsole(),
};
return (

View File

@@ -2,7 +2,6 @@
exports[`Load Query Pane should render Default properly 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -36,14 +36,7 @@ describe("New Vertex Panel", () => {
it("should call form submit method", () => {
const onSubmitSpy = jest.fn();
const newWrapper = mount(
<NewVertexPanel
explorer={fakeExplorer}
partitionKeyPropertyProp={undefined}
openNotificationConsole={(): void => undefined}
onSubmit={onSubmitSpy}
/>
);
const newWrapper = mount(<NewVertexPanel partitionKeyPropertyProp={undefined} onSubmit={onSubmitSpy} />);
//eslint-disable-next-line
newWrapper.find("form").simulate("submit", { preventDefault: () => {} });
@@ -61,14 +54,7 @@ describe("New Vertex Panel", () => {
const result = onSubmitSpy(fakeNewVertexData, onErrorSpy, onSuccessSpy);
const newWrapper = mount(
<NewVertexPanel
explorer={fakeExplorer}
partitionKeyPropertyProp={undefined}
openNotificationConsole={(): void => undefined}
onSubmit={onSubmitSpy}
/>
);
const newWrapper = mount(<NewVertexPanel partitionKeyPropertyProp={undefined} onSubmit={onSubmitSpy} />);
//eslint-disable-next-line
newWrapper.find("form").simulate("submit", { preventDefault: () => {} });

View File

@@ -1,21 +1,17 @@
import { useBoolean } from "@fluentui/react-hooks";
import React, { FunctionComponent, useState } from "react";
import * as ViewModels from "../../../Contracts/ViewModels";
import Explorer from "../../Explorer";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { NewVertexComponent } from "../../Graph/NewVertexComponent/NewVertexComponent";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
export interface INewVertexPanelProps {
explorer: Explorer;
partitionKeyPropertyProp: string;
onSubmit: (result: ViewModels.NewVertexData, onError: (errorMsg: string) => void, onSuccess: () => void) => void;
openNotificationConsole: () => void;
}
export const NewVertexPanel: FunctionComponent<INewVertexPanelProps> = ({
explorer,
partitionKeyPropertyProp,
onSubmit,
openNotificationConsole,
}: INewVertexPanelProps): JSX.Element => {
let newVertexDataValue: ViewModels.NewVertexData;
const [errorMessage, setErrorMessage] = useState<string>("");
@@ -33,10 +29,10 @@ export const NewVertexPanel: FunctionComponent<INewVertexPanelProps> = ({
setErrorMessage(errorMsg);
setLoadingFalse();
};
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const onSuccess = () => {
setLoadingFalse();
explorer.closeSidePanel();
closeSidePanel();
};
const onChange = (newVertexData: ViewModels.NewVertexData) => {
@@ -47,7 +43,6 @@ export const NewVertexPanel: FunctionComponent<INewVertexPanelProps> = ({
isExecuting: isLoading,
submitButtonText: "OK",
onSubmit: () => submit(),
expandConsole: openNotificationConsole,
};
return (

View File

@@ -2,7 +2,6 @@
exports[`New Vertex Panel should render default property 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -9,7 +9,6 @@ describe("PaneContainerComponent test", () => {
panelContent: <div></div>,
isOpen: true,
isConsoleExpanded: false,
closePanel: undefined,
};
const wrapper = shallow(<PanelContainerComponent {...panelContainerProps} />);
expect(wrapper).toMatchSnapshot();
@@ -21,7 +20,6 @@ describe("PaneContainerComponent test", () => {
panelContent: undefined,
isOpen: true,
isConsoleExpanded: false,
closePanel: undefined,
};
const wrapper = shallow(<PanelContainerComponent {...panelContainerProps} />);
expect(wrapper).toMatchSnapshot();
@@ -33,7 +31,6 @@ describe("PaneContainerComponent test", () => {
panelContent: <div></div>,
isOpen: true,
isConsoleExpanded: true,
closePanel: undefined,
};
const wrapper = shallow(<PanelContainerComponent {...panelContainerProps} />);
expect(wrapper).toMatchSnapshot();

View File

@@ -1,12 +1,13 @@
import { IPanelProps, IRenderFunction, Panel, PanelType } from "@fluentui/react";
import * as React from "react";
import { useNotificationConsole } from "../../hooks/useNotificationConsole";
import { useSidePanel } from "../../hooks/useSidePanel";
export interface PanelContainerProps {
headerText: string;
panelContent: JSX.Element;
isConsoleExpanded: boolean;
isOpen: boolean;
closePanel: () => void;
panelWidth?: string;
onRenderNavigationContent?: IRenderFunction<IPanelProps>;
}
@@ -69,7 +70,7 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
if ((ev.target as HTMLElement).id === "notificationConsoleHeader") {
ev.preventDefault();
} else {
this.props.closePanel();
useSidePanel.getState().closeSidePanel();
}
};
@@ -81,3 +82,24 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
return panelHeight + "px";
};
}
export const SidePanel: React.FC = () => {
const isConsoleExpanded = useNotificationConsole((state) => state.isExpanded);
const { isOpen, panelContent, headerText } = useSidePanel((state) => {
return {
isOpen: state.isOpen,
panelContent: state.panelContent,
headerText: state.headerText,
};
});
// TODO Refactor PanelContainerComponent into a functional component and remove this wrapper
// This component only exists so we can use hooks and pass them down to a non-functional component
return (
<PanelContainerComponent
isOpen={isOpen}
panelContent={panelContent}
headerText={headerText}
isConsoleExpanded={isConsoleExpanded}
/>
);
};

View File

@@ -1,5 +1,6 @@
import { Icon, Link, Stack, Text } from "@fluentui/react";
import React from "react";
import { useNotificationConsole } from "../../hooks/useNotificationConsole";
export interface PanelInfoErrorProps {
message: string;
@@ -7,7 +8,6 @@ export interface PanelInfoErrorProps {
showErrorDetails: boolean;
link?: string;
linkText?: string;
openNotificationConsole?: () => void;
formError?: boolean;
}
@@ -17,8 +17,9 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
showErrorDetails,
link,
linkText,
openNotificationConsole,
}: PanelInfoErrorProps): JSX.Element => {
const expandConsole = useNotificationConsole((state) => state.expandConsole);
let icon: JSX.Element = <Icon iconName="InfoSolid" className="panelLargeInfoIcon" aria-label="Infomation" />;
if (messageType === "error") {
icon = <Icon iconName="StatusErrorFull" className="panelErrorIcon" aria-label="error" />;
@@ -41,7 +42,7 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
)}
</Text>
{showErrorDetails && (
<a className="paneErrorLink" role="link" onClick={openNotificationConsole}>
<a className="paneErrorLink" role="link" onClick={expandConsole}>
More details
</a>
)}

View File

@@ -3,6 +3,7 @@ import React, { FunctionComponent, useEffect, useState } from "react";
import { HttpStatusCodes } from "../../../Common/Constants";
import { getErrorMessage, getErrorStack, handleError } from "../../../Common/ErrorHandlingUtils";
import { useNotebookSnapshotStore } from "../../../hooks/useNotebookSnapshotStore";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { JunoClient } from "../../../Juno/JunoClient";
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
@@ -17,8 +18,6 @@ import { PublishNotebookPaneComponent, PublishNotebookPaneProps } from "./Publis
export interface PublishNotebookPaneAProps {
explorer: Explorer;
closePanel: () => void;
openNotificationConsole: () => void;
junoClient: JunoClient;
name: string;
author: string;
@@ -29,13 +28,14 @@ export interface PublishNotebookPaneAProps {
export const PublishNotebookPane: FunctionComponent<PublishNotebookPaneAProps> = ({
explorer: container,
junoClient,
closePanel,
name,
author,
notebookContent,
notebookContentRef,
onTakeSnapshot,
}: PublishNotebookPaneAProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [isCodeOfConductAccepted, setIsCodeOfConductAccepted] = useState<boolean>(false);
const [content, setContent] = useState<string>("");
const [formError, setFormError] = useState<string>("");
@@ -152,7 +152,7 @@ export const PublishNotebookPane: FunctionComponent<PublishNotebookPaneAProps> =
clearPublishingMessage();
setIsExecuting(false);
}
closePanel();
closeSidePanel();
};
const createFormError = (formError: string, formErrorDetail: string, area: string): void => {
@@ -171,7 +171,6 @@ export const PublishNotebookPane: FunctionComponent<PublishNotebookPaneAProps> =
isExecuting: isExecuting,
submitButtonText: "Publish",
onSubmit: () => submit(),
expandConsole: () => container.expandConsole(),
isSubmitButtonHidden: !isCodeOfConductAccepted,
};

View File

@@ -4,7 +4,6 @@ import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent";
import { PanelLoadingScreen } from "../PanelLoadingScreen";
export interface RightPaneFormProps {
expandConsole: () => void;
formError: string;
isExecuting: boolean;
onSubmit: () => void;
@@ -14,7 +13,6 @@ export interface RightPaneFormProps {
}
export const RightPaneForm: FunctionComponent<RightPaneFormProps> = ({
expandConsole,
formError,
isExecuting,
onSubmit,
@@ -30,14 +28,7 @@ export const RightPaneForm: FunctionComponent<RightPaneFormProps> = ({
return (
<>
<form className="panelFormWrapper" onSubmit={handleOnSubmit}>
{formError && (
<PanelInfoErrorComponent
messageType="error"
message={formError}
showErrorDetails={true}
openNotificationConsole={expandConsole}
/>
)}
{formError && <PanelInfoErrorComponent messageType="error" message={formError} showErrorDetails={true} />}
{children}
{!isSubmitButtonHidden && <PanelFooterComponent buttonLabel={submitButtonText} />}
</form>

View File

@@ -4,6 +4,7 @@ import React, { FunctionComponent, useState } from "react";
import { Areas, SavedQueries } from "../../../Common/Constants";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import { Query } from "../../../Contracts/DataModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
@@ -13,13 +14,10 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
interface SaveQueryPaneProps {
explorer: Explorer;
closePanel: () => void;
}
export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({
explorer,
closePanel,
}: SaveQueryPaneProps): JSX.Element => {
export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({ explorer }: SaveQueryPaneProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false);
const [formError, setFormError] = useState<string>("");
const [queryName, setQueryName] = useState<string>("");
@@ -71,7 +69,7 @@ export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({
},
startKey
);
closePanel();
closeSidePanel();
} catch (error) {
setLoadingFalse();
const errorMessage = getErrorMessage(error);
@@ -128,7 +126,6 @@ export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({
};
const props: RightPaneFormProps = {
expandConsole: () => explorer.expandConsole(),
formError: formError,
isExecuting: isLoading,
submitButtonText: canSaveQueries() ? "Save" : "Complete setup",

View File

@@ -2,7 +2,6 @@
exports[`Save Query Pane should render Default properly 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -3,13 +3,10 @@ import React from "react";
import { DatabaseAccount } from "../../../Contracts/DataModels";
import { updateUserContext } from "../../../UserContext";
import { SettingsPane } from "./SettingsPane";
const props = {
expandConsole: (): void => undefined,
closePanel: (): void => undefined,
};
describe("Settings Pane", () => {
it("should render Default properly", () => {
const wrapper = shallow(<SettingsPane {...props} />);
const wrapper = shallow(<SettingsPane />);
expect(wrapper).toMatchSnapshot();
});
@@ -21,7 +18,7 @@ describe("Settings Pane", () => {
},
} as DatabaseAccount,
});
const wrapper = shallow(<SettingsPane {...props} />);
const wrapper = shallow(<SettingsPane />);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -3,21 +3,15 @@ import React, { FunctionComponent, MouseEvent, useState } from "react";
import * as Constants from "../../../Common/Constants";
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
import { configContext } from "../../../ConfigContext";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { LocalStorageUtility, StorageKey } from "../../../Shared/StorageUtility";
import * as StringUtility from "../../../Shared/StringUtility";
import { userContext } from "../../../UserContext";
import { logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
export interface SettingsPaneProps {
expandConsole: () => void;
closePanel: () => void;
}
export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
expandConsole,
closePanel,
}: SettingsPaneProps) => {
export const SettingsPane: FunctionComponent = () => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [isExecuting, setIsExecuting] = useState<boolean>(false);
const [pageOption, setPageOption] = useState<string>(
LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage) === Constants.Queries.unlimitedItemsPerPage
@@ -88,7 +82,7 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
logConsoleInfo(
`Updated query setting to ${LocalStorageUtility.getEntryString(StorageKey.SetPartitionKeyUndefined)}`
);
closePanel();
closeSidePanel();
e.preventDefault();
};
@@ -101,7 +95,6 @@ export const SettingsPane: FunctionComponent<SettingsPaneProps> = ({
};
const genericPaneProps: RightPaneFormProps = {
expandConsole,
formError: "",
isExecuting,
submitButtonText: "Apply",

View File

@@ -2,7 +2,6 @@
exports[`Settings Pane should render Default properly 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}
@@ -149,7 +148,6 @@ exports[`Settings Pane should render Default properly 1`] = `
exports[`Settings Pane should render Gremlin properly 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -3,6 +3,7 @@ import { useBoolean } from "@fluentui/react-hooks";
import React, { FunctionComponent, KeyboardEvent, useState } from "react";
import { Areas, NormalizedEventKey } from "../../../Common/Constants";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext";
@@ -12,20 +13,17 @@ import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent";
import { PanelLoadingScreen } from "../PanelLoadingScreen";
interface SetupNoteBooksPanelProps {
explorer: Explorer;
closePanel: () => void;
openNotificationConsole: () => void;
panelTitle: string;
panelDescription: string;
}
export const SetupNoteBooksPanel: FunctionComponent<SetupNoteBooksPanelProps> = ({
explorer,
closePanel,
openNotificationConsole,
panelTitle,
panelDescription,
}: SetupNoteBooksPanelProps): JSX.Element => {
const title = panelTitle;
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const description = panelDescription;
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false);
const [errorMessage, setErrorMessage] = useState<string>("");
@@ -51,7 +49,7 @@ export const SetupNoteBooksPanel: FunctionComponent<SetupNoteBooksPanelProps> =
const startKey: number = TelemetryProcessor.traceStart(Action.CreateNotebookWorkspace, {
dataExplorerArea: Areas.ContextualPane,
paneTitle: title,
paneTitle: panelTitle,
});
const clear = NotificationConsoleUtils.logConsoleProgress("Creating a new default notebook workspace");
@@ -64,13 +62,13 @@ export const SetupNoteBooksPanel: FunctionComponent<SetupNoteBooksPanelProps> =
);
explorer.isAccountReady.valueHasMutated(); // re-trigger init notebooks
closePanel();
closeSidePanel();
TelemetryProcessor.traceSuccess(
Action.CreateNotebookWorkspace,
{
dataExplorerArea: Areas.ContextualPane,
paneTitle: title,
paneTitle: panelTitle,
},
startKey
);
@@ -81,7 +79,7 @@ export const SetupNoteBooksPanel: FunctionComponent<SetupNoteBooksPanelProps> =
Action.CreateNotebookWorkspace,
{
dataExplorerArea: Areas.ContextualPane,
paneTitle: title,
paneTitle: panelTitle,
error: errorMessage,
errorStack: getErrorStack(error),
},
@@ -99,12 +97,7 @@ export const SetupNoteBooksPanel: FunctionComponent<SetupNoteBooksPanelProps> =
return (
<form className="panelFormWrapper">
{errorMessage && (
<PanelInfoErrorComponent
message={errorMessage}
messageType="error"
showErrorDetails={showErrorDetails}
openNotificationConsole={openNotificationConsole}
/>
<PanelInfoErrorComponent message={errorMessage} messageType="error" showErrorDetails={showErrorDetails} />
)}
<div className="panelMainContent">
<div className="pkPadding">

View File

@@ -89,7 +89,6 @@ export const StringInputPane: FunctionComponent<StringInputPanelProps> = ({
isExecuting: isExecuting,
submitButtonText: submitButtonLabel,
onSubmit: submit,
expandConsole: () => container.expandConsole(),
};
return (
<RightPaneForm {...props}>

View File

@@ -7,837 +7,32 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
errorMessage="Could not create directory "
explorer={
Explorer {
"_isAfecFeatureRegistered": [Function],
"_isInitializingNotebooks": false,
"_refreshSparkEnabledStateForAccount": [Function],
"_resetNotebookWorkspace": [Function],
"addCollectionText": [Function],
"arcadiaToken": [Function],
"canExceedMaximumValue": [Function],
"canSaveQueries": [Function],
"closeSidePanel": undefined,
"collapsedResourceTreeWidth": 36,
"collectionCreationDefaults": Object {
"storage": "100",
"throughput": Object {
"fixed": 400,
"shared": 400,
"unlimited": 400,
"unlimitedmax": 1000000,
"unlimitedmin": 400,
},
},
"collectionTitle": [Function],
"collectionTreeNodeAltText": [Function],
"commandBarComponentAdapter": CommandBarComponentAdapter {
"container": [Circular],
"isNotebookTabActive": [Function],
"parameters": [Function],
"tabsButtons": Array [],
},
"databases": [Function],
"deleteCollectionText": [Function],
"deleteDatabaseText": [Function],
"gitHubClient": GitHubClient {
"errorCallback": [Function],
"ocktokit": OctokitWithDefaults {
"actions": Object {
"addSelectedRepoToOrgSecret": [Function],
"cancelWorkflowRun": [Function],
"createOrUpdateOrgSecret": [Function],
"createOrUpdateRepoSecret": [Function],
"createOrUpdateSecretForRepo": [Function],
"createRegistrationToken": [Function],
"createRegistrationTokenForOrg": [Function],
"createRegistrationTokenForRepo": [Function],
"createRemoveToken": [Function],
"createRemoveTokenForOrg": [Function],
"createRemoveTokenForRepo": [Function],
"deleteArtifact": [Function],
"deleteOrgSecret": [Function],
"deleteRepoSecret": [Function],
"deleteSecretFromRepo": [Function],
"deleteSelfHostedRunnerFromOrg": [Function],
"deleteSelfHostedRunnerFromRepo": [Function],
"deleteWorkflowRunLogs": [Function],
"downloadArtifact": [Function],
"downloadJobLogsForWorkflowRun": [Function],
"downloadWorkflowJobLogs": [Function],
"downloadWorkflowRunLogs": [Function],
"getArtifact": [Function],
"getJobForWorkflowRun": [Function],
"getOrgPublicKey": [Function],
"getOrgSecret": [Function],
"getPublicKey": [Function],
"getRepoPublicKey": [Function],
"getRepoSecret": [Function],
"getSecret": [Function],
"getSelfHostedRunner": [Function],
"getSelfHostedRunnerForOrg": [Function],
"getSelfHostedRunnerForRepo": [Function],
"getWorkflow": [Function],
"getWorkflowJob": [Function],
"getWorkflowRun": [Function],
"getWorkflowRunUsage": [Function],
"getWorkflowUsage": [Function],
"listArtifactsForRepo": [Function],
"listDownloadsForSelfHostedRunnerApplication": [Function],
"listJobsForWorkflowRun": [Function],
"listOrgSecrets": [Function],
"listRepoSecrets": [Function],
"listRepoWorkflowRuns": [Function],
"listRepoWorkflows": [Function],
"listRunnerApplicationsForOrg": [Function],
"listRunnerApplicationsForRepo": [Function],
"listSecretsForRepo": [Function],
"listSelectedReposForOrgSecret": [Function],
"listSelfHostedRunnersForOrg": [Function],
"listSelfHostedRunnersForRepo": [Function],
"listWorkflowJobLogs": [Function],
"listWorkflowRunArtifacts": [Function],
"listWorkflowRunLogs": [Function],
"listWorkflowRuns": [Function],
"listWorkflowRunsForRepo": [Function],
"reRunWorkflow": [Function],
"removeSelectedRepoFromOrgSecret": [Function],
"removeSelfHostedRunner": [Function],
"setSelectedReposForOrgSecret": [Function],
},
"activity": Object {
"checkRepoIsStarredByAuthenticatedUser": [Function],
"checkStarringRepo": [Function],
"deleteRepoSubscription": [Function],
"deleteThreadSubscription": [Function],
"getFeeds": [Function],
"getRepoSubscription": [Function],
"getThread": [Function],
"getThreadSubscription": [Function],
"getThreadSubscriptionForAuthenticatedUser": [Function],
"listEventsForAuthenticatedUser": [Function],
"listEventsForOrg": [Function],
"listEventsForUser": [Function],
"listFeeds": [Function],
"listNotifications": [Function],
"listNotificationsForAuthenticatedUser": [Function],
"listNotificationsForRepo": [Function],
"listOrgEventsForAuthenticatedUser": [Function],
"listPublicEvents": [Function],
"listPublicEventsForOrg": [Function],
"listPublicEventsForRepoNetwork": [Function],
"listPublicEventsForUser": [Function],
"listPublicOrgEvents": [Function],
"listReceivedEventsForUser": [Function],
"listReceivedPublicEventsForUser": [Function],
"listRepoEvents": [Function],
"listRepoNotificationsForAuthenticatedUser": [Function],
"listReposStarredByAuthenticatedUser": [Function],
"listReposStarredByUser": [Function],
"listReposWatchedByUser": [Function],
"listStargazersForRepo": [Function],
"listWatchedReposForAuthenticatedUser": [Function],
"listWatchersForRepo": [Function],
"markAsRead": [Function],
"markNotificationsAsRead": [Function],
"markNotificationsAsReadForRepo": [Function],
"markRepoNotificationsAsRead": [Function],
"markThreadAsRead": [Function],
"setRepoSubscription": [Function],
"setThreadSubscription": [Function],
"starRepo": [Function],
"starRepoForAuthenticatedUser": [Function],
"unstarRepo": [Function],
"unstarRepoForAuthenticatedUser": [Function],
},
"apps": Object {
"addRepoToInstallation": [Function],
"checkAccountIsAssociatedWithAny": [Function],
"checkAccountIsAssociatedWithAnyStubbed": [Function],
"checkToken": [Function],
"createContentAttachment": [Function],
"createFromManifest": [Function],
"createInstallationAccessToken": [Function],
"createInstallationToken": [Function],
"deleteAuthorization": [Function],
"deleteInstallation": [Function],
"deleteToken": [Function],
"getAuthenticated": [Function],
"getBySlug": [Function],
"getInstallation": [Function],
"getOrgInstallation": [Function],
"getRepoInstallation": [Function],
"getSubscriptionPlanForAccount": [Function],
"getSubscriptionPlanForAccountStubbed": [Function],
"getUserInstallation": [Function],
"listAccountsForPlan": [Function],
"listAccountsForPlanStubbed": [Function],
"listAccountsUserOrOrgOnPlan": [Function],
"listAccountsUserOrOrgOnPlanStubbed": [Function],
"listInstallationReposForAuthenticatedUser": [Function],
"listInstallations": [Function],
"listInstallationsForAuthenticatedUser": [Function],
"listMarketplacePurchasesForAuthenticatedUser": [Function],
"listMarketplacePurchasesForAuthenticatedUserStubbed": [Function],
"listPlans": [Function],
"listPlansStubbed": [Function],
"listRepos": [Function],
"listReposAccessibleToInstallation": [Function],
"listSubscriptionsForAuthenticatedUser": [Function],
"listSubscriptionsForAuthenticatedUserStubbed": [Function],
"removeRepoFromInstallation": [Function],
"resetToken": [Function],
"revokeInstallationAccessToken": [Function],
"revokeInstallationToken": [Function],
"suspendInstallation": [Function],
"unsuspendInstallation": [Function],
},
"auth": [Function],
"checks": Object {
"create": [Function],
"createSuite": [Function],
"get": [Function],
"getSuite": [Function],
"listAnnotations": [Function],
"listForRef": [Function],
"listForSuite": [Function],
"listSuitesForRef": [Function],
"rerequestSuite": [Function],
"setSuitesPreferences": [Function],
"update": [Function],
},
"codeScanning": Object {
"getAlert": [Function],
"listAlertsForRepo": [Function],
},
"codesOfConduct": Object {
"getAllCodesOfConduct": [Function],
"getConductCode": [Function],
"getForRepo": [Function],
"listConductCodes": [Function],
},
"emojis": Object {
"get": [Function],
},
"gists": Object {
"checkIsStarred": [Function],
"create": [Function],
"createComment": [Function],
"delete": [Function],
"deleteComment": [Function],
"fork": [Function],
"get": [Function],
"getComment": [Function],
"getRevision": [Function],
"list": [Function],
"listComments": [Function],
"listCommits": [Function],
"listForUser": [Function],
"listForks": [Function],
"listPublic": [Function],
"listPublicForUser": [Function],
"listStarred": [Function],
"star": [Function],
"unstar": [Function],
"update": [Function],
"updateComment": [Function],
},
"git": Object {
"createBlob": [Function],
"createCommit": [Function],
"createRef": [Function],
"createTag": [Function],
"createTree": [Function],
"deleteRef": [Function],
"getBlob": [Function],
"getCommit": [Function],
"getRef": [Function],
"getTag": [Function],
"getTree": [Function],
"listMatchingRefs": [Function],
"updateRef": [Function],
},
"gitignore": Object {
"getAllTemplates": [Function],
"getTemplate": [Function],
"listTemplates": [Function],
},
"graphql": [Function],
"hook": [Function],
"interactions": Object {
"addOrUpdateRestrictionsForOrg": [Function],
"addOrUpdateRestrictionsForRepo": [Function],
"getRestrictionsForOrg": [Function],
"getRestrictionsForRepo": [Function],
"removeRestrictionsForOrg": [Function],
"removeRestrictionsForRepo": [Function],
"setRestrictionsForOrg": [Function],
"setRestrictionsForRepo": [Function],
},
"issues": Object {
"addAssignees": [Function],
"addLabels": [Function],
"checkAssignee": [Function],
"checkUserCanBeAssigned": [Function],
"create": [Function],
"createComment": [Function],
"createLabel": [Function],
"createMilestone": [Function],
"deleteComment": [Function],
"deleteLabel": [Function],
"deleteMilestone": [Function],
"get": [Function],
"getComment": [Function],
"getEvent": [Function],
"getLabel": [Function],
"getMilestone": [Function],
"list": [Function],
"listAssignees": [Function],
"listComments": [Function],
"listCommentsForRepo": [Function],
"listEvents": [Function],
"listEventsForRepo": [Function],
"listEventsForTimeline": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listForRepo": [Function],
"listLabelsForMilestone": [Function],
"listLabelsForRepo": [Function],
"listLabelsOnIssue": [Function],
"listMilestones": [Function],
"listMilestonesForRepo": [Function],
"lock": [Function],
"removeAllLabels": [Function],
"removeAssignees": [Function],
"removeLabel": [Function],
"removeLabels": [Function],
"replaceAllLabels": [Function],
"replaceLabels": [Function],
"setLabels": [Function],
"unlock": [Function],
"update": [Function],
"updateComment": [Function],
"updateLabel": [Function],
"updateMilestone": [Function],
},
"licenses": Object {
"get": [Function],
"getAllCommonlyUsed": [Function],
"getForRepo": [Function],
"listCommonlyUsed": [Function],
},
"log": Object {
"debug": [Function],
"error": [Function],
"info": [Function],
"warn": [Function],
},
"markdown": Object {
"render": [Function],
"renderRaw": [Function],
},
"meta": Object {
"get": [Function],
},
"migrations": Object {
"cancelImport": [Function],
"deleteArchiveForAuthenticatedUser": [Function],
"deleteArchiveForOrg": [Function],
"downloadArchiveForOrg": [Function],
"getArchiveForAuthenticatedUser": [Function],
"getCommitAuthors": [Function],
"getImportProgress": [Function],
"getImportStatus": [Function],
"getLargeFiles": [Function],
"getStatusForAuthenticatedUser": [Function],
"getStatusForOrg": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listReposForOrg": [Function],
"listReposForUser": [Function],
"mapCommitAuthor": [Function],
"setLfsPreference": [Function],
"startForAuthenticatedUser": [Function],
"startForOrg": [Function],
"startImport": [Function],
"unlockRepoForAuthenticatedUser": [Function],
"unlockRepoForOrg": [Function],
"updateImport": [Function],
},
"orgs": Object {
"addOrUpdateMembership": [Function],
"blockUser": [Function],
"checkBlockedUser": [Function],
"checkMembership": [Function],
"checkMembershipForUser": [Function],
"checkPublicMembership": [Function],
"checkPublicMembershipForUser": [Function],
"concealMembership": [Function],
"convertMemberToOutsideCollaborator": [Function],
"createHook": [Function],
"createInvitation": [Function],
"createWebhook": [Function],
"deleteHook": [Function],
"deleteWebhook": [Function],
"get": [Function],
"getHook": [Function],
"getMembership": [Function],
"getMembershipForAuthenticatedUser": [Function],
"getMembershipForUser": [Function],
"getWebhook": [Function],
"list": [Function],
"listAppInstallations": [Function],
"listBlockedUsers": [Function],
"listForAuthenticatedUser": [Function],
"listForUser": [Function],
"listHooks": [Function],
"listInstallations": [Function],
"listInvitationTeams": [Function],
"listMembers": [Function],
"listMemberships": [Function],
"listMembershipsForAuthenticatedUser": [Function],
"listOutsideCollaborators": [Function],
"listPendingInvitations": [Function],
"listPublicMembers": [Function],
"listWebhooks": [Function],
"pingHook": [Function],
"pingWebhook": [Function],
"publicizeMembership": [Function],
"removeMember": [Function],
"removeMembership": [Function],
"removeMembershipForUser": [Function],
"removeOutsideCollaborator": [Function],
"removePublicMembershipForAuthenticatedUser": [Function],
"setMembershipForUser": [Function],
"setPublicMembershipForAuthenticatedUser": [Function],
"unblockUser": [Function],
"update": [Function],
"updateHook": [Function],
"updateMembership": [Function],
"updateMembershipForAuthenticatedUser": [Function],
"updateWebhook": [Function],
},
"paginate": [Function],
"projects": Object {
"addCollaborator": [Function],
"createCard": [Function],
"createColumn": [Function],
"createForAuthenticatedUser": [Function],
"createForOrg": [Function],
"createForRepo": [Function],
"delete": [Function],
"deleteCard": [Function],
"deleteColumn": [Function],
"get": [Function],
"getCard": [Function],
"getColumn": [Function],
"getPermissionForUser": [Function],
"listCards": [Function],
"listCollaborators": [Function],
"listColumns": [Function],
"listForOrg": [Function],
"listForRepo": [Function],
"listForUser": [Function],
"moveCard": [Function],
"moveColumn": [Function],
"removeCollaborator": [Function],
"reviewUserPermissionLevel": [Function],
"update": [Function],
"updateCard": [Function],
"updateColumn": [Function],
},
"pulls": Object {
"checkIfMerged": [Function],
"create": [Function],
"createComment": [Function],
"createReplyForReviewComment": [Function],
"createReview": [Function],
"createReviewComment": [Function],
"createReviewCommentReply": [Function],
"createReviewRequest": [Function],
"deleteComment": [Function],
"deletePendingReview": [Function],
"deleteReviewComment": [Function],
"deleteReviewRequest": [Function],
"dismissReview": [Function],
"get": [Function],
"getComment": [Function],
"getCommentsForReview": [Function],
"getReview": [Function],
"getReviewComment": [Function],
"list": [Function],
"listComments": [Function],
"listCommentsForRepo": [Function],
"listCommentsForReview": [Function],
"listCommits": [Function],
"listFiles": [Function],
"listRequestedReviewers": [Function],
"listReviewComments": [Function],
"listReviewCommentsForRepo": [Function],
"listReviewRequests": [Function],
"listReviews": [Function],
"merge": [Function],
"removeRequestedReviewers": [Function],
"requestReviewers": [Function],
"submitReview": [Function],
"update": [Function],
"updateBranch": [Function],
"updateComment": [Function],
"updateReview": [Function],
"updateReviewComment": [Function],
},
"rateLimit": Object {
"get": [Function],
},
"reactions": Object {
"createForCommitComment": [Function],
"createForIssue": [Function],
"createForIssueComment": [Function],
"createForPullRequestReviewComment": [Function],
"createForTeamDiscussionCommentInOrg": [Function],
"createForTeamDiscussionInOrg": [Function],
"delete": [Function],
"deleteForCommitComment": [Function],
"deleteForIssue": [Function],
"deleteForIssueComment": [Function],
"deleteForPullRequestComment": [Function],
"deleteForTeamDiscussion": [Function],
"deleteForTeamDiscussionComment": [Function],
"deleteLegacy": [Function],
"listForCommitComment": [Function],
"listForIssue": [Function],
"listForIssueComment": [Function],
"listForPullRequestReviewComment": [Function],
"listForTeamDiscussionCommentInOrg": [Function],
"listForTeamDiscussionInOrg": [Function],
},
"repos": Object {
"acceptInvitation": [Function],
"addAppAccessRestrictions": [Function],
"addCollaborator": [Function],
"addDeployKey": [Function],
"addProtectedBranchAdminEnforcement": [Function],
"addProtectedBranchAppRestrictions": [Function],
"addProtectedBranchRequiredSignatures": [Function],
"addProtectedBranchRequiredStatusChecksContexts": [Function],
"addProtectedBranchTeamRestrictions": [Function],
"addProtectedBranchUserRestrictions": [Function],
"addStatusCheckContexts": [Function],
"addTeamAccessRestrictions": [Function],
"addUserAccessRestrictions": [Function],
"checkCollaborator": [Function],
"checkVulnerabilityAlerts": [Function],
"compareCommits": [Function],
"createCommitComment": [Function],
"createCommitSignatureProtection": [Function],
"createCommitStatus": [Function],
"createDeployKey": [Function],
"createDeployment": [Function],
"createDeploymentStatus": [Function],
"createDispatchEvent": [Function],
"createForAuthenticatedUser": [Function],
"createFork": [Function],
"createHook": [Function],
"createInOrg": [Function],
"createOrUpdateFile": [Function],
"createOrUpdateFileContents": [Function],
"createPagesSite": [Function],
"createRelease": [Function],
"createStatus": [Function],
"createUsingTemplate": [Function],
"createWebhook": [Function],
"declineInvitation": [Function],
"delete": [Function],
"deleteAccessRestrictions": [Function],
"deleteAdminBranchProtection": [Function],
"deleteBranchProtection": [Function],
"deleteCommitComment": [Function],
"deleteCommitSignatureProtection": [Function],
"deleteDeployKey": [Function],
"deleteDeployment": [Function],
"deleteDownload": [Function],
"deleteFile": [Function],
"deleteHook": [Function],
"deleteInvitation": [Function],
"deletePagesSite": [Function],
"deletePullRequestReviewProtection": [Function],
"deleteRelease": [Function],
"deleteReleaseAsset": [Function],
"deleteWebhook": [Function],
"disableAutomatedSecurityFixes": [Function],
"disablePagesSite": [Function],
"disableVulnerabilityAlerts": [Function],
"downloadArchive": [Function],
"enableAutomatedSecurityFixes": [Function],
"enablePagesSite": [Function],
"enableVulnerabilityAlerts": [Function],
"get": [Function],
"getAccessRestrictions": [Function],
"getAdminBranchProtection": [Function],
"getAllStatusCheckContexts": [Function],
"getAllTopics": [Function],
"getAppsWithAccessToProtectedBranch": [Function],
"getArchiveLink": [Function],
"getBranch": [Function],
"getBranchProtection": [Function],
"getClones": [Function],
"getCodeFrequencyStats": [Function],
"getCollaboratorPermissionLevel": [Function],
"getCombinedStatusForRef": [Function],
"getCommit": [Function],
"getCommitActivityStats": [Function],
"getCommitComment": [Function],
"getCommitSignatureProtection": [Function],
"getCommunityProfileMetrics": [Function],
"getContent": [Function],
"getContents": [Function],
"getContributorsStats": [Function],
"getDeployKey": [Function],
"getDeployment": [Function],
"getDeploymentStatus": [Function],
"getDownload": [Function],
"getHook": [Function],
"getLatestPagesBuild": [Function],
"getLatestRelease": [Function],
"getPages": [Function],
"getPagesBuild": [Function],
"getParticipationStats": [Function],
"getProtectedBranchAdminEnforcement": [Function],
"getProtectedBranchPullRequestReviewEnforcement": [Function],
"getProtectedBranchRequiredSignatures": [Function],
"getProtectedBranchRequiredStatusChecks": [Function],
"getProtectedBranchRestrictions": [Function],
"getPullRequestReviewProtection": [Function],
"getPunchCardStats": [Function],
"getReadme": [Function],
"getRelease": [Function],
"getReleaseAsset": [Function],
"getReleaseByTag": [Function],
"getStatusChecksProtection": [Function],
"getTeamsWithAccessToProtectedBranch": [Function],
"getTopPaths": [Function],
"getTopReferrers": [Function],
"getUsersWithAccessToProtectedBranch": [Function],
"getViews": [Function],
"getWebhook": [Function],
"list": [Function],
"listAssetsForRelease": [Function],
"listBranches": [Function],
"listBranchesForHeadCommit": [Function],
"listCollaborators": [Function],
"listCommentsForCommit": [Function],
"listCommitComments": [Function],
"listCommitCommentsForRepo": [Function],
"listCommitStatusesForRef": [Function],
"listCommits": [Function],
"listContributors": [Function],
"listDeployKeys": [Function],
"listDeploymentStatuses": [Function],
"listDeployments": [Function],
"listDownloads": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listForUser": [Function],
"listForks": [Function],
"listHooks": [Function],
"listInvitations": [Function],
"listInvitationsForAuthenticatedUser": [Function],
"listLanguages": [Function],
"listPagesBuilds": [Function],
"listProtectedBranchRequiredStatusChecksContexts": [Function],
"listPublic": [Function],
"listPullRequestsAssociatedWithCommit": [Function],
"listReleaseAssets": [Function],
"listReleases": [Function],
"listStatusesForRef": [Function],
"listTags": [Function],
"listTeams": [Function],
"listTopics": [Function],
"listWebhooks": [Function],
"merge": [Function],
"pingHook": [Function],
"pingWebhook": [Function],
"removeAppAccessRestrictions": [Function],
"removeBranchProtection": [Function],
"removeCollaborator": [Function],
"removeDeployKey": [Function],
"removeProtectedBranchAdminEnforcement": [Function],
"removeProtectedBranchAppRestrictions": [Function],
"removeProtectedBranchPullRequestReviewEnforcement": [Function],
"removeProtectedBranchRequiredSignatures": [Function],
"removeProtectedBranchRequiredStatusChecks": [Function],
"removeProtectedBranchRequiredStatusChecksContexts": [Function],
"removeProtectedBranchRestrictions": [Function],
"removeProtectedBranchTeamRestrictions": [Function],
"removeProtectedBranchUserRestrictions": [Function],
"removeStatusCheckContexts": [Function],
"removeStatusCheckProtection": [Function],
"removeTeamAccessRestrictions": [Function],
"removeUserAccessRestrictions": [Function],
"replaceAllTopics": [Function],
"replaceProtectedBranchAppRestrictions": [Function],
"replaceProtectedBranchRequiredStatusChecksContexts": [Function],
"replaceProtectedBranchTeamRestrictions": [Function],
"replaceProtectedBranchUserRestrictions": [Function],
"replaceTopics": [Function],
"requestPageBuild": [Function],
"requestPagesBuild": [Function],
"retrieveCommunityProfileMetrics": [Function],
"setAdminBranchProtection": [Function],
"setAppAccessRestrictions": [Function],
"setStatusCheckContexts": [Function],
"setTeamAccessRestrictions": [Function],
"setUserAccessRestrictions": [Function],
"testPushHook": [Function],
"testPushWebhook": [Function],
"transfer": [Function],
"update": [Function],
"updateBranchProtection": [Function],
"updateCommitComment": [Function],
"updateHook": [Function],
"updateInformationAboutPagesSite": [Function],
"updateInvitation": [Function],
"updateProtectedBranchPullRequestReviewEnforcement": [Function],
"updateProtectedBranchRequiredStatusChecks": [Function],
"updatePullRequestReviewProtection": [Function],
"updateRelease": [Function],
"updateReleaseAsset": [Function],
"updateStatusCheckPotection": [Function],
"updateWebhook": [Function],
"uploadReleaseAsset": [Function],
},
"request": [Function],
"search": Object {
"code": [Function],
"commits": [Function],
"issuesAndPullRequests": [Function],
"labels": [Function],
"repos": [Function],
"topics": [Function],
"users": [Function],
},
"teams": Object {
"addOrUpdateMembershipForUserInOrg": [Function],
"addOrUpdateMembershipInOrg": [Function],
"addOrUpdateProjectInOrg": [Function],
"addOrUpdateProjectPermissionsInOrg": [Function],
"addOrUpdateRepoInOrg": [Function],
"addOrUpdateRepoPermissionsInOrg": [Function],
"checkManagesRepoInOrg": [Function],
"checkPermissionsForProjectInOrg": [Function],
"checkPermissionsForRepoInOrg": [Function],
"create": [Function],
"createDiscussionCommentInOrg": [Function],
"createDiscussionInOrg": [Function],
"deleteDiscussionCommentInOrg": [Function],
"deleteDiscussionInOrg": [Function],
"deleteInOrg": [Function],
"getByName": [Function],
"getDiscussionCommentInOrg": [Function],
"getDiscussionInOrg": [Function],
"getMembershipForUserInOrg": [Function],
"getMembershipInOrg": [Function],
"list": [Function],
"listChildInOrg": [Function],
"listDiscussionCommentsInOrg": [Function],
"listDiscussionsInOrg": [Function],
"listForAuthenticatedUser": [Function],
"listMembersInOrg": [Function],
"listPendingInvitationsInOrg": [Function],
"listProjectsInOrg": [Function],
"listReposInOrg": [Function],
"removeMembershipForUserInOrg": [Function],
"removeMembershipInOrg": [Function],
"removeProjectInOrg": [Function],
"removeRepoInOrg": [Function],
"reviewProjectInOrg": [Function],
"updateDiscussionCommentInOrg": [Function],
"updateDiscussionInOrg": [Function],
"updateInOrg": [Function],
},
"users": Object {
"addEmailForAuthenticated": [Function],
"addEmails": [Function],
"block": [Function],
"checkBlocked": [Function],
"checkFollowing": [Function],
"checkFollowingForUser": [Function],
"checkPersonIsFollowedByAuthenticated": [Function],
"createGpgKey": [Function],
"createGpgKeyForAuthenticated": [Function],
"createPublicKey": [Function],
"createPublicSshKeyForAuthenticated": [Function],
"deleteEmailForAuthenticated": [Function],
"deleteEmails": [Function],
"deleteGpgKey": [Function],
"deleteGpgKeyForAuthenticated": [Function],
"deletePublicKey": [Function],
"deletePublicSshKeyForAuthenticated": [Function],
"follow": [Function],
"getAuthenticated": [Function],
"getByUsername": [Function],
"getContextForUser": [Function],
"getGpgKey": [Function],
"getGpgKeyForAuthenticated": [Function],
"getPublicKey": [Function],
"getPublicSshKeyForAuthenticated": [Function],
"list": [Function],
"listBlocked": [Function],
"listBlockedByAuthenticated": [Function],
"listEmails": [Function],
"listEmailsForAuthenticated": [Function],
"listFollowedByAuthenticated": [Function],
"listFollowersForAuthenticatedUser": [Function],
"listFollowersForUser": [Function],
"listFollowingForAuthenticatedUser": [Function],
"listFollowingForUser": [Function],
"listGpgKeys": [Function],
"listGpgKeysForAuthenticated": [Function],
"listGpgKeysForUser": [Function],
"listPublicEmails": [Function],
"listPublicEmailsForAuthenticated": [Function],
"listPublicKeys": [Function],
"listPublicKeysForUser": [Function],
"listPublicSshKeysForAuthenticated": [Function],
"setPrimaryEmailVisibilityForAuthenticated": [Function],
"togglePrimaryEmailVisibility": [Function],
"unblock": [Function],
"unfollow": [Function],
"updateAuthenticated": [Function],
},
},
},
"hasStorageAnalyticsAfecFeature": [Function],
"isAccountReady": [Function],
"isFixedCollectionWithSharedThroughputSupported": [Function],
"isHostedDataExplorerEnabled": [Function],
"isLeftPaneExpanded": [Function],
"isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function],
"isPublishNotebookPaneEnabled": [Function],
"isResourceTokenCollectionNodeSelected": [Function],
"isSchemaEnabled": [Function],
"isServerlessEnabled": [Function],
"isShellEnabled": [Function],
"isSparkEnabled": [Function],
"isSparkEnabledForAccount": [Function],
"isSynapseLinkUpdating": [Function],
"isTabsContentExpanded": [Function],
"junoClient": JunoClient {
"cachedPinnedRepos": [Function],
},
"memoryUsageInfo": [Function],
"notebookBasePath": [Function],
"notebookServerInfo": [Function],
"onGitHubClientError": [Function],
"onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function],
"openSidePanel": undefined,
"provideFeedbackEmail": [Function],
"queriesClient": QueriesClient {
"container": [Circular],
},
"refreshNotebookList": [Function],
"refreshTreeTitle": [Function],
"resourceTokenCollection": [Function],
"resourceTokenCollectionId": [Function],
"resourceTokenDatabaseId": [Function],
@@ -857,7 +52,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
"selectedDatabaseId": [Function],
"selectedNode": [Function],
"setInProgressConsoleDataIdToBeDeleted": undefined,
"setIsNotificationConsoleExpanded": undefined,
"setNotificationConsoleData": undefined,
"sparkClusterConnectionInfo": [Function],
"splitter": Splitter {
@@ -876,7 +70,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
"activeTab": [Function],
"openedTabs": [Function],
},
"toggleLeftPaneExpandedKeyPress": [Function],
}
}
inProgressMessage="Creating directory "
@@ -895,7 +88,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
successMessage="Created directory "
>
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -1,23 +1,20 @@
import { mount } from "enzyme";
import * as ko from "knockout";
import React from "react";
import Explorer from "../../Explorer";
import TableListViewModal from "../../Tables/DataTable/TableEntityListViewModel";
import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient } from "../../Tables/TableDataClient";
import { CassandraAPIDataClient, TablesAPIDataClient } from "../../Tables/TableDataClient";
import QueryTablesTab from "../../Tabs/QueryTablesTab";
import { AddTableEntityPanel } from "./AddTableEntityPanel";
describe("Excute Add Table Entity Pane", () => {
const fakeExplorer = {} as Explorer;
const fakeQueryTablesTab = {} as QueryTablesTab;
const fakeTableEntityListViewModel = {} as TableListViewModal;
const fakeCassandraApiClient = {} as CassandraAPIDataClient;
fakeTableEntityListViewModel.items = ko.observableArray<Entities.ITableEntity>();
fakeTableEntityListViewModel.headers = [];
const props = {
explorer: fakeExplorer,
closePanel: (): void => undefined,
tableDataClient: new TablesAPIDataClient(),
queryTablesTab: fakeQueryTablesTab,
tableEntityListViewModel: fakeTableEntityListViewModel,
cassandraApiClient: fakeCassandraApiClient,

View File

@@ -5,13 +5,13 @@ import * as _ from "underscore";
import AddPropertyIcon from "../../../../images/Add-property.svg";
import RevertBackIcon from "../../../../images/RevertBack.svg";
import { TableEntity } from "../../../Common/TableEntity";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { userContext } from "../../../UserContext";
import Explorer from "../../Explorer";
import * as TableConstants from "../../Tables/Constants";
import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities";
import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel";
import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient, CassandraTableKey } from "../../Tables/TableDataClient";
import { CassandraAPIDataClient, CassandraTableKey, TableDataClient } from "../../Tables/TableDataClient";
import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
import * as Utilities from "../../Tables/Utilities";
import QueryTablesTab from "../../Tabs/QueryTablesTab";
@@ -37,8 +37,7 @@ import {
} from "./Validators/EntityTableHelper";
interface AddTableEntityPanelProps {
explorer: Explorer;
closePanel: () => void;
tableDataClient: TableDataClient;
queryTablesTab: QueryTablesTab;
tableEntityListViewModel: TableEntityListViewModel;
cassandraApiClient: CassandraAPIDataClient;
@@ -57,12 +56,12 @@ interface EntityRowType {
}
export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> = ({
explorer,
closePanel,
tableDataClient,
queryTablesTab,
tableEntityListViewModel,
cassandraApiClient,
}: AddTableEntityPanelProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [entities, setEntities] = useState<EntityRowType[]>([]);
const [selectedRow, setSelectedRow] = useState<number>(0);
const [entityAttributeValue, setEntityAttributeValue] = useState<string>("");
@@ -106,15 +105,12 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
event.preventDefault();
const entity: Entities.ITableEntity = entityFromAttributes(entities);
const newEntity: Entities.ITableEntity = await explorer.tableDataClient.createDocument(
queryTablesTab.collection,
entity
);
const newEntity: Entities.ITableEntity = await tableDataClient.createDocument(queryTablesTab.collection, entity);
await tableEntityListViewModel.addEntityToCache(newEntity);
if (!tryInsertNewHeaders(tableEntityListViewModel, newEntity)) {
tableEntityListViewModel.redrawTableThrottled();
}
closePanel();
closeSidePanel();
};
const tryInsertNewHeaders = (viewModel: TableEntityListViewModel, newEntity: Entities.ITableEntity): boolean => {
@@ -296,7 +292,6 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
}}
/>
}
closePanel={() => closePanel()}
isConsoleExpanded={false}
/>
);
@@ -308,7 +303,6 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
panelWidth="700px"
isOpen={true}
panelContent={renderPanelContent()}
closePanel={() => closePanel()}
isConsoleExpanded={false}
/>
);

View File

@@ -1,15 +1,13 @@
import { mount } from "enzyme";
import * as ko from "knockout";
import React from "react";
import Explorer from "../../Explorer";
import TableListViewModal from "../../Tables/DataTable/TableEntityListViewModel";
import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient } from "../../Tables/TableDataClient";
import { CassandraAPIDataClient, TablesAPIDataClient } from "../../Tables/TableDataClient";
import QueryTablesTab from "../../Tabs/QueryTablesTab";
import { EditTableEntityPanel } from "./EditTableEntityPanel";
describe("Excute Edit Table Entity Pane", () => {
const fakeExplorer = {} as Explorer;
const fakeQueryTablesTab = {} as QueryTablesTab;
const fakeTableEntityListViewModel = {} as TableListViewModal;
fakeTableEntityListViewModel.items = ko.observableArray<Entities.ITableEntity>();
@@ -18,8 +16,7 @@ describe("Excute Edit Table Entity Pane", () => {
fakeTableEntityListViewModel.selected = ko.observableArray<Entities.ITableEntity>([{}]);
const props = {
explorer: fakeExplorer,
closePanel: (): void => undefined,
tableDataClient: new TablesAPIDataClient(),
queryTablesTab: fakeQueryTablesTab,
tableEntityListViewModel: fakeTableEntityListViewModel,
cassandraApiClient: fakeCassandraApiClient,

View File

@@ -5,13 +5,13 @@ import * as _ from "underscore";
import AddPropertyIcon from "../../../../images/Add-property.svg";
import RevertBackIcon from "../../../../images/RevertBack.svg";
import { TableEntity } from "../../../Common/TableEntity";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { userContext } from "../../../UserContext";
import Explorer from "../../Explorer";
import * as TableConstants from "../../Tables/Constants";
import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities";
import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel";
import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient } from "../../Tables/TableDataClient";
import { CassandraAPIDataClient, TableDataClient } from "../../Tables/TableDataClient";
import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
import QueryTablesTab from "../../Tabs/QueryTablesTab";
import { PanelContainerComponent } from "../PanelContainerComponent";
@@ -34,8 +34,7 @@ import {
} from "./Validators/EntityTableHelper";
interface EditTableEntityPanelProps {
explorer: Explorer;
closePanel: () => void;
tableDataClient: TableDataClient;
queryTablesTab: QueryTablesTab;
tableEntityListViewModel: TableEntityListViewModel;
cassandraApiClient: CassandraAPIDataClient;
@@ -55,12 +54,12 @@ interface EntityRowType {
}
export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps> = ({
explorer,
closePanel,
tableDataClient,
queryTablesTab,
tableEntityListViewModel,
cassandraApiClient,
}: EditTableEntityPanelProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [entities, setEntities] = useState<EntityRowType[]>([]);
const [selectedRow, setSelectedRow] = useState<number>(0);
const [entityAttributeValue, setEntityAttributeValue] = useState<string>("");
@@ -197,9 +196,9 @@ export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps>
}
event.preventDefault();
const entity: Entities.ITableEntity = entityFromAttributes(entities);
const tableDataClient = userContext.apiType === "Cassandra" ? cassandraApiClient : explorer.tableDataClient;
const newTableDataClient = userContext.apiType === "Cassandra" ? cassandraApiClient : tableDataClient;
const originalDocumentData = userContext.apiType === "Cassandra" ? originalDocument[0] : originalDocument;
const newEntity: Entities.ITableEntity = await tableDataClient.updateDocument(
const newEntity: Entities.ITableEntity = await newTableDataClient.updateDocument(
queryTablesTab.collection,
originalDocumentData,
entity
@@ -210,7 +209,7 @@ export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps>
}
tableEntityListViewModel.selected.removeAll();
tableEntityListViewModel.selected.push(newEntity);
closePanel();
closeSidePanel();
};
const tryInsertNewHeaders = (viewModel: TableEntityListViewModel, newEntity: Entities.ITableEntity): boolean => {
@@ -391,7 +390,6 @@ export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps>
}}
/>
}
closePanel={() => closePanel()}
isConsoleExpanded={false}
/>
);
@@ -403,7 +401,6 @@ export const EditTableEntityPanel: FunctionComponent<EditTableEntityPanelProps>
panelWidth="700px"
isOpen={true}
panelContent={renderPanelContent()}
closePanel={() => closePanel()}
isConsoleExpanded={false}
/>
);

View File

@@ -1,14 +1,12 @@
import { Checkbox, Text } from "@fluentui/react";
import React, { FunctionComponent, useEffect, useState } from "react";
import { useSidePanel } from "../../../../hooks/useSidePanel";
import { userContext } from "../../../../UserContext";
import Explorer from "../../../Explorer";
import * as Constants from "../../../Tables/Constants";
import QueryViewModel from "../../../Tables/QueryBuilder/QueryViewModel";
import { RightPaneForm, RightPaneFormProps } from "../../RightPaneForm/RightPaneForm";
interface TableQuerySelectPanelProps {
explorer: Explorer;
closePanel: () => void;
queryViewModel: QueryViewModel;
}
@@ -19,10 +17,10 @@ interface ISelectColumn {
}
export const TableQuerySelectPanel: FunctionComponent<TableQuerySelectPanelProps> = ({
explorer,
closePanel,
queryViewModel,
}: TableQuerySelectPanelProps): JSX.Element => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const [columnOptions, setColumnOptions] = useState<ISelectColumn[]>([
{ columnName: "", selected: true, editable: false },
]);
@@ -31,7 +29,7 @@ export const TableQuerySelectPanel: FunctionComponent<TableQuerySelectPanelProps
const onSubmit = (): void => {
queryViewModel.selectText(getParameters());
queryViewModel.getSelectMessage();
closePanel();
closeSidePanel();
};
const props: RightPaneFormProps = {
@@ -39,7 +37,6 @@ export const TableQuerySelectPanel: FunctionComponent<TableQuerySelectPanelProps
isExecuting: false,
submitButtonText: "OK",
onSubmit,
expandConsole: () => explorer.expandConsole(),
};
const handleClick = (isChecked: boolean, selectedColumn: string): void => {

View File

@@ -11,7 +11,6 @@ exports[`Table query select Panel should render Default properly 1`] = `
}
>
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -3,9 +3,8 @@
exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
<AddTableEntityPanel
cassandraApiClient={Object {}}
closePanel={[Function]}
explorer={Object {}}
queryTablesTab={Object {}}
tableDataClient={TablesAPIDataClient {}}
tableEntityListViewModel={
Object {
"headers": Array [],
@@ -14,7 +13,6 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
}
>
<PanelContainerComponent
closePanel={[Function]}
headerText="Add Table Row"
isConsoleExpanded={false}
isOpen={true}

View File

@@ -3,9 +3,8 @@
exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
<EditTableEntityPanel
cassandraApiClient={Object {}}
closePanel={[Function]}
explorer={Object {}}
queryTablesTab={Object {}}
tableDataClient={TablesAPIDataClient {}}
tableEntityListViewModel={
Object {
"headers": Array [],
@@ -15,7 +14,6 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
}
>
<PanelContainerComponent
closePanel={[Function]}
headerText="Edit Table Entity"
isConsoleExpanded={false}
isOpen={true}

View File

@@ -1,20 +1,16 @@
import React, { ChangeEvent, FunctionComponent, useState } from "react";
import { Upload } from "../../../Common/Upload/Upload";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
export interface UploadFilePanelProps {
expandConsole: () => void;
closePanel: () => void;
uploadFile: (name: string, content: string) => Promise<NotebookContentItem>;
}
export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
expandConsole,
closePanel,
uploadFile,
}: UploadFilePanelProps) => {
export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({ uploadFile }: UploadFilePanelProps) => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
const extensions: string = undefined; //ex. ".ipynb"
const errorMessage = "Could not upload file";
const inProgressMessage = "Uploading file to notebook server";
@@ -42,7 +38,7 @@ export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
.then(
() => {
logConsoleInfo(`${successMessage} ${file.name}`);
closePanel();
closeSidePanel();
},
(error: string) => {
setFormErrors(errorMessage);
@@ -79,7 +75,6 @@ export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
};
const props: RightPaneFormProps = {
expandConsole,
formError: formErrors,
isExecuting: isExecuting,
submitButtonText: "Upload",

View File

@@ -4,7 +4,6 @@ import Explorer from "../../Explorer";
import { UploadItemsPane } from "./UploadItemsPane";
const props = {
explorer: new Explorer(),
closePanel: (): void => undefined,
};
describe("Upload Items Pane", () => {
it("should render Default properly", () => {

View File

@@ -26,7 +26,6 @@ export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({ explo
}
const selectedCollection = explorer.findSelectedCollection();
setIsExecuting(true);
selectedCollection
@@ -51,7 +50,6 @@ export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({ explo
};
const props: RightPaneFormProps = {
expandConsole: () => explorer.expandConsole(),
formError,
isExecuting: isExecuting,
submitButtonText: "Upload",

View File

@@ -2,7 +2,6 @@
exports[`Upload Items Pane should render Default properly 1`] = `
<RightPaneForm
expandConsole={[Function]}
formError=""
onSubmit={[Function]}
submitButtonText="Upload"

View File

@@ -5,841 +5,36 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
closePanel={[Function]}
explorer={
Explorer {
"_isAfecFeatureRegistered": [Function],
"_isInitializingNotebooks": false,
"_refreshSparkEnabledStateForAccount": [Function],
"_resetNotebookWorkspace": [Function],
"addCollectionText": [Function],
"arcadiaToken": [Function],
"canExceedMaximumValue": [Function],
"canSaveQueries": [Function],
"closeSidePanel": undefined,
"collapsedResourceTreeWidth": 36,
"collectionCreationDefaults": Object {
"storage": "100",
"throughput": Object {
"fixed": 400,
"shared": 400,
"unlimited": 400,
"unlimitedmax": 1000000,
"unlimitedmin": 400,
},
},
"collectionTitle": [Function],
"collectionTreeNodeAltText": [Function],
"commandBarComponentAdapter": CommandBarComponentAdapter {
"container": [Circular],
"isNotebookTabActive": [Function],
"parameters": [Function],
"tabsButtons": Array [],
},
"databases": [Function],
"deleteCollectionText": [Function],
"deleteDatabaseText": [Function],
"gitHubClient": GitHubClient {
"errorCallback": [Function],
"ocktokit": OctokitWithDefaults {
"actions": Object {
"addSelectedRepoToOrgSecret": [Function],
"cancelWorkflowRun": [Function],
"createOrUpdateOrgSecret": [Function],
"createOrUpdateRepoSecret": [Function],
"createOrUpdateSecretForRepo": [Function],
"createRegistrationToken": [Function],
"createRegistrationTokenForOrg": [Function],
"createRegistrationTokenForRepo": [Function],
"createRemoveToken": [Function],
"createRemoveTokenForOrg": [Function],
"createRemoveTokenForRepo": [Function],
"deleteArtifact": [Function],
"deleteOrgSecret": [Function],
"deleteRepoSecret": [Function],
"deleteSecretFromRepo": [Function],
"deleteSelfHostedRunnerFromOrg": [Function],
"deleteSelfHostedRunnerFromRepo": [Function],
"deleteWorkflowRunLogs": [Function],
"downloadArtifact": [Function],
"downloadJobLogsForWorkflowRun": [Function],
"downloadWorkflowJobLogs": [Function],
"downloadWorkflowRunLogs": [Function],
"getArtifact": [Function],
"getJobForWorkflowRun": [Function],
"getOrgPublicKey": [Function],
"getOrgSecret": [Function],
"getPublicKey": [Function],
"getRepoPublicKey": [Function],
"getRepoSecret": [Function],
"getSecret": [Function],
"getSelfHostedRunner": [Function],
"getSelfHostedRunnerForOrg": [Function],
"getSelfHostedRunnerForRepo": [Function],
"getWorkflow": [Function],
"getWorkflowJob": [Function],
"getWorkflowRun": [Function],
"getWorkflowRunUsage": [Function],
"getWorkflowUsage": [Function],
"listArtifactsForRepo": [Function],
"listDownloadsForSelfHostedRunnerApplication": [Function],
"listJobsForWorkflowRun": [Function],
"listOrgSecrets": [Function],
"listRepoSecrets": [Function],
"listRepoWorkflowRuns": [Function],
"listRepoWorkflows": [Function],
"listRunnerApplicationsForOrg": [Function],
"listRunnerApplicationsForRepo": [Function],
"listSecretsForRepo": [Function],
"listSelectedReposForOrgSecret": [Function],
"listSelfHostedRunnersForOrg": [Function],
"listSelfHostedRunnersForRepo": [Function],
"listWorkflowJobLogs": [Function],
"listWorkflowRunArtifacts": [Function],
"listWorkflowRunLogs": [Function],
"listWorkflowRuns": [Function],
"listWorkflowRunsForRepo": [Function],
"reRunWorkflow": [Function],
"removeSelectedRepoFromOrgSecret": [Function],
"removeSelfHostedRunner": [Function],
"setSelectedReposForOrgSecret": [Function],
},
"activity": Object {
"checkRepoIsStarredByAuthenticatedUser": [Function],
"checkStarringRepo": [Function],
"deleteRepoSubscription": [Function],
"deleteThreadSubscription": [Function],
"getFeeds": [Function],
"getRepoSubscription": [Function],
"getThread": [Function],
"getThreadSubscription": [Function],
"getThreadSubscriptionForAuthenticatedUser": [Function],
"listEventsForAuthenticatedUser": [Function],
"listEventsForOrg": [Function],
"listEventsForUser": [Function],
"listFeeds": [Function],
"listNotifications": [Function],
"listNotificationsForAuthenticatedUser": [Function],
"listNotificationsForRepo": [Function],
"listOrgEventsForAuthenticatedUser": [Function],
"listPublicEvents": [Function],
"listPublicEventsForOrg": [Function],
"listPublicEventsForRepoNetwork": [Function],
"listPublicEventsForUser": [Function],
"listPublicOrgEvents": [Function],
"listReceivedEventsForUser": [Function],
"listReceivedPublicEventsForUser": [Function],
"listRepoEvents": [Function],
"listRepoNotificationsForAuthenticatedUser": [Function],
"listReposStarredByAuthenticatedUser": [Function],
"listReposStarredByUser": [Function],
"listReposWatchedByUser": [Function],
"listStargazersForRepo": [Function],
"listWatchedReposForAuthenticatedUser": [Function],
"listWatchersForRepo": [Function],
"markAsRead": [Function],
"markNotificationsAsRead": [Function],
"markNotificationsAsReadForRepo": [Function],
"markRepoNotificationsAsRead": [Function],
"markThreadAsRead": [Function],
"setRepoSubscription": [Function],
"setThreadSubscription": [Function],
"starRepo": [Function],
"starRepoForAuthenticatedUser": [Function],
"unstarRepo": [Function],
"unstarRepoForAuthenticatedUser": [Function],
},
"apps": Object {
"addRepoToInstallation": [Function],
"checkAccountIsAssociatedWithAny": [Function],
"checkAccountIsAssociatedWithAnyStubbed": [Function],
"checkToken": [Function],
"createContentAttachment": [Function],
"createFromManifest": [Function],
"createInstallationAccessToken": [Function],
"createInstallationToken": [Function],
"deleteAuthorization": [Function],
"deleteInstallation": [Function],
"deleteToken": [Function],
"getAuthenticated": [Function],
"getBySlug": [Function],
"getInstallation": [Function],
"getOrgInstallation": [Function],
"getRepoInstallation": [Function],
"getSubscriptionPlanForAccount": [Function],
"getSubscriptionPlanForAccountStubbed": [Function],
"getUserInstallation": [Function],
"listAccountsForPlan": [Function],
"listAccountsForPlanStubbed": [Function],
"listAccountsUserOrOrgOnPlan": [Function],
"listAccountsUserOrOrgOnPlanStubbed": [Function],
"listInstallationReposForAuthenticatedUser": [Function],
"listInstallations": [Function],
"listInstallationsForAuthenticatedUser": [Function],
"listMarketplacePurchasesForAuthenticatedUser": [Function],
"listMarketplacePurchasesForAuthenticatedUserStubbed": [Function],
"listPlans": [Function],
"listPlansStubbed": [Function],
"listRepos": [Function],
"listReposAccessibleToInstallation": [Function],
"listSubscriptionsForAuthenticatedUser": [Function],
"listSubscriptionsForAuthenticatedUserStubbed": [Function],
"removeRepoFromInstallation": [Function],
"resetToken": [Function],
"revokeInstallationAccessToken": [Function],
"revokeInstallationToken": [Function],
"suspendInstallation": [Function],
"unsuspendInstallation": [Function],
},
"auth": [Function],
"checks": Object {
"create": [Function],
"createSuite": [Function],
"get": [Function],
"getSuite": [Function],
"listAnnotations": [Function],
"listForRef": [Function],
"listForSuite": [Function],
"listSuitesForRef": [Function],
"rerequestSuite": [Function],
"setSuitesPreferences": [Function],
"update": [Function],
},
"codeScanning": Object {
"getAlert": [Function],
"listAlertsForRepo": [Function],
},
"codesOfConduct": Object {
"getAllCodesOfConduct": [Function],
"getConductCode": [Function],
"getForRepo": [Function],
"listConductCodes": [Function],
},
"emojis": Object {
"get": [Function],
},
"gists": Object {
"checkIsStarred": [Function],
"create": [Function],
"createComment": [Function],
"delete": [Function],
"deleteComment": [Function],
"fork": [Function],
"get": [Function],
"getComment": [Function],
"getRevision": [Function],
"list": [Function],
"listComments": [Function],
"listCommits": [Function],
"listForUser": [Function],
"listForks": [Function],
"listPublic": [Function],
"listPublicForUser": [Function],
"listStarred": [Function],
"star": [Function],
"unstar": [Function],
"update": [Function],
"updateComment": [Function],
},
"git": Object {
"createBlob": [Function],
"createCommit": [Function],
"createRef": [Function],
"createTag": [Function],
"createTree": [Function],
"deleteRef": [Function],
"getBlob": [Function],
"getCommit": [Function],
"getRef": [Function],
"getTag": [Function],
"getTree": [Function],
"listMatchingRefs": [Function],
"updateRef": [Function],
},
"gitignore": Object {
"getAllTemplates": [Function],
"getTemplate": [Function],
"listTemplates": [Function],
},
"graphql": [Function],
"hook": [Function],
"interactions": Object {
"addOrUpdateRestrictionsForOrg": [Function],
"addOrUpdateRestrictionsForRepo": [Function],
"getRestrictionsForOrg": [Function],
"getRestrictionsForRepo": [Function],
"removeRestrictionsForOrg": [Function],
"removeRestrictionsForRepo": [Function],
"setRestrictionsForOrg": [Function],
"setRestrictionsForRepo": [Function],
},
"issues": Object {
"addAssignees": [Function],
"addLabels": [Function],
"checkAssignee": [Function],
"checkUserCanBeAssigned": [Function],
"create": [Function],
"createComment": [Function],
"createLabel": [Function],
"createMilestone": [Function],
"deleteComment": [Function],
"deleteLabel": [Function],
"deleteMilestone": [Function],
"get": [Function],
"getComment": [Function],
"getEvent": [Function],
"getLabel": [Function],
"getMilestone": [Function],
"list": [Function],
"listAssignees": [Function],
"listComments": [Function],
"listCommentsForRepo": [Function],
"listEvents": [Function],
"listEventsForRepo": [Function],
"listEventsForTimeline": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listForRepo": [Function],
"listLabelsForMilestone": [Function],
"listLabelsForRepo": [Function],
"listLabelsOnIssue": [Function],
"listMilestones": [Function],
"listMilestonesForRepo": [Function],
"lock": [Function],
"removeAllLabels": [Function],
"removeAssignees": [Function],
"removeLabel": [Function],
"removeLabels": [Function],
"replaceAllLabels": [Function],
"replaceLabels": [Function],
"setLabels": [Function],
"unlock": [Function],
"update": [Function],
"updateComment": [Function],
"updateLabel": [Function],
"updateMilestone": [Function],
},
"licenses": Object {
"get": [Function],
"getAllCommonlyUsed": [Function],
"getForRepo": [Function],
"listCommonlyUsed": [Function],
},
"log": Object {
"debug": [Function],
"error": [Function],
"info": [Function],
"warn": [Function],
},
"markdown": Object {
"render": [Function],
"renderRaw": [Function],
},
"meta": Object {
"get": [Function],
},
"migrations": Object {
"cancelImport": [Function],
"deleteArchiveForAuthenticatedUser": [Function],
"deleteArchiveForOrg": [Function],
"downloadArchiveForOrg": [Function],
"getArchiveForAuthenticatedUser": [Function],
"getCommitAuthors": [Function],
"getImportProgress": [Function],
"getImportStatus": [Function],
"getLargeFiles": [Function],
"getStatusForAuthenticatedUser": [Function],
"getStatusForOrg": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listReposForOrg": [Function],
"listReposForUser": [Function],
"mapCommitAuthor": [Function],
"setLfsPreference": [Function],
"startForAuthenticatedUser": [Function],
"startForOrg": [Function],
"startImport": [Function],
"unlockRepoForAuthenticatedUser": [Function],
"unlockRepoForOrg": [Function],
"updateImport": [Function],
},
"orgs": Object {
"addOrUpdateMembership": [Function],
"blockUser": [Function],
"checkBlockedUser": [Function],
"checkMembership": [Function],
"checkMembershipForUser": [Function],
"checkPublicMembership": [Function],
"checkPublicMembershipForUser": [Function],
"concealMembership": [Function],
"convertMemberToOutsideCollaborator": [Function],
"createHook": [Function],
"createInvitation": [Function],
"createWebhook": [Function],
"deleteHook": [Function],
"deleteWebhook": [Function],
"get": [Function],
"getHook": [Function],
"getMembership": [Function],
"getMembershipForAuthenticatedUser": [Function],
"getMembershipForUser": [Function],
"getWebhook": [Function],
"list": [Function],
"listAppInstallations": [Function],
"listBlockedUsers": [Function],
"listForAuthenticatedUser": [Function],
"listForUser": [Function],
"listHooks": [Function],
"listInstallations": [Function],
"listInvitationTeams": [Function],
"listMembers": [Function],
"listMemberships": [Function],
"listMembershipsForAuthenticatedUser": [Function],
"listOutsideCollaborators": [Function],
"listPendingInvitations": [Function],
"listPublicMembers": [Function],
"listWebhooks": [Function],
"pingHook": [Function],
"pingWebhook": [Function],
"publicizeMembership": [Function],
"removeMember": [Function],
"removeMembership": [Function],
"removeMembershipForUser": [Function],
"removeOutsideCollaborator": [Function],
"removePublicMembershipForAuthenticatedUser": [Function],
"setMembershipForUser": [Function],
"setPublicMembershipForAuthenticatedUser": [Function],
"unblockUser": [Function],
"update": [Function],
"updateHook": [Function],
"updateMembership": [Function],
"updateMembershipForAuthenticatedUser": [Function],
"updateWebhook": [Function],
},
"paginate": [Function],
"projects": Object {
"addCollaborator": [Function],
"createCard": [Function],
"createColumn": [Function],
"createForAuthenticatedUser": [Function],
"createForOrg": [Function],
"createForRepo": [Function],
"delete": [Function],
"deleteCard": [Function],
"deleteColumn": [Function],
"get": [Function],
"getCard": [Function],
"getColumn": [Function],
"getPermissionForUser": [Function],
"listCards": [Function],
"listCollaborators": [Function],
"listColumns": [Function],
"listForOrg": [Function],
"listForRepo": [Function],
"listForUser": [Function],
"moveCard": [Function],
"moveColumn": [Function],
"removeCollaborator": [Function],
"reviewUserPermissionLevel": [Function],
"update": [Function],
"updateCard": [Function],
"updateColumn": [Function],
},
"pulls": Object {
"checkIfMerged": [Function],
"create": [Function],
"createComment": [Function],
"createReplyForReviewComment": [Function],
"createReview": [Function],
"createReviewComment": [Function],
"createReviewCommentReply": [Function],
"createReviewRequest": [Function],
"deleteComment": [Function],
"deletePendingReview": [Function],
"deleteReviewComment": [Function],
"deleteReviewRequest": [Function],
"dismissReview": [Function],
"get": [Function],
"getComment": [Function],
"getCommentsForReview": [Function],
"getReview": [Function],
"getReviewComment": [Function],
"list": [Function],
"listComments": [Function],
"listCommentsForRepo": [Function],
"listCommentsForReview": [Function],
"listCommits": [Function],
"listFiles": [Function],
"listRequestedReviewers": [Function],
"listReviewComments": [Function],
"listReviewCommentsForRepo": [Function],
"listReviewRequests": [Function],
"listReviews": [Function],
"merge": [Function],
"removeRequestedReviewers": [Function],
"requestReviewers": [Function],
"submitReview": [Function],
"update": [Function],
"updateBranch": [Function],
"updateComment": [Function],
"updateReview": [Function],
"updateReviewComment": [Function],
},
"rateLimit": Object {
"get": [Function],
},
"reactions": Object {
"createForCommitComment": [Function],
"createForIssue": [Function],
"createForIssueComment": [Function],
"createForPullRequestReviewComment": [Function],
"createForTeamDiscussionCommentInOrg": [Function],
"createForTeamDiscussionInOrg": [Function],
"delete": [Function],
"deleteForCommitComment": [Function],
"deleteForIssue": [Function],
"deleteForIssueComment": [Function],
"deleteForPullRequestComment": [Function],
"deleteForTeamDiscussion": [Function],
"deleteForTeamDiscussionComment": [Function],
"deleteLegacy": [Function],
"listForCommitComment": [Function],
"listForIssue": [Function],
"listForIssueComment": [Function],
"listForPullRequestReviewComment": [Function],
"listForTeamDiscussionCommentInOrg": [Function],
"listForTeamDiscussionInOrg": [Function],
},
"repos": Object {
"acceptInvitation": [Function],
"addAppAccessRestrictions": [Function],
"addCollaborator": [Function],
"addDeployKey": [Function],
"addProtectedBranchAdminEnforcement": [Function],
"addProtectedBranchAppRestrictions": [Function],
"addProtectedBranchRequiredSignatures": [Function],
"addProtectedBranchRequiredStatusChecksContexts": [Function],
"addProtectedBranchTeamRestrictions": [Function],
"addProtectedBranchUserRestrictions": [Function],
"addStatusCheckContexts": [Function],
"addTeamAccessRestrictions": [Function],
"addUserAccessRestrictions": [Function],
"checkCollaborator": [Function],
"checkVulnerabilityAlerts": [Function],
"compareCommits": [Function],
"createCommitComment": [Function],
"createCommitSignatureProtection": [Function],
"createCommitStatus": [Function],
"createDeployKey": [Function],
"createDeployment": [Function],
"createDeploymentStatus": [Function],
"createDispatchEvent": [Function],
"createForAuthenticatedUser": [Function],
"createFork": [Function],
"createHook": [Function],
"createInOrg": [Function],
"createOrUpdateFile": [Function],
"createOrUpdateFileContents": [Function],
"createPagesSite": [Function],
"createRelease": [Function],
"createStatus": [Function],
"createUsingTemplate": [Function],
"createWebhook": [Function],
"declineInvitation": [Function],
"delete": [Function],
"deleteAccessRestrictions": [Function],
"deleteAdminBranchProtection": [Function],
"deleteBranchProtection": [Function],
"deleteCommitComment": [Function],
"deleteCommitSignatureProtection": [Function],
"deleteDeployKey": [Function],
"deleteDeployment": [Function],
"deleteDownload": [Function],
"deleteFile": [Function],
"deleteHook": [Function],
"deleteInvitation": [Function],
"deletePagesSite": [Function],
"deletePullRequestReviewProtection": [Function],
"deleteRelease": [Function],
"deleteReleaseAsset": [Function],
"deleteWebhook": [Function],
"disableAutomatedSecurityFixes": [Function],
"disablePagesSite": [Function],
"disableVulnerabilityAlerts": [Function],
"downloadArchive": [Function],
"enableAutomatedSecurityFixes": [Function],
"enablePagesSite": [Function],
"enableVulnerabilityAlerts": [Function],
"get": [Function],
"getAccessRestrictions": [Function],
"getAdminBranchProtection": [Function],
"getAllStatusCheckContexts": [Function],
"getAllTopics": [Function],
"getAppsWithAccessToProtectedBranch": [Function],
"getArchiveLink": [Function],
"getBranch": [Function],
"getBranchProtection": [Function],
"getClones": [Function],
"getCodeFrequencyStats": [Function],
"getCollaboratorPermissionLevel": [Function],
"getCombinedStatusForRef": [Function],
"getCommit": [Function],
"getCommitActivityStats": [Function],
"getCommitComment": [Function],
"getCommitSignatureProtection": [Function],
"getCommunityProfileMetrics": [Function],
"getContent": [Function],
"getContents": [Function],
"getContributorsStats": [Function],
"getDeployKey": [Function],
"getDeployment": [Function],
"getDeploymentStatus": [Function],
"getDownload": [Function],
"getHook": [Function],
"getLatestPagesBuild": [Function],
"getLatestRelease": [Function],
"getPages": [Function],
"getPagesBuild": [Function],
"getParticipationStats": [Function],
"getProtectedBranchAdminEnforcement": [Function],
"getProtectedBranchPullRequestReviewEnforcement": [Function],
"getProtectedBranchRequiredSignatures": [Function],
"getProtectedBranchRequiredStatusChecks": [Function],
"getProtectedBranchRestrictions": [Function],
"getPullRequestReviewProtection": [Function],
"getPunchCardStats": [Function],
"getReadme": [Function],
"getRelease": [Function],
"getReleaseAsset": [Function],
"getReleaseByTag": [Function],
"getStatusChecksProtection": [Function],
"getTeamsWithAccessToProtectedBranch": [Function],
"getTopPaths": [Function],
"getTopReferrers": [Function],
"getUsersWithAccessToProtectedBranch": [Function],
"getViews": [Function],
"getWebhook": [Function],
"list": [Function],
"listAssetsForRelease": [Function],
"listBranches": [Function],
"listBranchesForHeadCommit": [Function],
"listCollaborators": [Function],
"listCommentsForCommit": [Function],
"listCommitComments": [Function],
"listCommitCommentsForRepo": [Function],
"listCommitStatusesForRef": [Function],
"listCommits": [Function],
"listContributors": [Function],
"listDeployKeys": [Function],
"listDeploymentStatuses": [Function],
"listDeployments": [Function],
"listDownloads": [Function],
"listForAuthenticatedUser": [Function],
"listForOrg": [Function],
"listForUser": [Function],
"listForks": [Function],
"listHooks": [Function],
"listInvitations": [Function],
"listInvitationsForAuthenticatedUser": [Function],
"listLanguages": [Function],
"listPagesBuilds": [Function],
"listProtectedBranchRequiredStatusChecksContexts": [Function],
"listPublic": [Function],
"listPullRequestsAssociatedWithCommit": [Function],
"listReleaseAssets": [Function],
"listReleases": [Function],
"listStatusesForRef": [Function],
"listTags": [Function],
"listTeams": [Function],
"listTopics": [Function],
"listWebhooks": [Function],
"merge": [Function],
"pingHook": [Function],
"pingWebhook": [Function],
"removeAppAccessRestrictions": [Function],
"removeBranchProtection": [Function],
"removeCollaborator": [Function],
"removeDeployKey": [Function],
"removeProtectedBranchAdminEnforcement": [Function],
"removeProtectedBranchAppRestrictions": [Function],
"removeProtectedBranchPullRequestReviewEnforcement": [Function],
"removeProtectedBranchRequiredSignatures": [Function],
"removeProtectedBranchRequiredStatusChecks": [Function],
"removeProtectedBranchRequiredStatusChecksContexts": [Function],
"removeProtectedBranchRestrictions": [Function],
"removeProtectedBranchTeamRestrictions": [Function],
"removeProtectedBranchUserRestrictions": [Function],
"removeStatusCheckContexts": [Function],
"removeStatusCheckProtection": [Function],
"removeTeamAccessRestrictions": [Function],
"removeUserAccessRestrictions": [Function],
"replaceAllTopics": [Function],
"replaceProtectedBranchAppRestrictions": [Function],
"replaceProtectedBranchRequiredStatusChecksContexts": [Function],
"replaceProtectedBranchTeamRestrictions": [Function],
"replaceProtectedBranchUserRestrictions": [Function],
"replaceTopics": [Function],
"requestPageBuild": [Function],
"requestPagesBuild": [Function],
"retrieveCommunityProfileMetrics": [Function],
"setAdminBranchProtection": [Function],
"setAppAccessRestrictions": [Function],
"setStatusCheckContexts": [Function],
"setTeamAccessRestrictions": [Function],
"setUserAccessRestrictions": [Function],
"testPushHook": [Function],
"testPushWebhook": [Function],
"transfer": [Function],
"update": [Function],
"updateBranchProtection": [Function],
"updateCommitComment": [Function],
"updateHook": [Function],
"updateInformationAboutPagesSite": [Function],
"updateInvitation": [Function],
"updateProtectedBranchPullRequestReviewEnforcement": [Function],
"updateProtectedBranchRequiredStatusChecks": [Function],
"updatePullRequestReviewProtection": [Function],
"updateRelease": [Function],
"updateReleaseAsset": [Function],
"updateStatusCheckPotection": [Function],
"updateWebhook": [Function],
"uploadReleaseAsset": [Function],
},
"request": [Function],
"search": Object {
"code": [Function],
"commits": [Function],
"issuesAndPullRequests": [Function],
"labels": [Function],
"repos": [Function],
"topics": [Function],
"users": [Function],
},
"teams": Object {
"addOrUpdateMembershipForUserInOrg": [Function],
"addOrUpdateMembershipInOrg": [Function],
"addOrUpdateProjectInOrg": [Function],
"addOrUpdateProjectPermissionsInOrg": [Function],
"addOrUpdateRepoInOrg": [Function],
"addOrUpdateRepoPermissionsInOrg": [Function],
"checkManagesRepoInOrg": [Function],
"checkPermissionsForProjectInOrg": [Function],
"checkPermissionsForRepoInOrg": [Function],
"create": [Function],
"createDiscussionCommentInOrg": [Function],
"createDiscussionInOrg": [Function],
"deleteDiscussionCommentInOrg": [Function],
"deleteDiscussionInOrg": [Function],
"deleteInOrg": [Function],
"getByName": [Function],
"getDiscussionCommentInOrg": [Function],
"getDiscussionInOrg": [Function],
"getMembershipForUserInOrg": [Function],
"getMembershipInOrg": [Function],
"list": [Function],
"listChildInOrg": [Function],
"listDiscussionCommentsInOrg": [Function],
"listDiscussionsInOrg": [Function],
"listForAuthenticatedUser": [Function],
"listMembersInOrg": [Function],
"listPendingInvitationsInOrg": [Function],
"listProjectsInOrg": [Function],
"listReposInOrg": [Function],
"removeMembershipForUserInOrg": [Function],
"removeMembershipInOrg": [Function],
"removeProjectInOrg": [Function],
"removeRepoInOrg": [Function],
"reviewProjectInOrg": [Function],
"updateDiscussionCommentInOrg": [Function],
"updateDiscussionInOrg": [Function],
"updateInOrg": [Function],
},
"users": Object {
"addEmailForAuthenticated": [Function],
"addEmails": [Function],
"block": [Function],
"checkBlocked": [Function],
"checkFollowing": [Function],
"checkFollowingForUser": [Function],
"checkPersonIsFollowedByAuthenticated": [Function],
"createGpgKey": [Function],
"createGpgKeyForAuthenticated": [Function],
"createPublicKey": [Function],
"createPublicSshKeyForAuthenticated": [Function],
"deleteEmailForAuthenticated": [Function],
"deleteEmails": [Function],
"deleteGpgKey": [Function],
"deleteGpgKeyForAuthenticated": [Function],
"deletePublicKey": [Function],
"deletePublicSshKeyForAuthenticated": [Function],
"follow": [Function],
"getAuthenticated": [Function],
"getByUsername": [Function],
"getContextForUser": [Function],
"getGpgKey": [Function],
"getGpgKeyForAuthenticated": [Function],
"getPublicKey": [Function],
"getPublicSshKeyForAuthenticated": [Function],
"list": [Function],
"listBlocked": [Function],
"listBlockedByAuthenticated": [Function],
"listEmails": [Function],
"listEmailsForAuthenticated": [Function],
"listFollowedByAuthenticated": [Function],
"listFollowersForAuthenticatedUser": [Function],
"listFollowersForUser": [Function],
"listFollowingForAuthenticatedUser": [Function],
"listFollowingForUser": [Function],
"listGpgKeys": [Function],
"listGpgKeysForAuthenticated": [Function],
"listGpgKeysForUser": [Function],
"listPublicEmails": [Function],
"listPublicEmailsForAuthenticated": [Function],
"listPublicKeys": [Function],
"listPublicKeysForUser": [Function],
"listPublicSshKeysForAuthenticated": [Function],
"setPrimaryEmailVisibilityForAuthenticated": [Function],
"togglePrimaryEmailVisibility": [Function],
"unblock": [Function],
"unfollow": [Function],
"updateAuthenticated": [Function],
},
},
},
"hasStorageAnalyticsAfecFeature": [Function],
"isAccountReady": [Function],
"isFixedCollectionWithSharedThroughputSupported": [Function],
"isHostedDataExplorerEnabled": [Function],
"isLastCollection": [Function],
"isLastNonEmptyDatabase": [Function],
"isLeftPaneExpanded": [Function],
"isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function],
"isPublishNotebookPaneEnabled": [Function],
"isResourceTokenCollectionNodeSelected": [Function],
"isSchemaEnabled": [Function],
"isSelectedDatabaseShared": [Function],
"isServerlessEnabled": [Function],
"isShellEnabled": [Function],
"isSparkEnabled": [Function],
"isSparkEnabledForAccount": [Function],
"isSynapseLinkUpdating": [Function],
"isTabsContentExpanded": [Function],
"junoClient": JunoClient {
"cachedPinnedRepos": [Function],
},
"memoryUsageInfo": [Function],
"notebookBasePath": [Function],
"notebookServerInfo": [Function],
"onGitHubClientError": [Function],
"onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function],
"openSidePanel": undefined,
"provideFeedbackEmail": [Function],
"queriesClient": QueriesClient {
"container": [Circular],
},
"refreshAllDatabases": [Function],
"refreshNotebookList": [Function],
"refreshTreeTitle": [Function],
"resourceTokenCollection": [Function],
"resourceTokenCollectionId": [Function],
"resourceTokenDatabaseId": [Function],
@@ -859,7 +54,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
"selectedDatabaseId": [Function],
"selectedNode": [Function],
"setInProgressConsoleDataIdToBeDeleted": undefined,
"setIsNotificationConsoleExpanded": undefined,
"setNotificationConsoleData": undefined,
"sparkClusterConnectionInfo": [Function],
"splitter": Splitter {
@@ -878,7 +72,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
"activeTab": [Function],
"openedTabs": [Function],
},
"toggleLeftPaneExpandedKeyPress": [Function],
}
}
openNotificationConsole={[Function]}
@@ -890,7 +83,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
}
>
<RightPaneForm
expandConsole={[Function]}
formError=""
isExecuting={false}
onSubmit={[Function]}

View File

@@ -1,15 +1,14 @@
import * as ko from "knockout";
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
import { SplashScreen } from "./SplashScreen";
import { TabsManager } from "../Tabs/TabsManager";
import Explorer from "../Explorer";
import { TabsManager } from "../Tabs/TabsManager";
import { SplashScreen } from "./SplashScreen";
jest.mock("../Explorer");
const createExplorer = () => {
const mock = new Explorer();
mock.selectedNode = ko.observable();
mock.isNotebookEnabled = ko.observable(false);
mock.addCollectionText = ko.observable("add collection");
mock.tabsManager = new TabsManager();
return mock as jest.Mocked<Explorer>;
};

View File

@@ -17,7 +17,7 @@ import { AuthType } from "../../AuthType";
import * as Constants from "../../Common/Constants";
import * as ViewModels from "../../Contracts/ViewModels";
import { userContext } from "../../UserContext";
import { getDatabaseName } from "../../Utils/APITypeUtils";
import { getCollectionName, getDatabaseName } from "../../Utils/APITypeUtils";
import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher";
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
import Explorer from "../Explorer";
@@ -192,7 +192,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
const heroes: SplashScreenItem[] = [
{
iconSrc: NewContainerIcon,
title: this.container.addCollectionText(),
title: `New ${getCollectionName()}`,
description: "Create a new container for storage and throughput",
onClick: () => this.container.onNewCollectionClicked(),
},
@@ -250,12 +250,14 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
});
}
items.push({
iconSrc: OpenQueryIcon,
title: "Open Query",
description: null,
onClick: () => this.container.openBrowseQueriesPanel(),
});
if (userContext.apiType === "SQL") {
items.push({
iconSrc: OpenQueryIcon,
title: "Open Query",
description: null,
onClick: () => this.container.openBrowseQueriesPanel(),
});
}
if (userContext.apiType !== "Cassandra") {
items.push({

View File

@@ -2,7 +2,6 @@ import * as ko from "knockout";
import { DatabaseAccount } from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { updateUserContext } from "../../UserContext";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../Explorer";
import DocumentId from "../Tree/DocumentId";
import DocumentsTab from "./DocumentsTab";
@@ -17,7 +16,6 @@ describe("Documents tab", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {},
});
expect(documentsTab.buildQuery("")).toContain("select");
@@ -93,7 +91,6 @@ describe("Documents tab", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {},
});
expect(documentsTab.showPartitionKey).toBe(false);
@@ -108,7 +105,6 @@ describe("Documents tab", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {},
});
expect(documentsTab.showPartitionKey).toBe(false);
@@ -123,7 +119,6 @@ describe("Documents tab", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {},
});
expect(documentsTab.showPartitionKey).toBe(true);
@@ -141,7 +136,6 @@ describe("Documents tab", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {},
});
expect(documentsTab.showPartitionKey).toBe(false);
@@ -156,7 +150,6 @@ describe("Documents tab", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {},
});
expect(documentsTab.showPartitionKey).toBe(true);

View File

@@ -4,6 +4,7 @@ import NewVertexIcon from "../../../images/NewVertex.svg";
import StyleIcon from "../../../images/Style.svg";
import { DatabaseAccount } from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { useSidePanel } from "../../hooks/useSidePanel";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
import {
GraphAccessor,
@@ -11,9 +12,6 @@ import {
GraphExplorerError,
GraphExplorerProps,
} from "../Graph/GraphExplorerComponent/GraphExplorer";
// import { GraphAccessor, GraphExplorer, GraphExplorerError } from "../Graph/GraphExplorerComponent/GraphExplorer";
// import { GraphExplorerAdapter } from "../Graph/GraphExplorerComponent/GraphExplorerAdapter";
import { ContextualPaneBase } from "../Panes/ContextualPaneBase";
import { GraphStylingPanel } from "../Panes/GraphStylingPanel/GraphStylingPanel";
import { NewVertexPanel } from "../Panes/NewVertexPanel/NewVertexPanel";
import TabsBase from "./TabsBase";
@@ -71,7 +69,6 @@ export default class GraphTab extends TabsBase {
private isFilterQueryLoading: ko.Observable<boolean>;
private isValidQuery: ko.Observable<boolean>;
private collectionPartitionKeyProperty: string;
private contextualPane: ContextualPaneBase;
public graphExplorer: GraphExplorer;
public options: GraphTabOptions;
constructor(options: GraphTabOptions) {
@@ -159,12 +156,10 @@ export default class GraphTab extends TabsBase {
/* Command bar */
private showNewVertexEditor(): void {
this.collection.container.openSidePanel(
useSidePanel.getState().openSidePanel(
"New Vertex",
<NewVertexPanel
explorer={this.collection.container}
partitionKeyPropertyProp={this.collectionPartitionKeyProperty}
openNotificationConsole={() => this.collection.container.expandConsole()}
onSubmit={(
result: ViewModels.NewVertexData,
onError: (errorMessage: string) => void,
@@ -173,7 +168,7 @@ export default class GraphTab extends TabsBase {
this.graphAccessor.addVertex(result).then(
() => {
onSuccess();
this.contextualPane.cancel();
useSidePanel.getState().closeSidePanel();
},
(error: GraphExplorerError) => {
onError(error.title);
@@ -184,10 +179,9 @@ export default class GraphTab extends TabsBase {
);
}
public openStyling(): void {
this.collection.container.openSidePanel(
useSidePanel.getState().openSidePanel(
"Graph Style",
<GraphStylingPanel
closePanel={this.collection.container.closeSidePanel}
igraphConfigUiData={this.igraphConfigUiData}
igraphConfig={this.igraphConfig}
getValues={(igraphConfig?: IGraphConfig): void => {

View File

@@ -1,7 +1,6 @@
import { stringifyNotebook, toJS } from "@nteract/commutable";
import * as ko from "knockout";
import * as Q from "q";
import * as _ from "underscore";
import ClearAllOutputsIcon from "../../../images/notebook/Notebook-clear-all-outputs.svg";
import CopyIcon from "../../../images/notebook/Notebook-copy.svg";
import CutIcon from "../../../images/notebook/Notebook-cut.svg";
@@ -12,14 +11,9 @@ import RunAllIcon from "../../../images/notebook/Notebook-run-all.svg";
import RunIcon from "../../../images/notebook/Notebook-run.svg";
import { default as InterruptKernelIcon, default as KillKernelIcon } from "../../../images/notebook/Notebook-stop.svg";
import SaveIcon from "../../../images/save-cosmos.svg";
import { ArmApiVersions } from "../../Common/Constants";
import { configContext } from "../../ConfigContext";
import * as DataModels from "../../Contracts/DataModels";
import { useNotebookSnapshotStore } from "../../hooks/useNotebookSnapshotStore";
import { trackEvent } from "../../Shared/appInsights";
import { Action, ActionModifiers, Source } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import * as NotebookConfigurationUtils from "../../Utils/NotebookConfigurationUtils";
import { logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
@@ -38,7 +32,6 @@ export interface NotebookTabOptions extends NotebookTabBaseOptions {
export default class NotebookTabV2 extends NotebookTabBase {
public readonly html = '<div data-bind="react:notebookComponentAdapter" style="height: 100%"></div>';
public notebookPath: ko.Observable<string>;
private selectedSparkPool: ko.Observable<string>;
private notebookComponentAdapter: NotebookComponentAdapter;
constructor(options: NotebookTabOptions) {
@@ -53,16 +46,6 @@ export default class NotebookTabV2 extends NotebookTabBase {
notebookClient: NotebookTabBase.clientManager,
onUpdateKernelInfo: this.onKernelUpdate,
});
this.selectedSparkPool = ko.observable<string>(null);
this.container &&
this.container.arcadiaToken.subscribe(async () => {
const currentKernel = this.notebookComponentAdapter.getCurrentKernelName();
if (!currentKernel) {
return;
}
await this.configureServiceEndpoints(currentKernel);
});
}
public onCloseTabButtonClick(): Q.Promise<any> {
@@ -361,32 +344,6 @@ export default class NotebookTabV2 extends NotebookTabBase {
},
// TODO: Uncomment when undo/redo is reimplemented in nteract
];
if (this.container.hasStorageAnalyticsAfecFeature()) {
const arcadiaWorkspaceDropdown: CommandButtonComponentProps = {
iconSrc: null,
iconAlt: workspaceLabel,
ariaLabel: workspaceLabel,
onCommandClick: () => {},
commandButtonLabel: null,
hasPopup: false,
disabled: this.container.arcadiaWorkspaces.length < 1,
isDropdown: false,
isArcadiaPicker: true,
arcadiaProps: {
selectedSparkPool: this.selectedSparkPool(),
workspaces: this.container.arcadiaWorkspaces(),
onSparkPoolSelect: this.onSparkPoolSelect,
onCreateNewWorkspaceClicked: () => {
this.container.createWorkspace();
},
onCreateNewSparkPoolClicked: (workspaceResourceId: string) => {
this.container.createSparkPool(workspaceResourceId);
},
},
};
buttons.splice(1, 0, arcadiaWorkspaceDropdown);
}
return buttons;
}
@@ -394,50 +351,6 @@ export default class NotebookTabV2 extends NotebookTabBase {
this.updateNavbarWithTabsButtons();
}
private onSparkPoolSelect = (evt: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>, item: any) => {
if (!item || !item.text) {
this.selectedSparkPool(null);
return;
}
trackEvent(
{ name: "SparkPoolSelected" },
{
subscriptionId: userContext.subscriptionId,
accountName: userContext.databaseAccount?.name,
accountId: userContext.databaseAccount?.id,
}
);
this.container &&
this.container.arcadiaWorkspaces &&
this.container.arcadiaWorkspaces() &&
this.container.arcadiaWorkspaces().forEach(async (workspace) => {
if (workspace && workspace.name && workspace.sparkPools) {
const selectedPoolIndex = _.findIndex(workspace.sparkPools, (pool) => pool && pool.name === item.text);
if (selectedPoolIndex >= 0) {
const selectedPool = workspace.sparkPools[selectedPoolIndex];
if (selectedPool && selectedPool.name) {
this.container.sparkClusterConnectionInfo({
userName: undefined,
password: undefined,
endpoints: [
{
endpoint: `https://${workspace.name}.${configContext.ARCADIA_LIVY_ENDPOINT_DNS_ZONE}/livyApi/versions/${ArmApiVersions.arcadiaLivy}/sparkPools/${selectedPool.name}/`,
kind: DataModels.SparkClusterEndpointKind.Livy,
},
],
});
this.selectedSparkPool(item.text);
await this.reconfigureServiceEndpoints();
this.container.sparkClusterConnectionInfo.valueHasMutated();
return;
}
}
}
});
};
private onKernelUpdate = async () => {
await this.configureServiceEndpoints(this.notebookComponentAdapter.getCurrentKernelName()).catch((reason) => {
/* Erroring is ok here */

View File

@@ -2,7 +2,6 @@ import * as ko from "knockout";
import { DatabaseAccount } from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { updateUserContext } from "../../UserContext";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../Explorer";
import QueryTab from "./QueryTab";
@@ -26,7 +25,6 @@ describe("Query Tab", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {},
});
}

View File

@@ -10,6 +10,7 @@ import { MinimalQueryIterator } from "../../Common/IteratorUtilities";
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { useNotificationConsole } from "../../hooks/useNotificationConsole";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
@@ -198,7 +199,7 @@ export default class QueryTab extends TabsBase implements ViewModels.WaitsForTem
}
public onErrorDetailsClick = (src: any, event: MouseEvent): boolean => {
this.collection && this.collection.container.expandConsole();
useNotificationConsole.getState().expandConsole();
return false;
};

View File

@@ -9,6 +9,7 @@ import { updateStoredProcedure } from "../../Common/dataAccess/updateStoredProce
import editable from "../../Common/EditableUtility";
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
import * as ViewModels from "../../Contracts/ViewModels";
import { useNotificationConsole } from "../../hooks/useNotificationConsole";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
@@ -136,7 +137,7 @@ export default class StoredProcedureTab extends ScriptTabBase {
}
public onErrorDetailsClick = (src: any, event: MouseEvent): boolean => {
this.collection && this.collection.container.expandConsole();
useNotificationConsole.getState().expandConsole();
return false;
};

View File

@@ -3,11 +3,13 @@ import * as Constants from "../../Common/Constants";
import * as ThemeUtility from "../../Common/ThemeUtility";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { useNotificationConsole } from "../../hooks/useNotificationConsole";
import { RouteHandler } from "../../RouteHandlers/RouteHandler";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../Explorer";
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
import { TabsManager } from "./TabsManager";
@@ -122,8 +124,8 @@ export default class TabsBase extends WaitsForTemplateViewModel {
}
public onErrorDetailsClick = (src: any, event: MouseEvent): boolean => {
this.collection?.container?.expandConsole();
this.database?.container?.expandConsole();
useNotificationConsole.getState().expandConsole();
useNotificationConsole.getState().expandConsole();
return false;
};
@@ -162,7 +164,7 @@ export default class TabsBase extends WaitsForTemplateViewModel {
protected updateNavbarWithTabsButtons = (): void => {
if (this.isActive()) {
this.getContainer().onUpdateTabsButtons(this.getTabsButtons());
useCommandBar.getState().setContextButtons(this.getTabsButtons());
}
};
}

View File

@@ -52,7 +52,6 @@ describe("Tabs manager tests", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: undefined,
});
documentsTab = new DocumentsTab({
@@ -63,7 +62,6 @@ describe("Tabs manager tests", () => {
title: "",
tabPath: "",
hashLocation: "",
onUpdateTabsButtons: undefined,
});
// make sure tabs have different tabId

View File

@@ -1,4 +1,3 @@
import * as ko from "knockout";
import * as DataModels from "../../Contracts/DataModels";
import Explorer from "../Explorer";
import Collection from "./Collection";
@@ -36,8 +35,6 @@ describe("Collection", () => {
return false;
};
mockContainer.deleteCollectionText = ko.observable<string>("delete collection");
return generateCollection(mockContainer, "abc", data, {} as DataModels.Offer);
}

View File

@@ -21,6 +21,7 @@ import { userContext } from "../../UserContext";
import { SqlTriggerResource } from "../../Utils/arm/generatedClients/cosmos/types";
import { logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
import Explorer from "../Explorer";
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
import { CassandraAPIDataClient, CassandraTableKey, CassandraTableKeys } from "../Tables/TableDataClient";
import ConflictsTab from "../Tabs/ConflictsTab";
import DocumentsTab from "../Tabs/DocumentsTab";
@@ -221,7 +222,7 @@ export default class Collection implements ViewModels.Collection {
} else {
this.expandCollection();
}
this.container.onUpdateTabsButtons([]);
useCommandBar.getState().setContextButtons([]);
this.container.tabsManager.refreshActiveTab(
(tab) => tab.collection && tab.collection.databaseId === this.databaseId && tab.collection.id() === this.id()
);
@@ -299,7 +300,6 @@ export default class Collection implements ViewModels.Collection {
tabPath: `${this.databaseId}>${this.id()}>Documents`,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/documents`,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(documentsTab);
@@ -346,7 +346,6 @@ export default class Collection implements ViewModels.Collection {
tabPath: `${this.databaseId}>${this.id()}>Conflicts`,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/conflicts`,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(conflictsTab);
@@ -401,7 +400,6 @@ export default class Collection implements ViewModels.Collection {
node: this,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/entities`,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(queryTablesTab);
@@ -454,7 +452,6 @@ export default class Collection implements ViewModels.Collection {
databaseId: this.databaseId,
isTabsContentExpanded: this.container.isTabsContentExpanded,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(graphTab);
@@ -501,7 +498,6 @@ export default class Collection implements ViewModels.Collection {
node: this,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/mongoDocuments`,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(mongoDocumentsTab);
}
@@ -547,7 +543,6 @@ export default class Collection implements ViewModels.Collection {
node: this,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/schemaAnalyzer`,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
})
);
};
@@ -587,7 +582,6 @@ export default class Collection implements ViewModels.Collection {
collection: this,
node: this,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/settings`,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
};
let settingsTabV2 = matchingTabs && (matchingTabs[0] as CollectionSettingsTabV2);
@@ -632,7 +626,6 @@ export default class Collection implements ViewModels.Collection {
queryText: queryText,
partitionKey: collection.partitionKey,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(queryTab);
@@ -660,7 +653,6 @@ export default class Collection implements ViewModels.Collection {
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/mongoQuery`,
partitionKey: collection.partitionKey,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(mongoQueryTab);
@@ -692,7 +684,6 @@ export default class Collection implements ViewModels.Collection {
databaseId: this.databaseId,
isTabsContentExpanded: this.container.isTabsContentExpanded,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(graphTab);
@@ -707,7 +698,6 @@ export default class Collection implements ViewModels.Collection {
collection: this,
node: this,
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/mongoShell`,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
});
this.container.tabsManager.activateNewTab(mongoShellTab);

View File

@@ -81,7 +81,6 @@ export default class Database implements ViewModels.Database {
database: this,
hashLocation: `${Constants.HashRoutePrefixes.databasesWithId(this.id())}/settings`,
onLoadStartKey: startKey,
onUpdateTabsButtons: this.container.onUpdateTabsButtons,
};
settingsTab = new DatabaseSettingsTabV2(tabOptions);
settingsTab.pendingNotification(pendingNotification);

Some files were not shown because too many files have changed in this diff Show More