mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-24 11:21:23 +00:00
Compare commits
7 Commits
resolve_es
...
resolve_De
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
243329aa3d | ||
|
|
ae69fe30f2 | ||
|
|
a6a50297de | ||
|
|
c0bcd6294a | ||
|
|
5f356b509a | ||
|
|
ca5dbb856d | ||
|
|
a9e758f67c |
@@ -2,6 +2,8 @@
|
||||
src/**/__mocks__/**/*
|
||||
dist/
|
||||
Contracts/
|
||||
src/Api/Apis.ts
|
||||
src/AuthType.ts
|
||||
src/Bindings/BindingHandlersRegisterer.ts
|
||||
src/Bindings/ReactBindingHandler.ts
|
||||
src/Common/Constants.ts
|
||||
@@ -35,6 +37,7 @@ src/Definitions/svg.d.ts
|
||||
src/Explorer/ComponentRegisterer.test.ts
|
||||
src/Explorer/ComponentRegisterer.ts
|
||||
src/Explorer/Controls/DiffEditor/DiffEditorComponent.ts
|
||||
|
||||
src/Explorer/Controls/Editor/EditorComponent.ts
|
||||
src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts
|
||||
src/Explorer/DataSamples/ContainerSampleGenerator.test.ts
|
||||
@@ -78,15 +81,18 @@ src/Explorer/Tables/DataTable/DataTableBindingManager.ts
|
||||
src/Explorer/Tables/DataTable/DataTableBuilder.ts
|
||||
src/Explorer/Tables/DataTable/DataTableContextMenu.ts
|
||||
src/Explorer/Tables/DataTable/DataTableOperationManager.ts
|
||||
# src/Explorer/Tables/DataTable/DataTableOperations.ts
|
||||
src/Explorer/Tables/DataTable/DataTableViewModel.ts
|
||||
# src/Explorer/Tables/DataTable/TableCommands.ts
|
||||
# src/Explorer/Tables/DataTable/TableEntityCache.ts
|
||||
src/Explorer/Tables/DataTable/TableEntityListViewModel.ts
|
||||
# src/Explorer/Tables/Entities.ts
|
||||
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
|
||||
src/Explorer/Tables/TableDataClient.ts
|
||||
src/Explorer/Tables/TableEntityProcessor.ts
|
||||
src/Explorer/Tables/Utilities.ts
|
||||
src/Explorer/Tabs/ConflictsTab.ts
|
||||
src/Explorer/Tabs/DatabaseSettingsTab.ts
|
||||
src/Explorer/Tabs/DocumentsTab.test.ts
|
||||
src/Explorer/Tabs/DocumentsTab.ts
|
||||
src/Explorer/Tabs/GraphTab.ts
|
||||
src/Explorer/Tabs/MongoDocumentsTab.ts
|
||||
@@ -111,10 +117,12 @@ src/Index.ts
|
||||
src/Platform/Hosted/Authorization.ts
|
||||
src/ReactDevTools.ts
|
||||
src/Shared/Constants.ts
|
||||
src/Shared/DefaultExperienceUtility.test.ts
|
||||
src/Shared/DefaultExperienceUtility.ts
|
||||
src/Shared/appInsights.ts
|
||||
src/SparkClusterManager/ArcadiaResourceManager.ts
|
||||
src/SparkClusterManager/SparkClusterManager.ts
|
||||
src/Terminal/JupyterLabAppFactory.ts
|
||||
src/Terminal/NotebookAppContracts.d.ts
|
||||
src/applyExplorerBindings.ts
|
||||
src/global.d.ts
|
||||
src/setupTests.ts
|
||||
src/Explorer/Controls/InputTypeahead/InputTypeaheadComponent.tsx
|
||||
@@ -123,15 +131,25 @@ src/Explorer/Controls/Notebook/NotebookTerminalComponent.tsx
|
||||
src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx
|
||||
src/Explorer/Controls/TreeComponent/TreeComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx
|
||||
; src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphVizComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/LeftPaneComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/MiddlePaneComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.test.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.test.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
|
||||
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
||||
; src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/VirtualCommandBarComponent.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/contents/index.tsx
|
||||
; src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx
|
||||
src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx
|
||||
src/Explorer/Notebook/NotebookRenderer/decorators/draggable/index.tsx
|
||||
src/Explorer/Notebook/NotebookRenderer/decorators/hijack-scroll/index.tsx
|
||||
src/Explorer/Notebook/NotebookRenderer/decorators/kbd-shortcuts/index.tsx
|
||||
src/Explorer/Notebook/temp/inputs/connected-editors/codemirror.tsx
|
||||
src/Explorer/Tree/ResourceTreeAdapter.tsx
|
||||
__mocks__/monaco-editor.ts
|
||||
src/Explorer/Tree/ResourceTree.tsx
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* Data Explorer version {major.minor.patch}
|
||||
*/
|
||||
export const DataExplorer = "1.0.1";
|
||||
export const DataExplorer: string = "1.0.1";
|
||||
|
||||
@@ -58,7 +58,7 @@ export class LeftPaneComponent extends React.Component<LeftPaneComponentProps> {
|
||||
className={className}
|
||||
as="tr"
|
||||
aria-label={node.caption}
|
||||
onActivated={() => this.props.onRootNodeSelected(node.id)}
|
||||
onActivated={(e) => this.props.onRootNodeSelected(node.id)}
|
||||
key={node.id}
|
||||
>
|
||||
<td className="resultItem">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import * as Q from "q";
|
||||
import React from "react";
|
||||
import { GraphHighlightedNodeData, PossibleVertex } from "./GraphExplorer";
|
||||
import { Mode, NodePropertiesComponent, NodePropertiesComponentProps } from "./NodePropertiesComponent";
|
||||
import { NodePropertiesComponent, NodePropertiesComponentProps, Mode } from "./NodePropertiesComponent";
|
||||
import { GraphHighlightedNodeData, EditedProperties, EditedEdges, PossibleVertex } from "./GraphExplorer";
|
||||
|
||||
describe("Property pane", () => {
|
||||
const title = "My Title";
|
||||
@@ -37,18 +37,17 @@ describe("Property pane", () => {
|
||||
return {
|
||||
expandedTitle: title,
|
||||
isCollapsed: false,
|
||||
onCollapsedChanged: jest.fn(),
|
||||
onCollapsedChanged: (newValue: boolean): void => {},
|
||||
node: highlightedNode,
|
||||
getPkIdFromNodeData: (): string => undefined,
|
||||
collectionPartitionKeyProperty: undefined,
|
||||
updateVertexProperties: (): Q.Promise<void> => Q.resolve(),
|
||||
selectNode: jest.fn(),
|
||||
updatePossibleVertices: (): Q.Promise<PossibleVertex[]> => Q.resolve(undefined),
|
||||
possibleEdgeLabels: undefined,
|
||||
//eslint-disable-next-line
|
||||
editGraphEdges: (): Q.Promise<any> => Q.resolve(),
|
||||
deleteHighlightedNode: jest.fn(),
|
||||
onModeChanged: jest.fn(),
|
||||
getPkIdFromNodeData: (v: GraphHighlightedNodeData): string => null,
|
||||
collectionPartitionKeyProperty: null,
|
||||
updateVertexProperties: (editedProperties: EditedProperties): Q.Promise<void> => Q.resolve(),
|
||||
selectNode: (id: string): void => {},
|
||||
updatePossibleVertices: (): Q.Promise<PossibleVertex[]> => Q.resolve(null),
|
||||
possibleEdgeLabels: null,
|
||||
editGraphEdges: (editedEdges: EditedEdges): Q.Promise<any> => Q.resolve(),
|
||||
deleteHighlightedNode: (): void => {},
|
||||
onModeChanged: (newMode: Mode): void => {},
|
||||
viewMode: Mode.READONLY_PROP,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@ export class NodePropertiesComponent extends React.Component<
|
||||
super(props);
|
||||
this.state = {
|
||||
editedProperties: {
|
||||
pkId: undefined,
|
||||
pkId: null,
|
||||
readOnlyProperties: [],
|
||||
existingProperties: [],
|
||||
addedProperties: [],
|
||||
@@ -98,12 +98,15 @@ export class NodePropertiesComponent extends React.Component<
|
||||
};
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps(props: NodePropertiesComponentProps): Partial<NodePropertiesComponentState> {
|
||||
public static getDerivedStateFromProps(
|
||||
props: NodePropertiesComponentProps,
|
||||
state: NodePropertiesComponentState
|
||||
): Partial<NodePropertiesComponentState> {
|
||||
if (props.viewMode !== Mode.READONLY_PROP) {
|
||||
return { isDeleteConfirm: false };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
@@ -135,10 +138,10 @@ export class NodePropertiesComponent extends React.Component<
|
||||
* @param value
|
||||
*/
|
||||
private static getTypeOption(value: any): ViewModels.InputPropertyValueTypeString {
|
||||
if (value === undefined) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
const type = typeof value;
|
||||
let type = typeof value;
|
||||
switch (type) {
|
||||
case "number":
|
||||
case "boolean":
|
||||
@@ -169,9 +172,10 @@ export class NodePropertiesComponent extends React.Component<
|
||||
];
|
||||
|
||||
const existingProps: ViewModels.InputProperty[] = [];
|
||||
|
||||
if (this.props.node.hasOwnProperty("properties")) {
|
||||
const hProps = this.props.node["properties"];
|
||||
for (const p in hProps) {
|
||||
for (let p in hProps) {
|
||||
const propValues = hProps[p];
|
||||
(p === partitionKeyProperty ? readOnlyProps : existingProps).push({
|
||||
key: p,
|
||||
@@ -433,7 +437,7 @@ export class NodePropertiesComponent extends React.Component<
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { shallow } from "enzyme";
|
||||
import React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
import { GraphHighlightedNodeData } from "./GraphExplorer";
|
||||
|
||||
import {
|
||||
ReadOnlyNodePropertiesComponent,
|
||||
ReadOnlyNodePropertiesComponentProps,
|
||||
@@ -43,7 +44,7 @@ describe("<ReadOnlyNodePropertiesComponent />", () => {
|
||||
const mockNode2 = {
|
||||
...mockNode,
|
||||
properties: {
|
||||
key3: ["abcd", 1234, true, false, undefined],
|
||||
key3: ["abcd", 1234, true, false, undefined, null],
|
||||
},
|
||||
};
|
||||
const props: ReadOnlyNodePropertiesComponentProps = { node: mockNode2 };
|
||||
|
||||
@@ -60,7 +60,9 @@ export class ReadOnlyNodePropertiesComponent extends React.Component<ReadOnlyNod
|
||||
}
|
||||
|
||||
public static singlePropertyValueToString(value: ViewModels.GremlinPropertyValueType): string {
|
||||
if (typeof value === "undefined") {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
} else if (typeof value === "undefined") {
|
||||
return "undefined";
|
||||
} else {
|
||||
return value.toString();
|
||||
@@ -69,8 +71,11 @@ export class ReadOnlyNodePropertiesComponent extends React.Component<ReadOnlyNod
|
||||
|
||||
public static renderSinglePropertyValue(value: ViewModels.GremlinPropertyValueType): JSX.Element {
|
||||
let singlePropValue = value;
|
||||
const className = "propertyValue";
|
||||
if (typeof singlePropValue === "undefined") {
|
||||
let className = "propertyValue";
|
||||
if (singlePropValue === null) {
|
||||
singlePropValue = "null";
|
||||
className += " isNull";
|
||||
} else if (typeof singlePropValue === "undefined") {
|
||||
singlePropValue = "undefined";
|
||||
} else {
|
||||
singlePropValue = value.toString();
|
||||
|
||||
@@ -123,7 +123,7 @@ exports[`<ReadOnlyNodePropertiesComponent /> renders properties (with multiple v
|
||||
</td>
|
||||
<td
|
||||
className="valueCol"
|
||||
title="abcd, 1234, true, false, undefined"
|
||||
title="abcd, 1234, true, false, undefined, null"
|
||||
>
|
||||
<div
|
||||
className="propertyValue"
|
||||
@@ -155,6 +155,12 @@ exports[`<ReadOnlyNodePropertiesComponent /> renders properties (with multiple v
|
||||
>
|
||||
undefined
|
||||
</div>
|
||||
<div
|
||||
className="propertyValue isNull"
|
||||
key="null"
|
||||
>
|
||||
null
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -4,8 +4,6 @@ import * as React from "react";
|
||||
import { useFullScreenURLs } from "../hooks/useFullScreenURLs";
|
||||
|
||||
export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
const [isReadUrlCopy, setIsReadUrlCopy] = React.useState<boolean>(false);
|
||||
const [isReadWriteUrlCopy, setIsReadWriteUrlCopy] = React.useState<boolean>(false);
|
||||
const result = useFullScreenURLs();
|
||||
if (!result) {
|
||||
return <Spinner label="Generating URLs..." ariaLive="assertive" labelPosition="right" />;
|
||||
@@ -27,9 +25,8 @@ export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
<DefaultButton
|
||||
onClick={() => {
|
||||
copyToClipboard(readWriteUrl);
|
||||
setIsReadWriteUrlCopy(true);
|
||||
}}
|
||||
text={isReadWriteUrlCopy ? "Copied" : "Copy"}
|
||||
text="Copy"
|
||||
iconProps={{ iconName: "Copy" }}
|
||||
/>
|
||||
<PrimaryButton
|
||||
@@ -44,10 +41,9 @@ export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
<Stack horizontal tokens={{ childrenGap: 10 }}>
|
||||
<DefaultButton
|
||||
onClick={() => {
|
||||
setIsReadUrlCopy(true);
|
||||
copyToClipboard(readUrl);
|
||||
}}
|
||||
text={isReadUrlCopy ? "Copied" : "Copy"}
|
||||
text="Copy"
|
||||
iconProps={{ iconName: "Copy" }}
|
||||
/>
|
||||
<PrimaryButton
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Collection } from "Contracts/ViewModels";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import { useTabs } from "hooks/useTabs";
|
||||
import React, { FunctionComponent, useState } from "react";
|
||||
import { DefaultExperienceUtility } from "Shared/DefaultExperienceUtility";
|
||||
import * as DefaultExperienceUtility from "Shared/DefaultExperienceUtility";
|
||||
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "UserContext";
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Collection, Database } from "Contracts/ViewModels";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import { useTabs } from "hooks/useTabs";
|
||||
import React, { FunctionComponent, useState } from "react";
|
||||
import { DefaultExperienceUtility } from "Shared/DefaultExperienceUtility";
|
||||
import * as DefaultExperienceUtility from "Shared/DefaultExperienceUtility";
|
||||
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "UserContext";
|
||||
|
||||
@@ -10,7 +10,7 @@ describe("Documents tab", () => {
|
||||
describe("buildQuery", () => {
|
||||
it("should generate the right select query for SQL API", () => {
|
||||
const documentsTab = new DocumentsTab({
|
||||
partitionKey: null,
|
||||
partitionKey: undefined,
|
||||
documentIds: ko.observableArray<DocumentId>(),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
@@ -82,9 +82,9 @@ describe("Documents tab", () => {
|
||||
container: mongoExplorer,
|
||||
});
|
||||
|
||||
it("should be false for null or undefined collection", () => {
|
||||
it("should be false for undefined or undefined collection", () => {
|
||||
const documentsTab = new DocumentsTab({
|
||||
partitionKey: null,
|
||||
partitionKey: undefined,
|
||||
documentIds: ko.observableArray<DocumentId>(),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
@@ -94,10 +94,10 @@ describe("Documents tab", () => {
|
||||
expect(documentsTab.showPartitionKey).toBe(false);
|
||||
});
|
||||
|
||||
it("should be false for null or undefined partitionKey", () => {
|
||||
it("should be false for undefined or undefined partitionKey", () => {
|
||||
const documentsTab = new DocumentsTab({
|
||||
collection: collectionWithoutPartitionKey,
|
||||
partitionKey: null,
|
||||
partitionKey: undefined,
|
||||
documentIds: ko.observableArray<DocumentId>(),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
@@ -110,7 +110,7 @@ describe("Documents tab", () => {
|
||||
it("should be true for non-Mongo accounts with system partitionKey", () => {
|
||||
const documentsTab = new DocumentsTab({
|
||||
collection: collectionWithSystemPartitionKey,
|
||||
partitionKey: null,
|
||||
partitionKey: undefined,
|
||||
documentIds: ko.observableArray<DocumentId>(),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
@@ -126,7 +126,7 @@ describe("Documents tab", () => {
|
||||
});
|
||||
const documentsTab = new DocumentsTab({
|
||||
collection: mongoCollectionWithSystemPartitionKey,
|
||||
partitionKey: null,
|
||||
partitionKey: undefined,
|
||||
documentIds: ko.observableArray<DocumentId>(),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
@@ -139,7 +139,7 @@ describe("Documents tab", () => {
|
||||
it("should be true for non-system partitionKey", () => {
|
||||
const documentsTab = new DocumentsTab({
|
||||
collection: collectionWithNonSystemPartitionKey,
|
||||
partitionKey: null,
|
||||
partitionKey: undefined,
|
||||
documentIds: ko.observableArray<DocumentId>(),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
|
||||
@@ -118,7 +118,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
||||
const saveButtonChildren = [];
|
||||
if (this.container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
||||
saveButtonChildren.push({
|
||||
iconName: copyToLabel,
|
||||
iconName: "Copy",
|
||||
onCommandClick: () => this.copyNotebook(),
|
||||
commandButtonLabel: copyToLabel,
|
||||
hasPopup: false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as ko from "knockout";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import * as Constants from "../Common/Constants";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
|
||||
export abstract class WaitsForTemplateViewModel implements ViewModels.WaitsForTemplate {
|
||||
public isTemplateReady: ko.Observable<boolean>;
|
||||
@@ -14,11 +14,11 @@ export abstract class WaitsForTemplateViewModel implements ViewModels.WaitsForTe
|
||||
callback(value);
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (e: KeyboardEvent) {
|
||||
document.addEventListener("keydown", (e: KeyboardEvent) => {
|
||||
// To trap keyboard focus in AddCollection pane
|
||||
let firstFocusableElement = document.getElementById("closeBtnAddCollection");
|
||||
let lastFocusableElement = document.getElementById("submitBtnAddCollection");
|
||||
var isTabPressed = e.keyCode === Constants.KeyCodes.Tab;
|
||||
const firstFocusableElement = document.getElementById("closeBtnAddCollection");
|
||||
const lastFocusableElement = document.getElementById("submitBtnAddCollection");
|
||||
const isTabPressed = e.keyCode === Constants.KeyCodes.Tab;
|
||||
if (isTabPressed) {
|
||||
if (e.shiftKey) {
|
||||
/* shift + tab */ if (document.activeElement === firstFocusableElement) {
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { configContext } from "../../ConfigContext";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
|
||||
import * as DefaultExperienceUtility from "../../Shared/DefaultExperienceUtility";
|
||||
import { userContext } from "../../UserContext";
|
||||
|
||||
export default class AuthHeadersUtil {
|
||||
public static async generateEncryptedToken(readOnly: boolean = false): Promise<DataModels.GenerateTokenResponse> {
|
||||
const url = configContext.BACKEND_ENDPOINT + "/api/tokens/generateToken" + AuthHeadersUtil._generateResourceUrl();
|
||||
const headers: any = { authorization: userContext.authorizationToken };
|
||||
headers[Constants.HttpHeaders.getReadOnlyKey] = readOnly;
|
||||
export const _generateResourceUrl = (): string => {
|
||||
const { databaseAccount, resourceGroup, subscriptionId } = userContext;
|
||||
const apiKind: DataModels.ApiKind = DefaultExperienceUtility.getApiKindFromDefaultExperience(userContext.apiType);
|
||||
const accountEndpoint = databaseAccount?.properties?.documentEndpoint || "";
|
||||
const sid = subscriptionId || "";
|
||||
const rg = resourceGroup || "";
|
||||
const dba = databaseAccount?.name || "";
|
||||
const resourceUrl = encodeURIComponent(accountEndpoint);
|
||||
const rid = "";
|
||||
const rtype = "";
|
||||
return `?resourceUrl=${resourceUrl}&rid=${rid}&rtype=${rtype}&sid=${sid}&rg=${rg}&dba=${dba}&api=${apiKind}`;
|
||||
};
|
||||
|
||||
const response = await fetch(url, { method: "POST", headers });
|
||||
const result = await response.json();
|
||||
// This API has a quirk where the response must be parsed to JSON twice
|
||||
return JSON.parse(result);
|
||||
}
|
||||
export const generateEncryptedToken = async (readOnly = false): Promise<DataModels.GenerateTokenResponse> => {
|
||||
const url = configContext.BACKEND_ENDPOINT + "/api/tokens/generateToken" + _generateResourceUrl();
|
||||
const headers: any = { authorization: userContext.authorizationToken };
|
||||
headers[Constants.HttpHeaders.getReadOnlyKey] = readOnly;
|
||||
|
||||
private static _generateResourceUrl(): string {
|
||||
const { databaseAccount, resourceGroup, subscriptionId } = userContext;
|
||||
const apiKind: DataModels.ApiKind = DefaultExperienceUtility.getApiKindFromDefaultExperience(userContext.apiType);
|
||||
const accountEndpoint = databaseAccount?.properties?.documentEndpoint || "";
|
||||
const sid = subscriptionId || "";
|
||||
const rg = resourceGroup || "";
|
||||
const dba = databaseAccount?.name || "";
|
||||
const resourceUrl = encodeURIComponent(accountEndpoint);
|
||||
const rid = "";
|
||||
const rtype = "";
|
||||
return `?resourceUrl=${resourceUrl}&rid=${rid}&rtype=${rtype}&sid=${sid}&rg=${rg}&dba=${dba}&api=${apiKind}`;
|
||||
}
|
||||
}
|
||||
const response = await fetch(url, { method: "POST", headers });
|
||||
const result = await response.json();
|
||||
// This API has a quirk where the response must be parsed to JSON twice
|
||||
return JSON.parse(result);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AccountKind, CapabilityNames } from "../../Common/Constants";
|
||||
import { AccessInputMetadata, ApiKind } from "../../Contracts/DataModels";
|
||||
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
|
||||
import * as DefaultExperienceUtility from "../../Shared/DefaultExperienceUtility";
|
||||
import { userContext } from "../../UserContext";
|
||||
|
||||
export function getDatabaseAccountPropertiesFromMetadata(metadata: AccessInputMetadata): unknown {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import { userContext } from "../UserContext";
|
||||
import { DefaultExperienceUtility } from "./DefaultExperienceUtility";
|
||||
import * as DefaultExperienceUtility from "./DefaultExperienceUtility";
|
||||
|
||||
describe("Default Experience Utility", () => {
|
||||
describe("getDefaultExperienceFromApiKind()", () => {
|
||||
function runScenario(apiKind: number, expectedExperience: typeof userContext.apiType): void {
|
||||
const runScenario = (apiKind: number, expectedExperience: typeof userContext.apiType): void => {
|
||||
const resolvedExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(apiKind);
|
||||
expect(resolvedExperience).toEqual(expectedExperience);
|
||||
}
|
||||
};
|
||||
|
||||
describe("On SQL", () => {
|
||||
it("should return SQL", () => runScenario(DataModels.ApiKind.SQL, "SQL"));
|
||||
@@ -35,10 +35,10 @@ describe("Default Experience Utility", () => {
|
||||
});
|
||||
|
||||
describe("getApiKindFromDefaultExperience()", () => {
|
||||
function runScenario(defaultExperience: typeof userContext.apiType | null, expectedApiKind: number): void {
|
||||
const runScenario = (defaultExperience: typeof userContext.apiType | null, expectedApiKind: number): void => {
|
||||
const resolvedApiKind = DefaultExperienceUtility.getApiKindFromDefaultExperience(defaultExperience);
|
||||
expect(resolvedApiKind).toEqual(expectedApiKind);
|
||||
}
|
||||
};
|
||||
|
||||
describe("On SQL", () => {
|
||||
it("should return SQL", () => runScenario("SQL", DataModels.ApiKind.SQL));
|
||||
@@ -60,8 +60,8 @@ describe("Default Experience Utility", () => {
|
||||
it("should return Graph", () => runScenario("Gremlin", DataModels.ApiKind.Graph));
|
||||
});
|
||||
|
||||
describe("On null", () => {
|
||||
it("should return SQL", () => runScenario(null, DataModels.ApiKind.SQL));
|
||||
describe("On undefined", () => {
|
||||
it("should return SQL", () => runScenario(undefined, DataModels.ApiKind.SQL));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,47 +1,45 @@
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import { userContext } from "../UserContext";
|
||||
|
||||
export class DefaultExperienceUtility {
|
||||
public static getApiKindFromDefaultExperience(defaultExperience: typeof userContext.apiType): DataModels.ApiKind {
|
||||
if (!defaultExperience) {
|
||||
export const getApiKindFromDefaultExperience = (defaultExperience: typeof userContext.apiType): DataModels.ApiKind => {
|
||||
if (!defaultExperience) {
|
||||
return DataModels.ApiKind.SQL;
|
||||
}
|
||||
|
||||
switch (defaultExperience) {
|
||||
case "SQL":
|
||||
return DataModels.ApiKind.SQL;
|
||||
}
|
||||
case "Mongo":
|
||||
return DataModels.ApiKind.MongoDB;
|
||||
case "Tables":
|
||||
return DataModels.ApiKind.Table;
|
||||
case "Cassandra":
|
||||
return DataModels.ApiKind.Cassandra;
|
||||
case "Gremlin":
|
||||
return DataModels.ApiKind.Graph;
|
||||
default:
|
||||
return DataModels.ApiKind.SQL;
|
||||
}
|
||||
};
|
||||
|
||||
switch (defaultExperience) {
|
||||
case "SQL":
|
||||
return DataModels.ApiKind.SQL;
|
||||
case "Mongo":
|
||||
return DataModels.ApiKind.MongoDB;
|
||||
case "Tables":
|
||||
return DataModels.ApiKind.Table;
|
||||
case "Cassandra":
|
||||
return DataModels.ApiKind.Cassandra;
|
||||
case "Gremlin":
|
||||
return DataModels.ApiKind.Graph;
|
||||
default:
|
||||
return DataModels.ApiKind.SQL;
|
||||
}
|
||||
export const getDefaultExperienceFromApiKind = (apiKind: DataModels.ApiKind): typeof userContext.apiType => {
|
||||
if (apiKind === undefined) {
|
||||
return "SQL";
|
||||
}
|
||||
|
||||
public static getDefaultExperienceFromApiKind(apiKind: DataModels.ApiKind): typeof userContext.apiType {
|
||||
if (apiKind == null) {
|
||||
switch (apiKind) {
|
||||
case DataModels.ApiKind.SQL:
|
||||
return "SQL";
|
||||
case DataModels.ApiKind.MongoDB:
|
||||
case DataModels.ApiKind.MongoDBCompute:
|
||||
return "Mongo";
|
||||
case DataModels.ApiKind.Table:
|
||||
return "Tables";
|
||||
case DataModels.ApiKind.Cassandra:
|
||||
return "Cassandra";
|
||||
case DataModels.ApiKind.Graph:
|
||||
return "Gremlin";
|
||||
default:
|
||||
return "SQL";
|
||||
}
|
||||
|
||||
switch (apiKind) {
|
||||
case DataModels.ApiKind.SQL:
|
||||
return "SQL";
|
||||
case DataModels.ApiKind.MongoDB:
|
||||
case DataModels.ApiKind.MongoDBCompute:
|
||||
return "Mongo";
|
||||
case DataModels.ApiKind.Table:
|
||||
return "Tables";
|
||||
case DataModels.ApiKind.Cassandra:
|
||||
return "Cassandra";
|
||||
case DataModels.ApiKind.Graph:
|
||||
return "Gremlin";
|
||||
default:
|
||||
return "SQL";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,37 +5,35 @@ import { ServerConnection, TerminalManager } from "@jupyterlab/services";
|
||||
import { Terminal } from "@jupyterlab/terminal";
|
||||
import { Panel, Widget } from "@phosphor/widgets";
|
||||
|
||||
export class JupyterLabAppFactory {
|
||||
public static async createTerminalApp(serverSettings: ServerConnection.ISettings) {
|
||||
const manager = new TerminalManager({
|
||||
serverSettings: serverSettings,
|
||||
});
|
||||
const session = await manager.startNew();
|
||||
const term = new Terminal(session, { theme: "dark", shutdownOnClose: true });
|
||||
export const createTerminalApp = async (serverSettings: ServerConnection.ISettings) => {
|
||||
const manager = new TerminalManager({
|
||||
serverSettings: serverSettings,
|
||||
});
|
||||
const session = await manager.startNew();
|
||||
const term = new Terminal(session, { theme: "dark", shutdownOnClose: true });
|
||||
|
||||
if (!term) {
|
||||
console.error("Failed starting terminal");
|
||||
return;
|
||||
}
|
||||
|
||||
term.title.closable = false;
|
||||
term.addClass("terminalWidget");
|
||||
|
||||
let panel = new Panel();
|
||||
panel.addWidget(term as any);
|
||||
panel.id = "main";
|
||||
|
||||
// Attach the widget to the dom.
|
||||
Widget.attach(panel, document.body);
|
||||
|
||||
// Handle resize events.
|
||||
window.addEventListener("resize", () => {
|
||||
panel.update();
|
||||
});
|
||||
|
||||
// Dispose terminal when unloading.
|
||||
window.addEventListener("unload", () => {
|
||||
panel.dispose();
|
||||
});
|
||||
if (!term) {
|
||||
console.error("Failed starting terminal");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
term.title.closable = false;
|
||||
term.addClass("terminalWidget");
|
||||
|
||||
const panel = new Panel();
|
||||
panel.addWidget(term as any);
|
||||
panel.id = "main";
|
||||
|
||||
// Attach the widget to the dom.
|
||||
Widget.attach(panel, document.body);
|
||||
|
||||
// Handle resize events.
|
||||
window.addEventListener("resize", () => {
|
||||
panel.update();
|
||||
});
|
||||
|
||||
// Dispose terminal when unloading.
|
||||
window.addEventListener("unload", () => {
|
||||
panel.dispose();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Action } from "../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
||||
import { updateUserContext } from "../UserContext";
|
||||
import "./index.css";
|
||||
import { JupyterLabAppFactory } from "./JupyterLabAppFactory";
|
||||
import { createTerminalApp } from "./JupyterLabAppFactory";
|
||||
import { TerminalProps } from "./TerminalProps";
|
||||
|
||||
const createServerSettings = (props: TerminalProps): ServerConnection.ISettings => {
|
||||
@@ -54,7 +54,7 @@ const initTerminal = async (props: TerminalProps) => {
|
||||
const startTime = TelemetryProcessor.traceStart(Action.OpenTerminal, data);
|
||||
|
||||
try {
|
||||
await JupyterLabAppFactory.createTerminalApp(serverSettings);
|
||||
await createTerminalApp(serverSettings);
|
||||
TelemetryProcessor.traceSuccess(Action.OpenTerminal, data, startTime);
|
||||
} catch (error) {
|
||||
TelemetryProcessor.traceFailure(Action.OpenTerminal, data, startTime);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { BindingHandlersRegisterer } from "./Bindings/BindingHandlersRegisterer"
|
||||
import Explorer from "./Explorer/Explorer";
|
||||
|
||||
export const applyExplorerBindings = (explorer: Explorer) => {
|
||||
if (explorer) {
|
||||
if (!!explorer) {
|
||||
window.dataExplorer = explorer;
|
||||
BindingHandlersRegisterer.registerBindingHandlers();
|
||||
ko.applyBindings(explorer);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { GenerateTokenResponse } from "../Contracts/DataModels";
|
||||
import AuthHeadersUtil from "../Platform/Hosted/Authorization";
|
||||
import * as AuthHeadersUtil from "../Platform/Hosted/Authorization";
|
||||
|
||||
export function useFullScreenURLs(): GenerateTokenResponse | undefined {
|
||||
const [state, setState] = useState<GenerateTokenResponse>();
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
getDatabaseAccountPropertiesFromMetadata,
|
||||
} from "../Platform/Hosted/HostedUtils";
|
||||
import { CollectionCreation } from "../Shared/Constants";
|
||||
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
||||
import * as DefaultExperienceUtility from "../Shared/DefaultExperienceUtility";
|
||||
import { PortalEnv, updateUserContext, userContext } from "../UserContext";
|
||||
import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||
import { DatabaseAccountListKeysResult } from "../Utils/arm/generatedClients/cosmos/types";
|
||||
|
||||
Reference in New Issue
Block a user