mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-26 04:11:24 +00:00
Compare commits
20 Commits
Remove-Exp
...
jbunster/s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
881cef6157 | ||
|
|
4efacace16 | ||
|
|
9878bf0d5e | ||
|
|
5e0523c7d9 | ||
|
|
9d0bc86197 | ||
|
|
531df811da | ||
|
|
5a019eb431 | ||
|
|
8f3cb7282b | ||
|
|
154db1dcd5 | ||
|
|
e8b79d6260 | ||
|
|
10c4dd0f19 | ||
|
|
5cf16d01b5 | ||
|
|
127784abdd | ||
|
|
c7b9ff6794 | ||
|
|
71e7ad4547 | ||
|
|
67062c18aa | ||
|
|
ab283cb8ff | ||
|
|
045a28b7a4 | ||
|
|
b7c911d19a | ||
|
|
5323f6ca4b |
@@ -5,7 +5,6 @@ src/Api/Apis.ts
|
|||||||
src/AuthType.ts
|
src/AuthType.ts
|
||||||
src/Bindings/BindingHandlersRegisterer.ts
|
src/Bindings/BindingHandlersRegisterer.ts
|
||||||
src/Bindings/ReactBindingHandler.ts
|
src/Bindings/ReactBindingHandler.ts
|
||||||
src/Common/ArrayHashMap.ts
|
|
||||||
src/Common/Constants.ts
|
src/Common/Constants.ts
|
||||||
src/Common/CosmosClient.test.ts
|
src/Common/CosmosClient.test.ts
|
||||||
src/Common/CosmosClient.ts
|
src/Common/CosmosClient.ts
|
||||||
@@ -13,15 +12,12 @@ src/Common/DataAccessUtilityBase.test.ts
|
|||||||
src/Common/DataAccessUtilityBase.ts
|
src/Common/DataAccessUtilityBase.ts
|
||||||
src/Common/EditableUtility.ts
|
src/Common/EditableUtility.ts
|
||||||
src/Common/HashMap.test.ts
|
src/Common/HashMap.test.ts
|
||||||
src/Common/HashMap.ts
|
|
||||||
src/Common/Logger.test.ts
|
src/Common/Logger.test.ts
|
||||||
src/Common/MessageHandler.test.ts
|
src/Common/MessageHandler.test.ts
|
||||||
src/Common/MessageHandler.ts
|
src/Common/MessageHandler.ts
|
||||||
src/Common/MongoProxyClient.test.ts
|
src/Common/MongoProxyClient.test.ts
|
||||||
src/Common/MongoUtility.ts
|
src/Common/MongoUtility.ts
|
||||||
src/Common/NotificationsClientBase.ts
|
src/Common/NotificationsClientBase.ts
|
||||||
src/Common/ObjectCache.test.ts
|
|
||||||
src/Common/ObjectCache.ts
|
|
||||||
src/Common/QueriesClient.ts
|
src/Common/QueriesClient.ts
|
||||||
src/Common/Splitter.ts
|
src/Common/Splitter.ts
|
||||||
src/Config.ts
|
src/Config.ts
|
||||||
@@ -125,7 +121,7 @@ src/Explorer/Panes/GraphStylingPane.ts
|
|||||||
# src/Explorer/Panes/NewVertexPane.ts
|
# src/Explorer/Panes/NewVertexPane.ts
|
||||||
src/Explorer/Panes/PaneComponents.ts
|
src/Explorer/Panes/PaneComponents.ts
|
||||||
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
||||||
src/Explorer/Panes/StringInputPane.ts
|
src/Explorer/Panes/SetupNotebooksPane.ts
|
||||||
src/Explorer/Panes/SwitchDirectoryPane.ts
|
src/Explorer/Panes/SwitchDirectoryPane.ts
|
||||||
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
||||||
|
|||||||
30519
package-lock.json
generated
30519
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -176,7 +176,7 @@
|
|||||||
"typescript": "4.2.4",
|
"typescript": "4.2.4",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"wait-on": "4.0.2",
|
"wait-on": "4.0.2",
|
||||||
"webpack": "4.43.0",
|
"webpack": "4.46.0",
|
||||||
"webpack-bundle-analyzer": "3.6.1",
|
"webpack-bundle-analyzer": "3.6.1",
|
||||||
"webpack-cli": "3.3.10",
|
"webpack-cli": "3.3.10",
|
||||||
"webpack-dev-server": "3.11.0"
|
"webpack-dev-server": "3.11.0"
|
||||||
@@ -195,7 +195,7 @@
|
|||||||
"watch": "npm run start",
|
"watch": "npm run start",
|
||||||
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
||||||
"build:ase": "gulp build:ase",
|
"build:ase": "gulp build:ase",
|
||||||
"compile": "tsc",
|
"compile": "tsc -p ./tsconfig.build.json",
|
||||||
"compile:contracts": "tsc -p ./tsconfig.contracts.json",
|
"compile:contracts": "tsc -p ./tsconfig.contracts.json",
|
||||||
"compile:strict": "tsc -p ./tsconfig.strict.json",
|
"compile:strict": "tsc -p ./tsconfig.strict.json",
|
||||||
"format": "prettier --write \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
|
"format": "prettier --write \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
"build:contracts": "npm run compile:contracts",
|
"build:contracts": "npm run compile:contracts",
|
||||||
"strict:find": "node ./strict-null-checks/find.js",
|
"strict:find": "node ./strict-null-checks/find.js",
|
||||||
"strict:add": "node ./strict-null-checks/auto-add.js",
|
"strict:add": "node ./strict-null-checks/auto-add.js",
|
||||||
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
|
"compile:fullStrict": "tsc",
|
||||||
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -22,13 +22,7 @@ export interface ReactAdapter {
|
|||||||
export class Registerer {
|
export class Registerer {
|
||||||
public static register(): void {
|
public static register(): void {
|
||||||
ko.bindingHandlers.react = {
|
ko.bindingHandlers.react = {
|
||||||
init: (
|
init: (element: any, wrappedValueAccessor: () => any) => {
|
||||||
element: any,
|
|
||||||
wrappedValueAccessor: () => any,
|
|
||||||
allBindings?: ko.AllBindings,
|
|
||||||
viewModel?: any,
|
|
||||||
bindingContext?: ko.BindingContext
|
|
||||||
) => {
|
|
||||||
const adapter: ReactAdapter = wrappedValueAccessor();
|
const adapter: ReactAdapter = wrappedValueAccessor();
|
||||||
|
|
||||||
if (adapter.setElement) {
|
if (adapter.setElement) {
|
||||||
|
|||||||
@@ -1,49 +1,9 @@
|
|||||||
import { HashMap } from "./HashMap";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash map of arrays which allows to:
|
* Hash map of arrays which allows to:
|
||||||
* - push an item by key: add to array and create array if needed
|
* - push an item by key: add to array and create array if needed
|
||||||
* - remove item by key: remove from array and delete array if needed
|
* - remove item by key: remove from array and delete array if needed
|
||||||
*/
|
*/
|
||||||
|
export class ArrayHashMap<T> extends Map<string, T[]> {
|
||||||
export class ArrayHashMap<T> {
|
|
||||||
private store: HashMap<T[]>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.store = new HashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public has(key: string): boolean {
|
|
||||||
return this.store.has(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(key: string): T[] {
|
|
||||||
return this.store.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public size(): number {
|
|
||||||
return this.store.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear(): void {
|
|
||||||
this.store.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public keys(): string[] {
|
|
||||||
return this.store.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
public delete(key: string): boolean {
|
|
||||||
return this.store.delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEach(key: string, iteratorFct: (value: T) => void) {
|
|
||||||
const values = this.store.get(key);
|
|
||||||
if (values) {
|
|
||||||
values.forEach((value) => iteratorFct(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item into array.
|
* Insert item into array.
|
||||||
* If no array, create one.
|
* If no array, create one.
|
||||||
@@ -52,16 +12,8 @@ export class ArrayHashMap<T> {
|
|||||||
* @param item
|
* @param item
|
||||||
*/
|
*/
|
||||||
public push(key: string, item: T): void {
|
public push(key: string, item: T): void {
|
||||||
let itemsArray: T[] = this.store.get(key);
|
const array = this.get(key);
|
||||||
if (!itemsArray) {
|
array ? array.includes(item) || array.push(item) : this.set(key, [item]);
|
||||||
itemsArray = [item];
|
|
||||||
this.store.set(key, itemsArray);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemsArray.indexOf(item) === -1) {
|
|
||||||
itemsArray.push(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,18 +22,11 @@ export class ArrayHashMap<T> {
|
|||||||
* @param key
|
* @param key
|
||||||
* @param itemToRemove
|
* @param itemToRemove
|
||||||
*/
|
*/
|
||||||
public remove(key: string, itemToRemove: T) {
|
public remove(key: string, itemToRemove: T): void {
|
||||||
if (!this.store.has(key)) {
|
const array = this.get(key);
|
||||||
return;
|
if (array) {
|
||||||
}
|
const remaining = array.filter((item) => item !== itemToRemove);
|
||||||
|
remaining.length ? this.set(key, remaining) : this.delete(key);
|
||||||
const itemsArray = this.store.get(key);
|
|
||||||
const index = itemsArray.indexOf(itemToRemove);
|
|
||||||
if (index >= 0) {
|
|
||||||
itemsArray.splice(index, 1);
|
|
||||||
if (itemsArray.length === 0) {
|
|
||||||
this.store.delete(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
|
|
||||||
export const getEntityName = (): string => {
|
export const getEntityName = (): string => {
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return "document";
|
return "document";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface TableEntityProps {
|
|||||||
entityValuePlaceholder: string;
|
entityValuePlaceholder: string;
|
||||||
entityValue: string | Date;
|
entityValue: string | Date;
|
||||||
isEntityTypeDate: boolean;
|
isEntityTypeDate: boolean;
|
||||||
|
isEntityValueDisable?: boolean;
|
||||||
entityTimeValue: string;
|
entityTimeValue: string;
|
||||||
entityValueType: string;
|
entityValueType: string;
|
||||||
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
||||||
@@ -22,6 +23,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
entityValueType,
|
entityValueType,
|
||||||
onEntityValueChange,
|
onEntityValueChange,
|
||||||
onSelectDate,
|
onSelectDate,
|
||||||
|
isEntityValueDisable,
|
||||||
onEntityTimeValueChange,
|
onEntityTimeValueChange,
|
||||||
}: TableEntityProps): JSX.Element => {
|
}: TableEntityProps): JSX.Element => {
|
||||||
if (isEntityTypeDate) {
|
if (isEntityTypeDate) {
|
||||||
@@ -33,6 +35,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
value={entityValue && new Date(entityValue)}
|
value={entityValue && new Date(entityValue)}
|
||||||
ariaLabel={entityValuePlaceholder}
|
ariaLabel={entityValuePlaceholder}
|
||||||
onSelectDate={onSelectDate}
|
onSelectDate={onSelectDate}
|
||||||
|
disabled={isEntityValueDisable}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={entityValueLabel && entityValueLabel}
|
label={entityValueLabel && entityValueLabel}
|
||||||
@@ -41,6 +44,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
type="time"
|
type="time"
|
||||||
value={entityTimeValue}
|
value={entityTimeValue}
|
||||||
onChange={onEntityTimeValueChange}
|
onChange={onEntityTimeValueChange}
|
||||||
|
disabled={isEntityValueDisable}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -52,6 +56,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
className="addEntityTextField"
|
className="addEntityTextField"
|
||||||
id="entityValueId"
|
id="entityValueId"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
disabled={isEntityValueDisable}
|
||||||
type={entityValueType}
|
type={entityValueType}
|
||||||
placeholder={entityValuePlaceholder}
|
placeholder={entityValuePlaceholder}
|
||||||
value={typeof entityValue === "string" && entityValue}
|
value={typeof entityValue === "string" && entityValue}
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
import { HashMap } from "./HashMap";
|
|
||||||
|
|
||||||
describe("HashMap", () => {
|
|
||||||
it("should test if key/val exists", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 123);
|
|
||||||
|
|
||||||
expect(map.has("a")).toBe(true);
|
|
||||||
expect(map.has("b")).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should get object back", () => {
|
|
||||||
const map = new HashMap<string>();
|
|
||||||
map.set("a", "123");
|
|
||||||
map.set("a", "456");
|
|
||||||
|
|
||||||
expect(map.get("a")).toBe("456");
|
|
||||||
expect(map.get("a")).not.toBe("123");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return the right size", () => {
|
|
||||||
const map = new HashMap<string>();
|
|
||||||
map.set("a", "123");
|
|
||||||
map.set("b", "456");
|
|
||||||
|
|
||||||
expect(map.size()).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be iterable", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.set("b", 10);
|
|
||||||
map.set("c", 100);
|
|
||||||
map.set("d", 1000);
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
map.forEach((key: string, value: number) => {
|
|
||||||
i += value;
|
|
||||||
});
|
|
||||||
expect(i).toBe(1111);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be deleted", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.set("b", 10);
|
|
||||||
|
|
||||||
expect(map.delete("a")).toBe(true);
|
|
||||||
expect(map.delete("c")).toBe(false);
|
|
||||||
expect(map.has("a")).toBe(false);
|
|
||||||
expect(map.has("b")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should clear", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.clear();
|
|
||||||
expect(map.size()).toBe(0);
|
|
||||||
expect(map.has("a")).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return all keys", () => {
|
|
||||||
const map = new HashMap<number>();
|
|
||||||
map.set("a", 1);
|
|
||||||
map.set("b", 1);
|
|
||||||
expect(map.keys()).toEqual(["a", "b"]);
|
|
||||||
map.clear();
|
|
||||||
expect(map.keys().length).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* Simple hashmap implementation that doesn't rely on ES6 Map nor polyfills
|
|
||||||
*/
|
|
||||||
export class HashMap<T> {
|
|
||||||
constructor(private container: { [key: string]: T } = {}) {}
|
|
||||||
|
|
||||||
public has(key: string): boolean {
|
|
||||||
return this.container.hasOwnProperty(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set(key: string, value: T): void {
|
|
||||||
this.container[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(key: string): T {
|
|
||||||
return this.container[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
public size(): number {
|
|
||||||
return Object.keys(this.container).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public delete(key: string): boolean {
|
|
||||||
if (this.has(key)) {
|
|
||||||
delete this.container[key];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear(): void {
|
|
||||||
this.container = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
public keys(): string[] {
|
|
||||||
return Object.keys(this.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEach(iteratorFct: (key: string, value: T) => void) {
|
|
||||||
for (const k in this.container) {
|
|
||||||
iteratorFct(k, this.container[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ describe("Object cache", () => {
|
|||||||
cache.set("b", 2);
|
cache.set("b", 2);
|
||||||
cache.set("c", 3);
|
cache.set("c", 3);
|
||||||
cache.set("d", 4);
|
cache.set("d", 4);
|
||||||
expect(cache.size()).toBe(2);
|
expect(cache.size).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should remove first added element to keep size at limit", () => {
|
it("should remove first added element to keep size at limit", () => {
|
||||||
|
|||||||
@@ -1,56 +1,27 @@
|
|||||||
import { HashMap } from "./HashMap";
|
export class ObjectCache<T> extends Map<string, T> {
|
||||||
|
constructor(private limit: number) {
|
||||||
export class ObjectCache<T> extends HashMap<T> {
|
|
||||||
private keyQueue: string[]; // Last touched key FIFO to purge cache if too big.
|
|
||||||
private maxNbElements: number;
|
|
||||||
|
|
||||||
public constructor(maxNbElements: number) {
|
|
||||||
super();
|
super();
|
||||||
this.keyQueue = [];
|
|
||||||
this.maxNbElements = maxNbElements;
|
|
||||||
this.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear(): void {
|
public get(key: string): T | undefined {
|
||||||
super.clear();
|
return this.touch(key);
|
||||||
this.keyQueue = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(key: string): T {
|
public set(key: string, value: T): this {
|
||||||
this.markKeyAsTouched(key);
|
if (this.size === this.limit) {
|
||||||
return super.get(key);
|
this.delete(this.keys().next().value);
|
||||||
}
|
|
||||||
|
|
||||||
public set(key: string, value: T): void {
|
|
||||||
super.set(key, value);
|
|
||||||
|
|
||||||
this.markKeyAsTouched(key);
|
|
||||||
|
|
||||||
if (super.size() > this.maxNbElements && key !== this.keyQueue[0]) {
|
|
||||||
this.reduceCacheSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.touch(key, value), this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private touch(key: string, value = super.get(key)) {
|
||||||
* Invalidate elements to keep the total number below the limit
|
// Map keeps (re) insertion order according to ES6 spec
|
||||||
*/
|
if (value) {
|
||||||
private reduceCacheSize(): void {
|
this.delete(key);
|
||||||
// remove a key
|
super.set(key, value);
|
||||||
const oldKey = this.keyQueue.shift();
|
|
||||||
if (oldKey) {
|
|
||||||
super.delete(oldKey);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return value;
|
||||||
* Bubble up this key as new.
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
private markKeyAsTouched(key: string) {
|
|
||||||
const n = this.keyQueue.indexOf(key);
|
|
||||||
if (n > -1) {
|
|
||||||
this.keyQueue.splice(n, 1);
|
|
||||||
}
|
|
||||||
this.keyQueue.push(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import * as ViewModels from "../Contracts/ViewModels";
|
|||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import * as QueryUtils from "../Utils/QueryUtils";
|
import * as QueryUtils from "../Utils/QueryUtils";
|
||||||
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
|
||||||
import { createCollection } from "./dataAccess/createCollection";
|
import { createCollection } from "./dataAccess/createCollection";
|
||||||
import { handleError } from "./ErrorHandlingUtils";
|
|
||||||
import { createDocument } from "./dataAccess/createDocument";
|
import { createDocument } from "./dataAccess/createDocument";
|
||||||
import { deleteDocument } from "./dataAccess/deleteDocument";
|
import { deleteDocument } from "./dataAccess/deleteDocument";
|
||||||
import { queryDocuments } from "./dataAccess/queryDocuments";
|
import { queryDocuments } from "./dataAccess/queryDocuments";
|
||||||
|
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
||||||
|
import { handleError } from "./ErrorHandlingUtils";
|
||||||
|
|
||||||
export class QueriesClient {
|
export class QueriesClient {
|
||||||
private static readonly PartitionKey: DataModels.PartitionKey = {
|
private static readonly PartitionKey: DataModels.PartitionKey = {
|
||||||
@@ -211,7 +211,7 @@ export class QueriesClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fetchQueriesQuery(): string {
|
private fetchQueriesQuery(): string {
|
||||||
if (this.container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return QueriesClient.FetchMongoQuery;
|
return QueriesClient.FetchMongoQuery;
|
||||||
}
|
}
|
||||||
return QueriesClient.FetchQuery;
|
return QueriesClient.FetchQuery;
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export class Splitter {
|
|||||||
$(this.leftSide).resizable(splitterOptions);
|
$(this.leftSide).resizable(splitterOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onResizeStart: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
private onResizeStart: JQueryUI.ResizableEvent = () => {
|
||||||
if (this.direction === SplitterDirection.Vertical) {
|
if (this.direction === SplitterDirection.Vertical) {
|
||||||
$(".ui-resizable-helper").height("100%");
|
$(".ui-resizable-helper").height("100%");
|
||||||
} else {
|
} else {
|
||||||
@@ -82,9 +82,7 @@ export class Splitter {
|
|||||||
$("iframe").css("pointer-events", "none");
|
$("iframe").css("pointer-events", "none");
|
||||||
};
|
};
|
||||||
|
|
||||||
private onResizeStop: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
private onResizeStop: JQueryUI.ResizableEvent = () => $("iframe").css("pointer-events", "auto");
|
||||||
$("iframe").css("pointer-events", "auto");
|
|
||||||
};
|
|
||||||
|
|
||||||
public collapseLeft() {
|
public collapseLeft() {
|
||||||
this.lastX = $(this.splitter).position().left;
|
this.lastX = $(this.splitter).position().left;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export interface TableEntityProps {
|
|||||||
options: { key: string; text: string }[];
|
options: { key: string; text: string }[];
|
||||||
isPropertyTypeDisable: boolean;
|
isPropertyTypeDisable: boolean;
|
||||||
entityTimeValue: string;
|
entityTimeValue: string;
|
||||||
|
isEntityValueDisable?: boolean;
|
||||||
onDeleteEntity?: () => void;
|
onDeleteEntity?: () => void;
|
||||||
onEditEntity?: () => void;
|
onEditEntity?: () => void;
|
||||||
onEntityPropertyChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
onEntityPropertyChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
||||||
@@ -55,6 +56,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|||||||
isPropertyTypeDisable,
|
isPropertyTypeDisable,
|
||||||
isEntityTypeDate,
|
isEntityTypeDate,
|
||||||
entityTimeValue,
|
entityTimeValue,
|
||||||
|
isEntityValueDisable,
|
||||||
onEditEntity,
|
onEditEntity,
|
||||||
onDeleteEntity,
|
onDeleteEntity,
|
||||||
onEntityPropertyChange,
|
onEntityPropertyChange,
|
||||||
@@ -113,6 +115,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|||||||
<EntityValue
|
<EntityValue
|
||||||
entityValueLabel={entityValueLabel}
|
entityValueLabel={entityValueLabel}
|
||||||
entityValueType={getEntityValueType()}
|
entityValueType={getEntityValueType()}
|
||||||
|
isEntityValueDisable={isEntityValueDisable}
|
||||||
entityValuePlaceholder={entityValuePlaceholder}
|
entityValuePlaceholder={entityValuePlaceholder}
|
||||||
entityValue={entityValue}
|
entityValue={entityValue}
|
||||||
isEntityTypeDate={isEntityTypeDate}
|
isEntityTypeDate={isEntityTypeDate}
|
||||||
@@ -121,10 +124,11 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|||||||
onSelectDate={onSelectDate}
|
onSelectDate={onSelectDate}
|
||||||
onEntityTimeValueChange={onEntityTimeValueChange}
|
onEntityTimeValueChange={onEntityTimeValueChange}
|
||||||
/>
|
/>
|
||||||
<TooltipHost content="Edit property" id="editTooltip">
|
{!isEntityValueDisable && (
|
||||||
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
|
<TooltipHost content="Edit property" id="editTooltip">
|
||||||
</TooltipHost>
|
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
|
||||||
|
</TooltipHost>
|
||||||
|
)}
|
||||||
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
|
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
|
||||||
<TooltipHost content="Delete property" id="deleteTooltip">
|
<TooltipHost content="Delete property" id="deleteTooltip">
|
||||||
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
|
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { createCollection, constructRpOptions } from "./createCollection";
|
import { constructRpOptions, createCollection } from "./createCollection";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("createCollection", () => {
|
describe("createCollection", () => {
|
||||||
const createCollectionParams: CreateCollectionParams = {
|
const createCollectionParams: CreateCollectionParams = {
|
||||||
@@ -22,7 +21,7 @@ describe("createCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,32 @@
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
||||||
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { client } from "../CosmosClient";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
import { userContext } from "../../UserContext";
|
||||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable,
|
getCassandraTable,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateMongoDBCollection,
|
|
||||||
getMongoDBCollection,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinGraph,
|
createUpdateGremlinGraph,
|
||||||
getGremlinGraph,
|
getGremlinGraph,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import {
|
||||||
|
createUpdateMongoDBCollection,
|
||||||
|
getMongoDBCollection,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { userContext } from "../../UserContext";
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { createDatabase } from "./createDatabase";
|
import { client } from "../CosmosClient";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||||
|
import { createDatabase } from "./createDatabase";
|
||||||
|
|
||||||
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
||||||
const clearMessage = logConsoleProgress(
|
const clearMessage = logConsoleProgress(
|
||||||
@@ -46,7 +45,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
await createDatabase(createDatabaseParams);
|
await createDatabase(createDatabaseParams);
|
||||||
}
|
}
|
||||||
collection = await createCollectionWithARM(params);
|
collection = await createCollectionWithARM(params);
|
||||||
} else if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
} else if (userContext.apiType === "Mongo") {
|
||||||
collection = await createMongoCollectionWithProxy(params);
|
collection = await createMongoCollectionWithProxy(params);
|
||||||
} else {
|
} else {
|
||||||
collection = await createCollectionWithSDK(params);
|
collection = await createCollectionWithSDK(params);
|
||||||
@@ -63,17 +62,17 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return createSqlContainer(params);
|
return createSqlContainer(params);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return createMongoCollection(params);
|
return createMongoCollection(params);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return createCassandraTable(params);
|
return createCassandraTable(params);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return createGraph(params);
|
return createGraph(params);
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
return createTable(params);
|
return createTable(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,37 +1,36 @@
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DatabaseResponse } from "@azure/cosmos";
|
import { DatabaseResponse } from "@azure/cosmos";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { AuthType } from "../../AuthType";
|
||||||
import {
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
CassandraKeyspaceCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
GremlinDatabaseCreateUpdateParameters,
|
|
||||||
MongoDBDatabaseCreateUpdateParameters,
|
|
||||||
SqlDatabaseCreateUpdateParameters,
|
|
||||||
CreateUpdateOptions,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraKeyspace,
|
createUpdateCassandraKeyspace,
|
||||||
getCassandraKeyspace,
|
getCassandraKeyspace,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateMongoDBDatabase,
|
|
||||||
getMongoDBDatabase,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinDatabase,
|
createUpdateGremlinDatabase,
|
||||||
getGremlinDatabase,
|
getGremlinDatabase,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import {
|
||||||
|
createUpdateMongoDBDatabase,
|
||||||
|
getMongoDBDatabase,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import {
|
||||||
|
CassandraKeyspaceCreateUpdateParameters,
|
||||||
|
CreateUpdateOptions,
|
||||||
|
GremlinDatabaseCreateUpdateParameters,
|
||||||
|
MongoDBDatabaseCreateUpdateParameters,
|
||||||
|
SqlDatabaseCreateUpdateParameters,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
||||||
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
if (userContext.apiType === "Tables") {
|
||||||
throw new Error("Creating database resources is not allowed for tables accounts");
|
throw new Error("Creating database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
||||||
@@ -49,15 +48,15 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return createSqlDatabase(params);
|
return createSqlDatabase(params);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return createMongoDatabase(params);
|
return createMongoDatabase(params);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return createCassandraKeyspace(params);
|
return createCassandraKeyspace(params);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return createGremlineDatabase(params);
|
return createGremlineDatabase(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlStoredProcedureCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlStoredProcedureResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlStoredProcedure,
|
createUpdateSqlStoredProcedure,
|
||||||
getSqlStoredProcedure,
|
getSqlStoredProcedure,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlStoredProcedureCreateUpdateParameters,
|
||||||
|
SqlStoredProcedureResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function createStoredProcedure(
|
export async function createStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -21,11 +20,7 @@ export async function createStoredProcedure(
|
|||||||
): Promise<StoredProcedureDefinition & Resource> {
|
): Promise<StoredProcedureDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlStoredProcedure(
|
const getResponse = await getSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
SqlTriggerCreateUpdateParameters,
|
SqlTriggerCreateUpdateParameters,
|
||||||
SqlTriggerResource,
|
SqlTriggerResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function createTrigger(
|
export async function createTrigger(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -18,11 +17,7 @@ export async function createTrigger(
|
|||||||
): Promise<TriggerDefinition & Resource> {
|
): Promise<TriggerDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlTrigger(
|
const getResponse = await getSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlUserDefinedFunctionResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlUserDefinedFunction,
|
createUpdateSqlUserDefinedFunction,
|
||||||
getSqlUserDefinedFunction,
|
getSqlUserDefinedFunction,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||||
|
SqlUserDefinedFunctionResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function createUserDefinedFunction(
|
export async function createUserDefinedFunction(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -21,11 +20,7 @@ export async function createUserDefinedFunction(
|
|||||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlUserDefinedFunction(
|
const getResponse = await getSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { deleteCollection } from "./deleteCollection";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteCollection } from "./deleteCollection";
|
||||||
|
|
||||||
describe("deleteCollection", () => {
|
describe("deleteCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -15,7 +14,7 @@ describe("deleteCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
||||||
@@ -31,18 +30,18 @@ function deleteCollectionWithARM(databaseId: string, collectionId: string): Prom
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
return deleteTable(subscriptionId, resourceGroup, accountName, collectionId);
|
return deleteTable(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { deleteDatabase } from "./deleteDatabase";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteDatabase } from "./deleteDatabase";
|
||||||
|
|
||||||
describe("deleteDatabase", () => {
|
describe("deleteDatabase", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -15,7 +14,7 @@ describe("deleteDatabase", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteDatabase(databaseId: string): Promise<void> {
|
export async function deleteDatabase(databaseId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
if (userContext.apiType === "Tables") {
|
||||||
throw new Error("Deleting database resources is not allowed for tables accounts");
|
throw new Error("Deleting database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
@@ -34,16 +33,16 @@ function deleteDatabaseWithARM(databaseId: string): Promise<void> {
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteStoredProcedure(
|
export async function deleteStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -13,11 +12,7 @@ export async function deleteStoredProcedure(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
await deleteSqlStoredProcedure(
|
await deleteSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
await deleteSqlTrigger(
|
await deleteSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
await deleteSqlUserDefinedFunction(
|
await deleteSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollection } from "./readCollection";
|
import { readCollection } from "./readCollection";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("readCollection", () => {
|
describe("readCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -13,7 +12,7 @@ describe("readCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,12 +31,12 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
rpResponse = await getSqlContainerThroughput(
|
rpResponse = await getSqlContainerThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -50,7 +45,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await getMongoDBCollectionThroughput(
|
rpResponse = await getMongoDBCollectionThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -59,7 +54,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await getCassandraTableThroughput(
|
rpResponse = await getCassandraTableThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -68,7 +63,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await getGremlinGraphThroughput(
|
rpResponse = await getGremlinGraphThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -77,7 +72,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollections } from "./readCollections";
|
import { readCollections } from "./readCollections";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("readCollections", () => {
|
describe("readCollections", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,7 +13,7 @@ describe("readCollections", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
@@ -14,11 +13,7 @@ import { handleError } from "../ErrorHandlingUtils";
|
|||||||
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
return await readCollectionsWithARM(databaseId);
|
return await readCollectionsWithARM(databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,22 +32,22 @@ async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Co
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
||||||
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { userContext } from "../../UserContext";
|
||||||
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
return await readDatabaseOfferWithARM(params.databaseId);
|
return await readDatabaseOfferWithARM(params.databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,21 +30,21 @@ const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { updateUserContext } from "../../UserContext";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readDatabases } from "./readDatabases";
|
import { readDatabases } from "./readDatabases";
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
|
|
||||||
describe("readDatabases", () => {
|
describe("readDatabases", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,7 +13,7 @@ describe("readDatabases", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export async function readDatabases(): Promise<DataModels.Database[]> {
|
export async function readDatabases(): Promise<DataModels.Database[]> {
|
||||||
let databases: DataModels.Database[];
|
let databases: DataModels.Database[];
|
||||||
const clearMessage = logConsoleProgress(`Querying databases`);
|
const clearMessage = logConsoleProgress(`Querying databases`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
databases = await readDatabasesWithARM();
|
databases = await readDatabasesWithARM();
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client().databases.readAll().fetchAll();
|
const sdkResponse = await client().databases.readAll().fetchAll();
|
||||||
@@ -37,19 +32,19 @@ async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import { client } from "../CosmosClient";
|
import { AuthType } from "../../AuthType";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readStoredProcedures(
|
export async function readStoredProcedures(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -13,11 +12,7 @@ export async function readStoredProcedures(
|
|||||||
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const rpResponse = await listSqlStoredProcedures(
|
const rpResponse = await listSqlStoredProcedures(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
import { client } from "../CosmosClient";
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readTriggers(
|
export async function readTriggers(
|
||||||
@@ -13,11 +12,7 @@ export async function readTriggers(
|
|||||||
): Promise<(TriggerDefinition & Resource)[]> {
|
): Promise<(TriggerDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const rpResponse = await listSqlTriggers(
|
const rpResponse = await listSqlTriggers(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import { client } from "../CosmosClient";
|
import { AuthType } from "../../AuthType";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readUserDefinedFunctions(
|
export async function readUserDefinedFunctions(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -13,11 +12,7 @@ export async function readUserDefinedFunctions(
|
|||||||
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const rpResponse = await listSqlUserDefinedFunctions(
|
const rpResponse = await listSqlUserDefinedFunctions(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { ContainerDefinition } from "@azure/cosmos";
|
|||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { Collection } from "../../Contracts/DataModels";
|
import { Collection } from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
@@ -38,11 +37,7 @@ export async function updateCollection(
|
|||||||
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
|
||||||
) {
|
|
||||||
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client()
|
const sdkResponse = await client()
|
||||||
@@ -71,18 +66,18 @@ async function updateCollectionWithARM(
|
|||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = userContext.databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
const defaultExperience = userContext.defaultExperience;
|
const defaultExperience = userContext.apiType;
|
||||||
|
|
||||||
switch (defaultExperience) {
|
switch (defaultExperience) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return updateMongoDBCollection(
|
return updateMongoDBCollection(
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
|
|||||||
@@ -1,54 +1,53 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { HttpHeaders } from "../Constants";
|
|
||||||
import { Offer, SDKOfferDefinition, UpdateOfferParams } from "../../Contracts/DataModels";
|
|
||||||
import { OfferDefinition } from "@azure/cosmos";
|
import { OfferDefinition } from "@azure/cosmos";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { ThroughputSettingsUpdateParameters } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { AuthType } from "../../AuthType";
|
||||||
import { client } from "../CosmosClient";
|
import { Offer, SDKOfferDefinition, UpdateOfferParams } from "../../Contracts/DataModels";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { parseSDKOfferResponse } from "../OfferUtility";
|
|
||||||
import { readCollectionOffer } from "./readCollectionOffer";
|
|
||||||
import { readDatabaseOffer } from "./readDatabaseOffer";
|
|
||||||
import {
|
import {
|
||||||
updateSqlDatabaseThroughput,
|
|
||||||
migrateSqlDatabaseToAutoscale,
|
|
||||||
migrateSqlDatabaseToManualThroughput,
|
|
||||||
migrateSqlContainerToAutoscale,
|
|
||||||
migrateSqlContainerToManualThroughput,
|
|
||||||
updateSqlContainerThroughput,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
|
||||||
updateCassandraKeyspaceThroughput,
|
|
||||||
migrateCassandraKeyspaceToAutoscale,
|
migrateCassandraKeyspaceToAutoscale,
|
||||||
migrateCassandraKeyspaceToManualThroughput,
|
migrateCassandraKeyspaceToManualThroughput,
|
||||||
migrateCassandraTableToAutoscale,
|
migrateCassandraTableToAutoscale,
|
||||||
migrateCassandraTableToManualThroughput,
|
migrateCassandraTableToManualThroughput,
|
||||||
|
updateCassandraKeyspaceThroughput,
|
||||||
updateCassandraTableThroughput,
|
updateCassandraTableThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
import {
|
||||||
updateMongoDBDatabaseThroughput,
|
|
||||||
migrateMongoDBDatabaseToAutoscale,
|
|
||||||
migrateMongoDBDatabaseToManualThroughput,
|
|
||||||
migrateMongoDBCollectionToAutoscale,
|
|
||||||
migrateMongoDBCollectionToManualThroughput,
|
|
||||||
updateMongoDBCollectionThroughput,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
|
||||||
updateGremlinDatabaseThroughput,
|
|
||||||
migrateGremlinDatabaseToAutoscale,
|
migrateGremlinDatabaseToAutoscale,
|
||||||
migrateGremlinDatabaseToManualThroughput,
|
migrateGremlinDatabaseToManualThroughput,
|
||||||
migrateGremlinGraphToAutoscale,
|
migrateGremlinGraphToAutoscale,
|
||||||
migrateGremlinGraphToManualThroughput,
|
migrateGremlinGraphToManualThroughput,
|
||||||
|
updateGremlinDatabaseThroughput,
|
||||||
updateGremlinGraphThroughput,
|
updateGremlinGraphThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { userContext } from "../../UserContext";
|
import {
|
||||||
|
migrateMongoDBCollectionToAutoscale,
|
||||||
|
migrateMongoDBCollectionToManualThroughput,
|
||||||
|
migrateMongoDBDatabaseToAutoscale,
|
||||||
|
migrateMongoDBDatabaseToManualThroughput,
|
||||||
|
updateMongoDBCollectionThroughput,
|
||||||
|
updateMongoDBDatabaseThroughput,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import {
|
||||||
|
migrateSqlContainerToAutoscale,
|
||||||
|
migrateSqlContainerToManualThroughput,
|
||||||
|
migrateSqlDatabaseToAutoscale,
|
||||||
|
migrateSqlDatabaseToManualThroughput,
|
||||||
|
updateSqlContainerThroughput,
|
||||||
|
updateSqlDatabaseThroughput,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
migrateTableToAutoscale,
|
migrateTableToAutoscale,
|
||||||
migrateTableToManualThroughput,
|
migrateTableToManualThroughput,
|
||||||
updateTableThroughput,
|
updateTableThroughput,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
|
import { ThroughputSettingsUpdateParameters } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { HttpHeaders } from "../Constants";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { parseSDKOfferResponse } from "../OfferUtility";
|
||||||
|
import { readCollectionOffer } from "./readCollectionOffer";
|
||||||
|
import { readDatabaseOffer } from "./readDatabaseOffer";
|
||||||
|
|
||||||
export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> => {
|
export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
let updatedOffer: Offer;
|
let updatedOffer: Offer;
|
||||||
@@ -61,7 +60,7 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
|
|||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
if (params.collectionId) {
|
if (params.collectionId) {
|
||||||
updatedOffer = await updateCollectionOfferWithARM(params);
|
updatedOffer = await updateCollectionOfferWithARM(params);
|
||||||
} else if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
} else if (userContext.apiType === "Tables") {
|
||||||
// update table's database offer with SDK since RP doesn't support it
|
// update table's database offer with SDK since RP doesn't support it
|
||||||
updatedOffer = await updateOfferWithSDK(params);
|
updatedOffer = await updateOfferWithSDK(params);
|
||||||
} else {
|
} else {
|
||||||
@@ -82,24 +81,24 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
|
|||||||
|
|
||||||
const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
try {
|
try {
|
||||||
switch (userContext.defaultExperience) {
|
switch (userContext.apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
await updateSqlContainerOffer(params);
|
await updateSqlContainerOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
await updateMongoCollectionOffer(params);
|
await updateMongoCollectionOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
await updateCassandraTableOffer(params);
|
await updateCassandraTableOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
await updateGremlinGraphOffer(params);
|
await updateGremlinGraphOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Table:
|
case "Tables":
|
||||||
await updateTableOffer(params);
|
await updateTableOffer(params);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${userContext.defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${userContext.apiType}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "MethodNotAllowed") {
|
if (error.code !== "MethodNotAllowed") {
|
||||||
@@ -116,21 +115,21 @@ const updateCollectionOfferWithARM = async (params: UpdateOfferParams): Promise<
|
|||||||
|
|
||||||
const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
const updateDatabaseOfferWithARM = async (params: UpdateOfferParams): Promise<Offer> => {
|
||||||
try {
|
try {
|
||||||
switch (userContext.defaultExperience) {
|
switch (userContext.apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
await updateSqlDatabaseOffer(params);
|
await updateSqlDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
await updateMongoDatabaseOffer(params);
|
await updateMongoDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
await updateCassandraKeyspaceOffer(params);
|
await updateCassandraKeyspaceOffer(params);
|
||||||
break;
|
break;
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
await updateGremlinDatabaseOffer(params);
|
await updateGremlinDatabaseOffer(params);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${userContext.defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${userContext.apiType}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "MethodNotAllowed") {
|
if (error.code !== "MethodNotAllowed") {
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlStoredProcedureCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlStoredProcedureResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlStoredProcedure,
|
createUpdateSqlStoredProcedure,
|
||||||
getSqlStoredProcedure,
|
getSqlStoredProcedure,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlStoredProcedureCreateUpdateParameters,
|
||||||
|
SqlStoredProcedureResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function updateStoredProcedure(
|
export async function updateStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -21,11 +20,7 @@ export async function updateStoredProcedure(
|
|||||||
): Promise<StoredProcedureDefinition & Resource> {
|
): Promise<StoredProcedureDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
|
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const getResponse = await getSqlStoredProcedure(
|
const getResponse = await getSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
|
import { TriggerDefinition } from "@azure/cosmos";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
SqlTriggerCreateUpdateParameters,
|
SqlTriggerCreateUpdateParameters,
|
||||||
SqlTriggerResource,
|
SqlTriggerResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { TriggerDefinition } from "@azure/cosmos";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function updateTrigger(
|
export async function updateTrigger(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -18,11 +17,7 @@ export async function updateTrigger(
|
|||||||
): Promise<TriggerDefinition> {
|
): Promise<TriggerDefinition> {
|
||||||
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const getResponse = await getSqlTrigger(
|
const getResponse = await getSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import {
|
import { AuthType } from "../../AuthType";
|
||||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
import { userContext } from "../../UserContext";
|
||||||
SqlUserDefinedFunctionResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import {
|
import {
|
||||||
createUpdateSqlUserDefinedFunction,
|
createUpdateSqlUserDefinedFunction,
|
||||||
getSqlUserDefinedFunction,
|
getSqlUserDefinedFunction,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||||
|
SqlUserDefinedFunctionResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function updateUserDefinedFunction(
|
export async function updateUserDefinedFunction(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -21,11 +20,7 @@ export async function updateUserDefinedFunction(
|
|||||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
|
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
|
||||||
try {
|
try {
|
||||||
if (
|
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||||
userContext.authType === AuthType.AAD &&
|
|
||||||
!userContext.useSDKOperations &&
|
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
|
||||||
) {
|
|
||||||
const getResponse = await getSqlUserDefinedFunction(
|
const getResponse = await getSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
export enum DefaultAccountExperienceType {
|
|
||||||
DocumentDB = "DocumentDB",
|
|
||||||
Graph = "Graph",
|
|
||||||
MongoDB = "MongoDB",
|
|
||||||
Table = "Table",
|
|
||||||
Cassandra = "Cassandra",
|
|
||||||
ApiForMongoDB = "Azure Cosmos DB for MongoDB API",
|
|
||||||
}
|
|
||||||
@@ -20,51 +20,6 @@ describe("Component Registerer", () => {
|
|||||||
expect(ko.components.isRegistered("json-editor")).toBe(true);
|
expect(ko.components.isRegistered("json-editor")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should register documents-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("documents-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register stored-procedure-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("stored-procedure-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register trigger-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("trigger-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register user-defined-function-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("user-defined-function-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register settings-tab-v2 component", () => {
|
|
||||||
expect(ko.components.isRegistered("database-settings-tab-v2")).toBe(true);
|
|
||||||
expect(ko.components.isRegistered("collection-settings-tab-v2")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register query-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("query-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register tables-query-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("tables-query-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register graph-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("graph-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register notebookv2-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("notebookv2-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register terminal-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("terminal-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register mongo-shell-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("mongo-shell-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should registeradd-collection-pane component", () => {
|
it("should registeradd-collection-pane component", () => {
|
||||||
expect(ko.components.isRegistered("add-collection-pane")).toBe(true);
|
expect(ko.components.isRegistered("add-collection-pane")).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -73,10 +28,6 @@ describe("Component Registerer", () => {
|
|||||||
expect(ko.components.isRegistered("graph-styling-pane")).toBe(true);
|
expect(ko.components.isRegistered("graph-styling-pane")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should register string-input-pane component", () => {
|
|
||||||
expect(ko.components.isRegistered("string-input-pane")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register dynamic-list component", () => {
|
it("should register dynamic-list component", () => {
|
||||||
expect(ko.components.isRegistered("dynamic-list")).toBe(true);
|
expect(ko.components.isRegistered("dynamic-list")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,21 +8,6 @@ import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent";
|
|||||||
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
|
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
|
||||||
import { GraphStyleComponent } from "./Graph/GraphStyleComponent/GraphStyleComponent";
|
import { GraphStyleComponent } from "./Graph/GraphStyleComponent/GraphStyleComponent";
|
||||||
import * as PaneComponents from "./Panes/PaneComponents";
|
import * as PaneComponents from "./Panes/PaneComponents";
|
||||||
import ConflictsTab from "./Tabs/ConflictsTab";
|
|
||||||
import DocumentsTab from "./Tabs/DocumentsTab";
|
|
||||||
import GalleryTab from "./Tabs/GalleryTab";
|
|
||||||
import GraphTab from "./Tabs/GraphTab";
|
|
||||||
import MongoShellTab from "./Tabs/MongoShellTab";
|
|
||||||
import NotebookTabV2 from "./Tabs/NotebookV2Tab";
|
|
||||||
import NotebookViewerTab from "./Tabs/NotebookViewerTab";
|
|
||||||
import QueryTab from "./Tabs/QueryTab";
|
|
||||||
import QueryTablesTab from "./Tabs/QueryTablesTab";
|
|
||||||
import SchemaAnalyzerTab from "./Tabs/SchemaAnalyzerTab";
|
|
||||||
import { DatabaseSettingsTabV2, SettingsTabV2 } from "./Tabs/SettingsTabV2";
|
|
||||||
import StoredProcedureTab from "./Tabs/StoredProcedureTab";
|
|
||||||
import TerminalTab from "./Tabs/TerminalTab";
|
|
||||||
import TriggerTab from "./Tabs/TriggerTab";
|
|
||||||
import UserDefinedFunctionTab from "./Tabs/UserDefinedFunctionTab";
|
|
||||||
|
|
||||||
ko.components.register("input-typeahead", new InputTypeaheadComponent());
|
ko.components.register("input-typeahead", new InputTypeaheadComponent());
|
||||||
ko.components.register("error-display", new ErrorDisplayComponent());
|
ko.components.register("error-display", new ErrorDisplayComponent());
|
||||||
@@ -33,26 +18,6 @@ ko.components.register("diff-editor", new DiffEditorComponent());
|
|||||||
ko.components.register("dynamic-list", DynamicListComponent);
|
ko.components.register("dynamic-list", DynamicListComponent);
|
||||||
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);
|
ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponentAutoPilotV3);
|
||||||
|
|
||||||
// Collection Tabs
|
|
||||||
[
|
|
||||||
DocumentsTab,
|
|
||||||
StoredProcedureTab,
|
|
||||||
TriggerTab,
|
|
||||||
UserDefinedFunctionTab,
|
|
||||||
SettingsTabV2,
|
|
||||||
QueryTab,
|
|
||||||
QueryTablesTab,
|
|
||||||
GraphTab,
|
|
||||||
MongoShellTab,
|
|
||||||
ConflictsTab,
|
|
||||||
NotebookTabV2,
|
|
||||||
TerminalTab,
|
|
||||||
GalleryTab,
|
|
||||||
NotebookViewerTab,
|
|
||||||
DatabaseSettingsTabV2,
|
|
||||||
SchemaAnalyzerTab,
|
|
||||||
].forEach(({ component: { name, template } }) => ko.components.register(name, { template }));
|
|
||||||
|
|
||||||
// Panes
|
// Panes
|
||||||
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
|
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
|
||||||
ko.components.register("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
|
ko.components.register("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
|
||||||
@@ -60,5 +25,4 @@ ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPane
|
|||||||
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
||||||
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
||||||
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
||||||
ko.components.register("string-input-pane", new PaneComponents.StringInputPaneComponent());
|
|
||||||
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());
|
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import DeleteTriggerIcon from "../../images/DeleteTrigger.svg";
|
|||||||
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
|
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
|
||||||
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
|
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
|
||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
|
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
|
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
|
||||||
import Explorer from "./Explorer";
|
import Explorer from "./Explorer";
|
||||||
@@ -30,16 +29,16 @@ export interface DatabaseContextMenuButtonParams {
|
|||||||
* New resource tree (in ReactJS)
|
* New resource tree (in ReactJS)
|
||||||
*/
|
*/
|
||||||
export class ResourceTreeContextMenuButtonFactory {
|
export class ResourceTreeContextMenuButtonFactory {
|
||||||
public static createDatabaseContextMenu(container: Explorer): TreeNodeMenuItem[] {
|
public static createDatabaseContextMenu(container: Explorer, databaseId: string): TreeNodeMenuItem[] {
|
||||||
const items: TreeNodeMenuItem[] = [
|
const items: TreeNodeMenuItem[] = [
|
||||||
{
|
{
|
||||||
iconSrc: AddCollectionIcon,
|
iconSrc: AddCollectionIcon,
|
||||||
onClick: () => container.onNewCollectionClicked(),
|
onClick: () => container.onNewCollectionClicked(databaseId),
|
||||||
label: container.addCollectionText(),
|
label: container.addCollectionText(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (userContext.defaultExperience !== DefaultAccountExperienceType.Table) {
|
if (userContext.apiType !== "Tables") {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: DeleteDatabaseIcon,
|
iconSrc: DeleteDatabaseIcon,
|
||||||
onClick: () => container.openDeleteDatabaseConfirmationPane(),
|
onClick: () => container.openDeleteDatabaseConfirmationPane(),
|
||||||
@@ -63,7 +62,7 @@ export class ResourceTreeContextMenuButtonFactory {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null),
|
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { accordionStackTokens } from "../Settings/SettingsRenderUtils";
|
|||||||
export interface CollapsibleSectionProps {
|
export interface CollapsibleSectionProps {
|
||||||
title: string;
|
title: string;
|
||||||
isExpandedByDefault: boolean;
|
isExpandedByDefault: boolean;
|
||||||
|
onExpand?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CollapsibleSectionState {
|
export interface CollapsibleSectionState {
|
||||||
@@ -23,6 +24,12 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
|
|||||||
this.setState({ isExpanded: !this.state.isExpanded });
|
this.setState({ isExpanded: !this.state.isExpanded });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public componentDidUpdate(): void {
|
||||||
|
if (this.state.isExpanded && this.props.onExpand) {
|
||||||
|
this.props.onExpand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
import template from "./diff-editor-component.html";
|
import template from "./diff-editor-component.html";
|
||||||
import * as monaco from "monaco-editor";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for ko component registration
|
* Helper class for ko component registration
|
||||||
@@ -92,7 +92,7 @@ export class DiffEditorViewModel {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor on diff mode and attach to DOM
|
* Create the monaco editor on diff mode and attach to DOM
|
||||||
*/
|
*/
|
||||||
protected createDiffEditor(
|
protected async createDiffEditor(
|
||||||
originalContent: string,
|
originalContent: string,
|
||||||
modifiedContent: string,
|
modifiedContent: string,
|
||||||
createCallback: (e: monaco.editor.IStandaloneDiffEditor) => void
|
createCallback: (e: monaco.editor.IStandaloneDiffEditor) => void
|
||||||
@@ -111,7 +111,7 @@ export class DiffEditorViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const language = this.params.editorLanguage || "json";
|
const language = this.params.editorLanguage || "json";
|
||||||
|
const monaco = await loadMonaco();
|
||||||
const originalModel = monaco.editor.createModel(originalContent, language);
|
const originalModel = monaco.editor.createModel(originalContent, language);
|
||||||
const modifiedModel = monaco.editor.createModel(modifiedContent, language);
|
const modifiedModel = monaco.editor.createModel(modifiedContent, language);
|
||||||
const diffEditor: monaco.editor.IStandaloneDiffEditor = monaco.editor.createDiffEditor(
|
const diffEditor: monaco.editor.IStandaloneDiffEditor = monaco.editor.createDiffEditor(
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
import { JsonEditorParams, JsonEditorViewModel } from "../JsonEditor/JsonEditorComponent";
|
import { JsonEditorParams, JsonEditorViewModel } from "../JsonEditor/JsonEditorComponent";
|
||||||
import template from "./editor-component.html";
|
import template from "./editor-component.html";
|
||||||
import * as monaco from "monaco-editor";
|
|
||||||
import { SqlCompletionItemProvider, ErrorMarkProvider } from "@azure/cosmos-language-service";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for ko component registration
|
* Helper class for ko component registration
|
||||||
@@ -49,15 +48,17 @@ class EditorViewModel extends JsonEditorViewModel {
|
|||||||
return this.params.contentType;
|
return this.params.contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected registerCompletionItemProvider() {
|
protected async registerCompletionItemProvider() {
|
||||||
let sqlCompletionItemProvider = new SqlCompletionItemProvider();
|
|
||||||
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
||||||
monaco.languages.registerCompletionItemProvider("sql", sqlCompletionItemProvider);
|
const { SqlCompletionItemProvider } = await import("@azure/cosmos-language-service");
|
||||||
|
const monaco = await loadMonaco();
|
||||||
|
monaco.languages.registerCompletionItemProvider("sql", new SqlCompletionItemProvider());
|
||||||
EditorViewModel.providerRegistered.push("sql");
|
EditorViewModel.providerRegistered.push("sql");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getErrorMarkers(input: string): Q.Promise<monaco.editor.IMarkerData[]> {
|
protected async getErrorMarkers(input: string): Promise<monaco.editor.IMarkerData[]> {
|
||||||
|
const { ErrorMarkProvider } = await import("@azure/cosmos-language-service");
|
||||||
return ErrorMarkProvider.getErrorMark(input);
|
return ErrorMarkProvider.getErrorMark(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as monaco from "monaco-editor";
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
|
|
||||||
export interface EditorReactProps {
|
export interface EditorReactProps {
|
||||||
language: string;
|
language: string;
|
||||||
@@ -61,7 +61,7 @@ export class EditorReact extends React.Component<EditorReactProps> {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor and attach to DOM
|
* Create the monaco editor and attach to DOM
|
||||||
*/
|
*/
|
||||||
private createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
private async createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
||||||
const options: monaco.editor.IEditorConstructionOptions = {
|
const options: monaco.editor.IEditorConstructionOptions = {
|
||||||
value: this.props.content,
|
value: this.props.content,
|
||||||
language: this.props.language,
|
language: this.props.language,
|
||||||
@@ -74,6 +74,7 @@ export class EditorReact extends React.Component<EditorReactProps> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.rootNode.innerHTML = "";
|
this.rootNode.innerHTML = "";
|
||||||
|
const monaco = await loadMonaco();
|
||||||
createCallback(monaco.editor.create(this.rootNode, options));
|
createCallback(monaco.editor.create(this.rootNode, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,21 +128,21 @@ class InputTypeaheadViewModel {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
callback: {
|
callback: {
|
||||||
onClick: (node: any, a: any, item: OnClickItem, event: any) => {
|
onClick: (_node: unknown, _a: unknown, item: OnClickItem) => {
|
||||||
cache.selection = item;
|
cache.selection = item;
|
||||||
|
|
||||||
if (params.selection) {
|
if (params.selection) {
|
||||||
params.selection(item);
|
params.selection(item);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onResult(node: any, query: any, result: any, resultCount: any, resultCountPerGroup: any) {
|
onResult(_node: unknown, query: any) {
|
||||||
cache.inputValue = query;
|
cache.inputValue = query;
|
||||||
if (params.inputValue) {
|
if (params.inputValue) {
|
||||||
params.inputValue(query);
|
params.inputValue(query);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
template: (query: string, item: any) => {
|
template: (_query: string, item: any) => {
|
||||||
// Don't display id if caption *IS* the id
|
// Don't display id if caption *IS* the id
|
||||||
return item.caption === item.value
|
return item.caption === item.value
|
||||||
? "<span>{{caption}}</span>"
|
? "<span>{{caption}}</span>"
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import Q from "q";
|
|
||||||
import * as monaco from "monaco-editor";
|
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import { loadMonaco, monaco } from "../../LazyMonaco";
|
||||||
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
|
import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel";
|
||||||
import template from "./json-editor-component.html";
|
import template from "./json-editor-component.html";
|
||||||
|
|
||||||
@@ -88,7 +87,7 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
/**
|
/**
|
||||||
* Create the monaco editor and attach to DOM
|
* Create the monaco editor and attach to DOM
|
||||||
*/
|
*/
|
||||||
protected createEditor(content: string, createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
protected async createEditor(content: string, createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
||||||
this.registerCompletionItemProvider();
|
this.registerCompletionItemProvider();
|
||||||
this.editorContainer = document.getElementById(this.getEditorId());
|
this.editorContainer = document.getElementById(this.getEditorId());
|
||||||
const options: monaco.editor.IEditorConstructionOptions = {
|
const options: monaco.editor.IEditorConstructionOptions = {
|
||||||
@@ -102,6 +101,7 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.editorContainer.innerHTML = "";
|
this.editorContainer.innerHTML = "";
|
||||||
|
const monaco = await loadMonaco();
|
||||||
createCallback(monaco.editor.create(this.editorContainer, options));
|
createCallback(monaco.editor.create(this.editorContainer, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,15 +109,16 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel {
|
|||||||
protected registerCompletionItemProvider() {}
|
protected registerCompletionItemProvider() {}
|
||||||
|
|
||||||
// Interface. Will be implemented in children editor view model such as EditorViewModel.
|
// Interface. Will be implemented in children editor view model such as EditorViewModel.
|
||||||
protected getErrorMarkers(input: string): Q.Promise<monaco.editor.IMarkerData[]> {
|
protected async getErrorMarkers(_: string): Promise<monaco.editor.IMarkerData[]> {
|
||||||
return Q.Promise(() => {});
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getEditorLanguage(): string {
|
protected getEditorLanguage(): string {
|
||||||
return "json";
|
return "json";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected configureEditor(editor: monaco.editor.IStandaloneCodeEditor) {
|
protected async configureEditor(editor: monaco.editor.IStandaloneCodeEditor) {
|
||||||
|
const monaco = await loadMonaco();
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
const queryEditorModel = this.editor.getModel();
|
const queryEditorModel = this.editor.getModel();
|
||||||
if (!this.params.isReadOnly && this.params.updatedContent) {
|
if (!this.params.isReadOnly && this.params.updatedContent) {
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { Card } from "@uifabric/react-cards";
|
import { Card } from "@uifabric/react-cards";
|
||||||
import {
|
import {
|
||||||
|
BaseButton,
|
||||||
|
Button,
|
||||||
FontWeights,
|
FontWeights,
|
||||||
Icon,
|
Icon,
|
||||||
IconButton,
|
IconButton,
|
||||||
Image,
|
Image,
|
||||||
ImageFit,
|
ImageFit,
|
||||||
Persona,
|
|
||||||
Text,
|
|
||||||
Link,
|
Link,
|
||||||
BaseButton,
|
|
||||||
Button,
|
|
||||||
LinkBase,
|
LinkBase,
|
||||||
|
Persona,
|
||||||
Separator,
|
Separator,
|
||||||
TooltipHost,
|
|
||||||
Spinner,
|
Spinner,
|
||||||
SpinnerSize,
|
SpinnerSize,
|
||||||
|
Text,
|
||||||
|
TooltipHost,
|
||||||
} from "office-ui-fabric-react";
|
} from "office-ui-fabric-react";
|
||||||
import * as React from "react";
|
import React, { FunctionComponent, useState } from "react";
|
||||||
|
import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg";
|
||||||
import { IGalleryItem } from "../../../../Juno/JunoClient";
|
import { IGalleryItem } from "../../../../Juno/JunoClient";
|
||||||
import * as FileSystemUtil from "../../../Notebook/FileSystemUtil";
|
import * as FileSystemUtil from "../../../Notebook/FileSystemUtil";
|
||||||
import CosmosDBLogo from "../../../../../images/CosmosDB-logo.svg";
|
|
||||||
|
|
||||||
export interface GalleryCardComponentProps {
|
export interface GalleryCardComponentProps {
|
||||||
data: IGalleryItem;
|
data: IGalleryItem;
|
||||||
@@ -34,166 +34,48 @@ export interface GalleryCardComponentProps {
|
|||||||
onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) => void;
|
onDeleteClick: (beforeDelete: () => void, afterDelete: () => void) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GalleryCardComponentState {
|
export const GalleryCardComponent: FunctionComponent<GalleryCardComponentProps> = ({
|
||||||
isDeletingPublishedNotebook: boolean;
|
data,
|
||||||
}
|
isFavorite,
|
||||||
|
showDownload,
|
||||||
|
showDelete,
|
||||||
|
onClick,
|
||||||
|
onTagClick,
|
||||||
|
onFavoriteClick,
|
||||||
|
onUnfavoriteClick,
|
||||||
|
onDownloadClick,
|
||||||
|
onDeleteClick,
|
||||||
|
}: GalleryCardComponentProps) => {
|
||||||
|
const CARD_WIDTH = 256;
|
||||||
|
const cardImageHeight = 144;
|
||||||
|
const cardDescriptionMaxChars = 80;
|
||||||
|
const cardItemGapBig = 10;
|
||||||
|
const cardItemGapSmall = 8;
|
||||||
|
const cardDeleteSpinnerHeight = 360;
|
||||||
|
const smallTextLineHeight = 18;
|
||||||
|
|
||||||
export class GalleryCardComponent extends React.Component<GalleryCardComponentProps, GalleryCardComponentState> {
|
const [isDeletingPublishedNotebook, setIsDeletingPublishedNotebook] = useState<boolean>(false);
|
||||||
public static readonly CARD_WIDTH = 256;
|
|
||||||
private static readonly cardImageHeight = 144;
|
|
||||||
public static readonly cardHeightToWidthRatio =
|
|
||||||
GalleryCardComponent.cardImageHeight / GalleryCardComponent.CARD_WIDTH;
|
|
||||||
private static readonly cardDescriptionMaxChars = 80;
|
|
||||||
private static readonly cardItemGapBig = 10;
|
|
||||||
private static readonly cardItemGapSmall = 8;
|
|
||||||
private static readonly cardDeleteSpinnerHeight = 360;
|
|
||||||
private static readonly smallTextLineHeight = 18;
|
|
||||||
|
|
||||||
constructor(props: GalleryCardComponentProps) {
|
const cardButtonsVisible = isFavorite !== undefined || showDownload || showDelete;
|
||||||
super(props);
|
const options: Intl.DateTimeFormatOptions = {
|
||||||
this.state = {
|
year: "numeric",
|
||||||
isDeletingPublishedNotebook: false,
|
month: "short",
|
||||||
};
|
day: "numeric",
|
||||||
}
|
};
|
||||||
|
const dateString = new Date(data.created).toLocaleString("default", options);
|
||||||
|
const cardTitle = FileSystemUtil.stripExtension(data.name, "ipynb");
|
||||||
|
|
||||||
public render(): JSX.Element {
|
const renderTruncatedDescription = (): string => {
|
||||||
const cardButtonsVisible = this.props.isFavorite !== undefined || this.props.showDownload || this.props.showDelete;
|
let truncatedDescription = data.description.substr(0, cardDescriptionMaxChars);
|
||||||
const options: Intl.DateTimeFormatOptions = {
|
if (data.description.length > cardDescriptionMaxChars) {
|
||||||
year: "numeric",
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
};
|
|
||||||
const dateString = new Date(this.props.data.created).toLocaleString("default", options);
|
|
||||||
const cardTitle = FileSystemUtil.stripExtension(this.props.data.name, "ipynb");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
style={{ background: "white" }}
|
|
||||||
aria-label={cardTitle}
|
|
||||||
data-is-focusable="true"
|
|
||||||
tokens={{ width: GalleryCardComponent.CARD_WIDTH, childrenGap: 0 }}
|
|
||||||
onClick={(event) => this.onClick(event, this.props.onClick)}
|
|
||||||
>
|
|
||||||
{this.state.isDeletingPublishedNotebook && (
|
|
||||||
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
|
|
||||||
<Spinner
|
|
||||||
size={SpinnerSize.large}
|
|
||||||
label={`Deleting '${cardTitle}'`}
|
|
||||||
styles={{ root: { height: GalleryCardComponent.cardDeleteSpinnerHeight } }}
|
|
||||||
/>
|
|
||||||
</Card.Item>
|
|
||||||
)}
|
|
||||||
{!this.state.isDeletingPublishedNotebook && (
|
|
||||||
<>
|
|
||||||
<Card.Item tokens={{ padding: GalleryCardComponent.cardItemGapBig }}>
|
|
||||||
<Persona
|
|
||||||
imageUrl={this.props.data.isSample && CosmosDBLogo}
|
|
||||||
text={this.props.data.author}
|
|
||||||
secondaryText={dateString}
|
|
||||||
/>
|
|
||||||
</Card.Item>
|
|
||||||
|
|
||||||
<Card.Item>
|
|
||||||
<Image
|
|
||||||
src={this.props.data.thumbnailUrl}
|
|
||||||
width={GalleryCardComponent.CARD_WIDTH}
|
|
||||||
height={GalleryCardComponent.cardImageHeight}
|
|
||||||
imageFit={ImageFit.cover}
|
|
||||||
alt={`${cardTitle} cover image`}
|
|
||||||
/>
|
|
||||||
</Card.Item>
|
|
||||||
|
|
||||||
<Card.Section styles={{ root: { padding: GalleryCardComponent.cardItemGapBig } }}>
|
|
||||||
<Text variant="small" nowrap styles={{ root: { height: GalleryCardComponent.smallTextLineHeight } }}>
|
|
||||||
{this.props.data.tags ? (
|
|
||||||
this.props.data.tags.map((tag, index, array) => (
|
|
||||||
<span key={tag}>
|
|
||||||
<Link onClick={(event) => this.onClick(event, () => this.props.onTagClick(tag))}>{tag}</Link>
|
|
||||||
{index === array.length - 1 ? <></> : ", "}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<br />
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text
|
|
||||||
styles={{
|
|
||||||
root: {
|
|
||||||
fontWeight: FontWeights.semibold,
|
|
||||||
paddingTop: GalleryCardComponent.cardItemGapSmall,
|
|
||||||
paddingBottom: GalleryCardComponent.cardItemGapSmall,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
nowrap
|
|
||||||
>
|
|
||||||
{cardTitle}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text variant="small" styles={{ root: { height: GalleryCardComponent.smallTextLineHeight * 2 } }}>
|
|
||||||
{this.renderTruncatedDescription()}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{this.props.data.views !== undefined &&
|
|
||||||
this.generateIconText("RedEye", this.props.data.views.toString())}
|
|
||||||
{this.props.data.downloads !== undefined &&
|
|
||||||
this.generateIconText("Download", this.props.data.downloads.toString())}
|
|
||||||
{this.props.data.favorites !== undefined &&
|
|
||||||
this.generateIconText("Heart", this.props.data.favorites.toString())}
|
|
||||||
</span>
|
|
||||||
</Card.Section>
|
|
||||||
|
|
||||||
{cardButtonsVisible && (
|
|
||||||
<Card.Section
|
|
||||||
styles={{
|
|
||||||
root: {
|
|
||||||
marginLeft: GalleryCardComponent.cardItemGapBig,
|
|
||||||
marginRight: GalleryCardComponent.cardItemGapBig,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Separator styles={{ root: { padding: 0, height: 1 } }} />
|
|
||||||
|
|
||||||
<span>
|
|
||||||
{this.props.isFavorite !== undefined &&
|
|
||||||
this.generateIconButtonWithTooltip(
|
|
||||||
this.props.isFavorite ? "HeartFill" : "Heart",
|
|
||||||
this.props.isFavorite ? "Unfavorite" : "Favorite",
|
|
||||||
"left",
|
|
||||||
this.props.isFavorite ? this.props.onUnfavoriteClick : this.props.onFavoriteClick
|
|
||||||
)}
|
|
||||||
|
|
||||||
{this.props.showDownload &&
|
|
||||||
this.generateIconButtonWithTooltip("Download", "Download", "left", this.props.onDownloadClick)}
|
|
||||||
|
|
||||||
{this.props.showDelete &&
|
|
||||||
this.generateIconButtonWithTooltip("Delete", "Remove", "right", () =>
|
|
||||||
this.props.onDeleteClick(
|
|
||||||
() => this.setState({ isDeletingPublishedNotebook: true }),
|
|
||||||
() => this.setState({ isDeletingPublishedNotebook: false })
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Card.Section>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderTruncatedDescription = (): string => {
|
|
||||||
let truncatedDescription = this.props.data.description.substr(0, GalleryCardComponent.cardDescriptionMaxChars);
|
|
||||||
if (this.props.data.description.length > GalleryCardComponent.cardDescriptionMaxChars) {
|
|
||||||
truncatedDescription = `${truncatedDescription} ...`;
|
truncatedDescription = `${truncatedDescription} ...`;
|
||||||
}
|
}
|
||||||
return truncatedDescription;
|
return truncatedDescription;
|
||||||
};
|
};
|
||||||
|
|
||||||
private generateIconText = (iconName: string, text: string): JSX.Element => {
|
const generateIconText = (iconName: string, text: string): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Text variant="tiny" styles={{ root: { color: "#605E5C", paddingRight: GalleryCardComponent.cardItemGapSmall } }}>
|
<Text variant="tiny" styles={{ root: { color: "#605E5C", paddingRight: cardItemGapSmall } }}>
|
||||||
<Icon iconName={iconName} styles={{ root: { verticalAlign: "middle" } }} /> {text}
|
<Icon iconName={iconName} styles={{ root: { verticalAlign: "middle" } }} /> {text}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -203,7 +85,7 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
|
|||||||
* Fluent UI doesn't support tooltips on IconButtons out of the box. In the meantime the recommendation is
|
* Fluent UI doesn't support tooltips on IconButtons out of the box. In the meantime the recommendation is
|
||||||
* to do the following (from https://developer.microsoft.com/en-us/fluentui#/controls/web/button)
|
* to do the following (from https://developer.microsoft.com/en-us/fluentui#/controls/web/button)
|
||||||
*/
|
*/
|
||||||
private generateIconButtonWithTooltip = (
|
const generateIconButtonWithTooltip = (
|
||||||
iconName: string,
|
iconName: string,
|
||||||
title: string,
|
title: string,
|
||||||
horizontalAlign: "right" | "left",
|
horizontalAlign: "right" | "left",
|
||||||
@@ -220,13 +102,13 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
|
|||||||
iconProps={{ iconName }}
|
iconProps={{ iconName }}
|
||||||
title={title}
|
title={title}
|
||||||
ariaLabel={title}
|
ariaLabel={title}
|
||||||
onClick={(event) => this.onClick(event, activate)}
|
onClick={(event) => handlerOnClick(event, activate)}
|
||||||
/>
|
/>
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onClick = (
|
const handlerOnClick = (
|
||||||
event:
|
event:
|
||||||
| React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | LinkBase, MouseEvent>
|
| React.MouseEvent<HTMLElement | HTMLAnchorElement | HTMLButtonElement | LinkBase, MouseEvent>
|
||||||
| React.MouseEvent<
|
| React.MouseEvent<
|
||||||
@@ -239,4 +121,112 @@ export class GalleryCardComponent extends React.Component<GalleryCardComponentPr
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
activate();
|
activate();
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
style={{ background: "white" }}
|
||||||
|
aria-label={cardTitle}
|
||||||
|
data-is-focusable="true"
|
||||||
|
tokens={{ width: CARD_WIDTH, childrenGap: 0 }}
|
||||||
|
onClick={(event) => handlerOnClick(event, onClick)}
|
||||||
|
>
|
||||||
|
{isDeletingPublishedNotebook && (
|
||||||
|
<Card.Item tokens={{ padding: cardItemGapBig }}>
|
||||||
|
<Spinner
|
||||||
|
size={SpinnerSize.large}
|
||||||
|
label={`Deleting '${cardTitle}'`}
|
||||||
|
styles={{ root: { height: cardDeleteSpinnerHeight } }}
|
||||||
|
/>
|
||||||
|
</Card.Item>
|
||||||
|
)}
|
||||||
|
{!isDeletingPublishedNotebook && (
|
||||||
|
<>
|
||||||
|
<Card.Item tokens={{ padding: cardItemGapBig }}>
|
||||||
|
<Persona imageUrl={data.isSample && CosmosDBLogo} text={data.author} secondaryText={dateString} />
|
||||||
|
</Card.Item>
|
||||||
|
|
||||||
|
<Card.Item>
|
||||||
|
<Image
|
||||||
|
src={data.thumbnailUrl}
|
||||||
|
width={CARD_WIDTH}
|
||||||
|
height={cardImageHeight}
|
||||||
|
imageFit={ImageFit.cover}
|
||||||
|
alt={`${cardTitle} cover image`}
|
||||||
|
/>
|
||||||
|
</Card.Item>
|
||||||
|
|
||||||
|
<Card.Section styles={{ root: { padding: cardItemGapBig } }}>
|
||||||
|
<Text variant="small" nowrap styles={{ root: { height: smallTextLineHeight } }}>
|
||||||
|
{data.tags ? (
|
||||||
|
data.tags.map((tag, index, array) => (
|
||||||
|
<span key={tag}>
|
||||||
|
<Link onClick={(event) => handlerOnClick(event, () => onTagClick(tag))}>{tag}</Link>
|
||||||
|
{index === array.length - 1 ? <></> : ", "}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<br />
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text
|
||||||
|
styles={{
|
||||||
|
root: {
|
||||||
|
fontWeight: FontWeights.semibold,
|
||||||
|
paddingTop: cardItemGapSmall,
|
||||||
|
paddingBottom: cardItemGapSmall,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
nowrap
|
||||||
|
>
|
||||||
|
{cardTitle}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text variant="small" styles={{ root: { height: smallTextLineHeight * 2 } }}>
|
||||||
|
{renderTruncatedDescription()}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{data.views !== undefined && generateIconText("RedEye", data.views.toString())}
|
||||||
|
{data.downloads !== undefined && generateIconText("Download", data.downloads.toString())}
|
||||||
|
{data.favorites !== undefined && generateIconText("Heart", data.favorites.toString())}
|
||||||
|
</span>
|
||||||
|
</Card.Section>
|
||||||
|
|
||||||
|
{cardButtonsVisible && (
|
||||||
|
<Card.Section
|
||||||
|
styles={{
|
||||||
|
root: {
|
||||||
|
marginLeft: cardItemGapBig,
|
||||||
|
marginRight: cardItemGapBig,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Separator styles={{ root: { padding: 0, height: 1 } }} />
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{isFavorite !== undefined &&
|
||||||
|
generateIconButtonWithTooltip(
|
||||||
|
isFavorite ? "HeartFill" : "Heart",
|
||||||
|
isFavorite ? "Unfavorite" : "Favorite",
|
||||||
|
"left",
|
||||||
|
isFavorite ? onUnfavoriteClick : onFavoriteClick
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showDownload && generateIconButtonWithTooltip("Download", "Download", "left", onDownloadClick)}
|
||||||
|
|
||||||
|
{showDelete &&
|
||||||
|
generateIconButtonWithTooltip("Delete", "Remove", "right", () =>
|
||||||
|
onDeleteClick(
|
||||||
|
() => setIsDeletingPublishedNotebook(true),
|
||||||
|
() => setIsDeletingPublishedNotebook(false)
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Card.Section>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { JunoClient } from "../../../Juno/JunoClient";
|
|
||||||
import { HttpStatusCodes, CodeOfConductEndpoints } from "../../../Common/Constants";
|
|
||||||
import { Stack, Text, Checkbox, PrimaryButton, Link } from "office-ui-fabric-react";
|
|
||||||
import { getErrorMessage, getErrorStack, handleError } from "../../../Common/ErrorHandlingUtils";
|
|
||||||
import { trace, traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
|
|
||||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
|
||||||
|
|
||||||
export interface CodeOfConductComponentProps {
|
|
||||||
junoClient: JunoClient;
|
|
||||||
onAcceptCodeOfConduct: (result: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CodeOfConductComponentState {
|
|
||||||
readCodeOfConduct: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CodeOfConductComponent extends React.Component<CodeOfConductComponentProps, CodeOfConductComponentState> {
|
|
||||||
private viewCodeOfConductTraced: boolean;
|
|
||||||
private descriptionPara1: string;
|
|
||||||
private descriptionPara2: string;
|
|
||||||
private descriptionPara3: string;
|
|
||||||
private link1: { label: string; url: string };
|
|
||||||
|
|
||||||
constructor(props: CodeOfConductComponentProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
readCodeOfConduct: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.descriptionPara1 = "Azure Cosmos DB Notebook Gallery - Code of Conduct";
|
|
||||||
this.descriptionPara2 = "The notebook public gallery contains notebook samples shared by users of Azure Cosmos DB.";
|
|
||||||
this.descriptionPara3 = "In order to view and publish your samples to the gallery, you must accept the ";
|
|
||||||
this.link1 = { label: "code of conduct.", url: CodeOfConductEndpoints.codeOfConduct };
|
|
||||||
}
|
|
||||||
|
|
||||||
private async acceptCodeOfConduct(): Promise<void> {
|
|
||||||
const startKey = traceStart(Action.NotebooksGalleryAcceptCodeOfConduct);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await this.props.junoClient.acceptCodeOfConduct();
|
|
||||||
if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) {
|
|
||||||
throw new Error(`Received HTTP ${response.status} when accepting code of conduct`);
|
|
||||||
}
|
|
||||||
|
|
||||||
traceSuccess(Action.NotebooksGalleryAcceptCodeOfConduct, {}, startKey);
|
|
||||||
|
|
||||||
this.props.onAcceptCodeOfConduct(response.data);
|
|
||||||
} catch (error) {
|
|
||||||
traceFailure(
|
|
||||||
Action.NotebooksGalleryAcceptCodeOfConduct,
|
|
||||||
{
|
|
||||||
error: getErrorMessage(error),
|
|
||||||
errorStack: getErrorStack(error),
|
|
||||||
},
|
|
||||||
startKey
|
|
||||||
);
|
|
||||||
|
|
||||||
handleError(error, "CodeOfConductComponent/acceptCodeOfConduct", "Failed to accept code of conduct");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onChangeCheckbox = (): void => {
|
|
||||||
this.setState({ readCodeOfConduct: !this.state.readCodeOfConduct });
|
|
||||||
};
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
if (!this.viewCodeOfConductTraced) {
|
|
||||||
this.viewCodeOfConductTraced = true;
|
|
||||||
trace(Action.NotebooksGalleryViewCodeOfConduct);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack tokens={{ childrenGap: 20 }}>
|
|
||||||
<Stack.Item>
|
|
||||||
<Text style={{ fontWeight: 500, fontSize: "20px" }}>{this.descriptionPara1}</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Text>{this.descriptionPara2}</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Text>
|
|
||||||
{this.descriptionPara3}
|
|
||||||
<Link href={this.link1.url} target="_blank">
|
|
||||||
{this.link1.label}
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<Checkbox
|
|
||||||
styles={{
|
|
||||||
label: {
|
|
||||||
margin: 0,
|
|
||||||
padding: "2 0 2 0",
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
fontSize: 12,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
label="I have read and accept the code of conduct."
|
|
||||||
onChange={this.onChangeCheckbox}
|
|
||||||
/>
|
|
||||||
</Stack.Item>
|
|
||||||
|
|
||||||
<Stack.Item>
|
|
||||||
<PrimaryButton
|
|
||||||
ariaLabel="Continue"
|
|
||||||
title="Continue"
|
|
||||||
onClick={async () => await this.acceptCodeOfConduct()}
|
|
||||||
tabIndex={0}
|
|
||||||
className="genericPaneSubmitBtn"
|
|
||||||
text="Continue"
|
|
||||||
disabled={!this.state.readCodeOfConduct}
|
|
||||||
/>
|
|
||||||
</Stack.Item>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
jest.mock("../../../Juno/JunoClient");
|
jest.mock("../../../../Juno/JunoClient");
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CodeOfConductComponent, CodeOfConductComponentProps } from "./CodeOfConductComponent";
|
import { CodeOfConductComponent, CodeOfConductComponentProps } from ".";
|
||||||
import { JunoClient } from "../../../Juno/JunoClient";
|
import { HttpStatusCodes } from "../../../../Common/Constants";
|
||||||
import { HttpStatusCodes } from "../../../Common/Constants";
|
import { JunoClient } from "../../../../Juno/JunoClient";
|
||||||
|
|
||||||
describe("CodeOfConductComponent", () => {
|
describe("CodeOfConductComponent", () => {
|
||||||
let codeOfConductProps: CodeOfConductComponentProps;
|
let codeOfConductProps: CodeOfConductComponentProps;
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import { Checkbox, Link, PrimaryButton, Stack, Text } from "office-ui-fabric-react";
|
||||||
|
import React, { FunctionComponent, useEffect, useState } from "react";
|
||||||
|
import { CodeOfConductEndpoints, HttpStatusCodes } from "../../../../Common/Constants";
|
||||||
|
import { getErrorMessage, getErrorStack, handleError } from "../../../../Common/ErrorHandlingUtils";
|
||||||
|
import { JunoClient } from "../../../../Juno/JunoClient";
|
||||||
|
import { Action } from "../../../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { trace, traceFailure, traceStart, traceSuccess } from "../../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
|
||||||
|
export interface CodeOfConductComponentProps {
|
||||||
|
junoClient: JunoClient;
|
||||||
|
onAcceptCodeOfConduct: (result: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CodeOfConductComponent: FunctionComponent<CodeOfConductComponentProps> = ({
|
||||||
|
junoClient,
|
||||||
|
onAcceptCodeOfConduct,
|
||||||
|
}: CodeOfConductComponentProps) => {
|
||||||
|
const descriptionPara1 = "Azure Cosmos DB Notebook Gallery - Code of Conduct";
|
||||||
|
const descriptionPara2 = "The notebook public gallery contains notebook samples shared by users of Azure Cosmos DB.";
|
||||||
|
const descriptionPara3 = "In order to view and publish your samples to the gallery, you must accept the ";
|
||||||
|
const link1: { label: string; url: string } = {
|
||||||
|
label: "code of conduct.",
|
||||||
|
url: CodeOfConductEndpoints.codeOfConduct,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [readCodeOfConduct, setReadCodeOfConduct] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const acceptCodeOfConduct = async (): Promise<void> => {
|
||||||
|
const startKey = traceStart(Action.NotebooksGalleryAcceptCodeOfConduct);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await junoClient.acceptCodeOfConduct();
|
||||||
|
if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) {
|
||||||
|
throw new Error(`Received HTTP ${response.status} when accepting code of conduct`);
|
||||||
|
}
|
||||||
|
|
||||||
|
traceSuccess(Action.NotebooksGalleryAcceptCodeOfConduct, {}, startKey);
|
||||||
|
|
||||||
|
onAcceptCodeOfConduct(response.data);
|
||||||
|
} catch (error) {
|
||||||
|
traceFailure(
|
||||||
|
Action.NotebooksGalleryAcceptCodeOfConduct,
|
||||||
|
{
|
||||||
|
error: getErrorMessage(error),
|
||||||
|
errorStack: getErrorStack(error),
|
||||||
|
},
|
||||||
|
startKey
|
||||||
|
);
|
||||||
|
|
||||||
|
handleError(error, "CodeOfConductComponent/acceptCodeOfConduct", "Failed to accept code of conduct");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeCheckbox = (): void => {
|
||||||
|
setReadCodeOfConduct(!readCodeOfConduct);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
trace(Action.NotebooksGalleryViewCodeOfConduct);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack tokens={{ childrenGap: 20 }}>
|
||||||
|
<Stack.Item>
|
||||||
|
<Text style={{ fontWeight: 500, fontSize: "20px" }}>{descriptionPara1}</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Text>{descriptionPara2}</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Text>
|
||||||
|
{descriptionPara3}
|
||||||
|
<Link href={link1.url} target="_blank">
|
||||||
|
{link1.label}
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<Checkbox
|
||||||
|
styles={{
|
||||||
|
label: {
|
||||||
|
margin: 0,
|
||||||
|
padding: "2 0 2 0",
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
label="I have read and accept the code of conduct."
|
||||||
|
onChange={onChangeCheckbox}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
|
||||||
|
<Stack.Item>
|
||||||
|
<PrimaryButton
|
||||||
|
ariaLabel="Continue"
|
||||||
|
title="Continue"
|
||||||
|
onClick={async () => await acceptCodeOfConduct()}
|
||||||
|
tabIndex={0}
|
||||||
|
className="genericPaneSubmitBtn"
|
||||||
|
text="Continue"
|
||||||
|
disabled={!readCodeOfConduct}
|
||||||
|
/>
|
||||||
|
</Stack.Item>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import ko from "knockout";
|
|
||||||
import * as React from "react";
|
|
||||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
|
||||||
import {
|
|
||||||
GalleryAndNotebookViewerComponentProps,
|
|
||||||
GalleryAndNotebookViewerComponent,
|
|
||||||
} from "./GalleryAndNotebookViewerComponent";
|
|
||||||
|
|
||||||
export class GalleryAndNotebookViewerComponentAdapter implements ReactAdapter {
|
|
||||||
private key: string;
|
|
||||||
public parameters: ko.Observable<number>;
|
|
||||||
|
|
||||||
constructor(private props: GalleryAndNotebookViewerComponentProps) {
|
|
||||||
this.reset();
|
|
||||||
this.parameters = ko.observable<number>(Date.now());
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderComponent(): JSX.Element {
|
|
||||||
return <GalleryAndNotebookViewerComponent key={this.key} {...this.props} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
public reset(): void {
|
|
||||||
this.key = `GalleryAndNotebookViewerComponent-${Date.now()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public triggerRender(): void {
|
|
||||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -34,6 +34,7 @@ import { CodeOfConductComponent } from "./CodeOfConductComponent";
|
|||||||
import "./GalleryViewerComponent.less";
|
import "./GalleryViewerComponent.less";
|
||||||
import { InfoComponent } from "./InfoComponent/InfoComponent";
|
import { InfoComponent } from "./InfoComponent/InfoComponent";
|
||||||
|
|
||||||
|
const CARD_WIDTH = 256;
|
||||||
export interface GalleryViewerComponentProps {
|
export interface GalleryViewerComponentProps {
|
||||||
container?: Explorer;
|
container?: Explorer;
|
||||||
junoClient: JunoClient;
|
junoClient: JunoClient;
|
||||||
@@ -643,7 +644,7 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
|
|||||||
|
|
||||||
private getPageSpecification = (itemIndex?: number, visibleRect?: IRectangle): IPageSpecification => {
|
private getPageSpecification = (itemIndex?: number, visibleRect?: IRectangle): IPageSpecification => {
|
||||||
if (itemIndex === 0) {
|
if (itemIndex === 0) {
|
||||||
this.columnCount = Math.floor(visibleRect.width / GalleryCardComponent.CARD_WIDTH) || this.columnCount;
|
this.columnCount = Math.floor(visibleRect.width / CARD_WIDTH) || this.columnCount;
|
||||||
this.rowCount = GalleryViewerComponent.rowsPerPage;
|
this.rowCount = GalleryViewerComponent.rowsPerPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,15 +136,13 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
this.container = this.collection?.container;
|
this.container = this.collection?.container;
|
||||||
this.offer = this.collection?.offer();
|
this.offer = this.collection?.offer();
|
||||||
this.isAnalyticalStorageEnabled = !!this.collection?.analyticalStorageTtl();
|
this.isAnalyticalStorageEnabled = !!this.collection?.analyticalStorageTtl();
|
||||||
this.shouldShowIndexingPolicyEditor =
|
this.shouldShowIndexingPolicyEditor = userContext.apiType !== "Cassandra" && userContext.apiType !== "Mongo";
|
||||||
this.container && userContext.apiType !== "Cassandra" && !this.container.isPreferredApiMongoDB();
|
|
||||||
|
|
||||||
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
|
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
|
||||||
|
|
||||||
// Mongo container with system partition key still treat as "Fixed"
|
// Mongo container with system partition key still treat as "Fixed"
|
||||||
this.isFixedContainer =
|
this.isFixedContainer =
|
||||||
this.container.isPreferredApiMongoDB() &&
|
userContext.apiType === "Mongo" && (!this.collection?.partitionKey || this.collection?.partitionKey.systemKey);
|
||||||
(!this.collection?.partitionKey || this.collection?.partitionKey.systemKey);
|
|
||||||
} else {
|
} else {
|
||||||
this.database = this.props.settingsTab.database;
|
this.database = this.props.settingsTab.database;
|
||||||
this.container = this.database?.container;
|
this.container = this.database?.container;
|
||||||
@@ -236,7 +234,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
|
|
||||||
public loadMongoIndexes = async (): Promise<void> => {
|
public loadMongoIndexes = async (): Promise<void> => {
|
||||||
if (
|
if (
|
||||||
this.container.isPreferredApiMongoDB() &&
|
userContext.apiType === "Mongo" &&
|
||||||
this.container.isEnableMongoCapabilityPresent() &&
|
this.container.isEnableMongoCapabilityPresent() &&
|
||||||
this.container.databaseAccount()
|
this.container.databaseAccount()
|
||||||
) {
|
) {
|
||||||
@@ -1002,7 +1000,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
tab: SettingsV2TabTypes.IndexingPolicyTab,
|
tab: SettingsV2TabTypes.IndexingPolicyTab,
|
||||||
content: <IndexingPolicyComponent {...indexingPolicyComponentProps} />,
|
content: <IndexingPolicyComponent {...indexingPolicyComponentProps} />,
|
||||||
});
|
});
|
||||||
} else if (this.container.isPreferredApiMongoDB()) {
|
} else if (userContext.apiType === "Mongo") {
|
||||||
const mongoIndexTabContext = this.getMongoIndexTabContent(mongoIndexingPolicyComponentProps);
|
const mongoIndexTabContext = this.getMongoIndexTabContent(mongoIndexingPolicyComponentProps);
|
||||||
if (mongoIndexTabContext) {
|
if (mongoIndexTabContext) {
|
||||||
tabs.push({
|
tabs.push({
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { MessageBar, MessageBarType, Stack } from "office-ui-fabric-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as DataModels from "../../../../Contracts/DataModels";
|
import * as DataModels from "../../../../Contracts/DataModels";
|
||||||
import * as monaco from "monaco-editor";
|
import { loadMonaco, monaco } from "../../../LazyMonaco";
|
||||||
import { isDirty, isIndexTransforming } from "../SettingsUtils";
|
|
||||||
import { MessageBar, MessageBarType, Stack } from "office-ui-fabric-react";
|
|
||||||
import { indexingPolicynUnsavedWarningMessage, titleAndInputStackProps } from "../SettingsRenderUtils";
|
import { indexingPolicynUnsavedWarningMessage, titleAndInputStackProps } from "../SettingsRenderUtils";
|
||||||
|
import { isDirty, isIndexTransforming } from "../SettingsUtils";
|
||||||
import { IndexingPolicyRefreshComponent } from "./IndexingPolicyRefresh/IndexingPolicyRefreshComponent";
|
import { IndexingPolicyRefreshComponent } from "./IndexingPolicyRefresh/IndexingPolicyRefreshComponent";
|
||||||
|
|
||||||
export interface IndexingPolicyComponentProps {
|
export interface IndexingPolicyComponentProps {
|
||||||
@@ -84,9 +84,9 @@ export class IndexingPolicyComponent extends React.Component<
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
private createIndexingPolicyEditor = (): void => {
|
private async createIndexingPolicyEditor(): Promise<void> {
|
||||||
const value: string = JSON.stringify(this.props.indexingPolicyContent, undefined, 4);
|
const value: string = JSON.stringify(this.props.indexingPolicyContent, undefined, 4);
|
||||||
|
const monaco = await loadMonaco();
|
||||||
this.indexingPolicyEditor = monaco.editor.create(this.indexingPolicyDiv.current, {
|
this.indexingPolicyEditor = monaco.editor.create(this.indexingPolicyDiv.current, {
|
||||||
value: value,
|
value: value,
|
||||||
language: "json",
|
language: "json",
|
||||||
@@ -98,7 +98,7 @@ export class IndexingPolicyComponent extends React.Component<
|
|||||||
indexingPolicyEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
|
indexingPolicyEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
|
||||||
this.props.logIndexingPolicySuccessMessage();
|
this.props.logIndexingPolicySuccessMessage();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
private onEditorContentChange = (): void => {
|
private onEditorContentChange = (): void => {
|
||||||
const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
|
const indexingPolicyEditorModel = this.indexingPolicyEditor.getModel();
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
userContext.apiType === "Cassandra" ||
|
userContext.apiType === "Cassandra" ||
|
||||||
userContext.apiType === "Tables" ||
|
userContext.apiType === "Tables" ||
|
||||||
!this.props.collection.partitionKeyProperty ||
|
!this.props.collection.partitionKeyProperty ||
|
||||||
(this.props.container.isPreferredApiMongoDB() && this.props.collection.partitionKey.systemKey)
|
(userContext.apiType === "Mongo" && this.props.collection.partitionKey.systemKey)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
|
|||||||
</Text>
|
</Text>
|
||||||
<Text>
|
<Text>
|
||||||
<em>
|
<em>
|
||||||
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
||||||
</em>
|
</em>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -689,7 +689,7 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
|
|||||||
</Text>
|
</Text>
|
||||||
<Text>
|
<Text>
|
||||||
<em>
|
<em>
|
||||||
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
||||||
</em>
|
</em>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -177,40 +177,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
CassandraAddCollectionPane {
|
CassandraAddCollectionPane {
|
||||||
"autoPilotUsageCost": [Function],
|
"autoPilotUsageCost": [Function],
|
||||||
"canConfigureThroughput": [Function],
|
"canConfigureThroughput": [Function],
|
||||||
@@ -233,9 +199,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -258,20 +222,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"userTableQuery": [Function],
|
"userTableQuery": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
@@ -426,9 +376,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -479,40 +427,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"defaultExperience": [Function],
|
"defaultExperience": [Function],
|
||||||
"deleteCollectionText": [Function],
|
"deleteCollectionText": [Function],
|
||||||
"deleteDatabaseText": [Function],
|
"deleteDatabaseText": [Function],
|
||||||
"editTableEntityPane": EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"graphStylingPane": GraphStylingPane {
|
"graphStylingPane": GraphStylingPane {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"firstFieldHasFocus": [Function],
|
"firstFieldHasFocus": [Function],
|
||||||
@@ -544,7 +458,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isMongoIndexingEnabled": [Function],
|
"isMongoIndexingEnabled": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isPreferredApiMongoDB": [Function],
|
|
||||||
"isPublishNotebookPaneEnabled": [Function],
|
"isPublishNotebookPaneEnabled": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
"isResourceTokenCollectionNodeSelected": [Function],
|
||||||
"isRightPanelV2Enabled": [Function],
|
"isRightPanelV2Enabled": [Function],
|
||||||
@@ -576,21 +489,9 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"resourceTree": ResourceTreeAdapter {
|
"resourceTree": ResourceTreeAdapter {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"copyNotebook": [Function],
|
"copyNotebook": [Function],
|
||||||
"databaseCollectionIdMap": ArrayHashMap {
|
"databaseCollectionIdMap": Map {},
|
||||||
"store": HashMap {
|
"koSubsCollectionIdMap": Map {},
|
||||||
"container": Object {},
|
"koSubsDatabaseIdMap": Map {},
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsCollectionIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsDatabaseIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
||||||
@@ -616,20 +517,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"onResizeStop": [Function],
|
"onResizeStop": [Function],
|
||||||
"splitterId": "h_splitter1",
|
"splitterId": "h_splitter1",
|
||||||
},
|
},
|
||||||
"stringInputPane": StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
"openedTabs": [Function],
|
"openedTabs": [Function],
|
||||||
@@ -805,40 +692,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
CassandraAddCollectionPane {
|
CassandraAddCollectionPane {
|
||||||
"autoPilotUsageCost": [Function],
|
"autoPilotUsageCost": [Function],
|
||||||
"canConfigureThroughput": [Function],
|
"canConfigureThroughput": [Function],
|
||||||
@@ -861,9 +714,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -886,20 +737,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"userTableQuery": [Function],
|
"userTableQuery": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
@@ -1054,9 +891,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -1107,40 +942,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"defaultExperience": [Function],
|
"defaultExperience": [Function],
|
||||||
"deleteCollectionText": [Function],
|
"deleteCollectionText": [Function],
|
||||||
"deleteDatabaseText": [Function],
|
"deleteDatabaseText": [Function],
|
||||||
"editTableEntityPane": EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"graphStylingPane": GraphStylingPane {
|
"graphStylingPane": GraphStylingPane {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"firstFieldHasFocus": [Function],
|
"firstFieldHasFocus": [Function],
|
||||||
@@ -1172,7 +973,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isMongoIndexingEnabled": [Function],
|
"isMongoIndexingEnabled": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isPreferredApiMongoDB": [Function],
|
|
||||||
"isPublishNotebookPaneEnabled": [Function],
|
"isPublishNotebookPaneEnabled": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
"isResourceTokenCollectionNodeSelected": [Function],
|
||||||
"isRightPanelV2Enabled": [Function],
|
"isRightPanelV2Enabled": [Function],
|
||||||
@@ -1204,21 +1004,9 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"resourceTree": ResourceTreeAdapter {
|
"resourceTree": ResourceTreeAdapter {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"copyNotebook": [Function],
|
"copyNotebook": [Function],
|
||||||
"databaseCollectionIdMap": ArrayHashMap {
|
"databaseCollectionIdMap": Map {},
|
||||||
"store": HashMap {
|
"koSubsCollectionIdMap": Map {},
|
||||||
"container": Object {},
|
"koSubsDatabaseIdMap": Map {},
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsCollectionIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsDatabaseIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
||||||
@@ -1244,20 +1032,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"onResizeStop": [Function],
|
"onResizeStop": [Function],
|
||||||
"splitterId": "h_splitter1",
|
"splitterId": "h_splitter1",
|
||||||
},
|
},
|
||||||
"stringInputPane": StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
"openedTabs": [Function],
|
"openedTabs": [Function],
|
||||||
@@ -1446,40 +1220,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
CassandraAddCollectionPane {
|
CassandraAddCollectionPane {
|
||||||
"autoPilotUsageCost": [Function],
|
"autoPilotUsageCost": [Function],
|
||||||
"canConfigureThroughput": [Function],
|
"canConfigureThroughput": [Function],
|
||||||
@@ -1502,9 +1242,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -1527,20 +1265,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"userTableQuery": [Function],
|
"userTableQuery": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
@@ -1695,9 +1419,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -1748,40 +1470,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"defaultExperience": [Function],
|
"defaultExperience": [Function],
|
||||||
"deleteCollectionText": [Function],
|
"deleteCollectionText": [Function],
|
||||||
"deleteDatabaseText": [Function],
|
"deleteDatabaseText": [Function],
|
||||||
"editTableEntityPane": EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"graphStylingPane": GraphStylingPane {
|
"graphStylingPane": GraphStylingPane {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"firstFieldHasFocus": [Function],
|
"firstFieldHasFocus": [Function],
|
||||||
@@ -1813,7 +1501,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isMongoIndexingEnabled": [Function],
|
"isMongoIndexingEnabled": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isPreferredApiMongoDB": [Function],
|
|
||||||
"isPublishNotebookPaneEnabled": [Function],
|
"isPublishNotebookPaneEnabled": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
"isResourceTokenCollectionNodeSelected": [Function],
|
||||||
"isRightPanelV2Enabled": [Function],
|
"isRightPanelV2Enabled": [Function],
|
||||||
@@ -1845,21 +1532,9 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"resourceTree": ResourceTreeAdapter {
|
"resourceTree": ResourceTreeAdapter {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"copyNotebook": [Function],
|
"copyNotebook": [Function],
|
||||||
"databaseCollectionIdMap": ArrayHashMap {
|
"databaseCollectionIdMap": Map {},
|
||||||
"store": HashMap {
|
"koSubsCollectionIdMap": Map {},
|
||||||
"container": Object {},
|
"koSubsDatabaseIdMap": Map {},
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsCollectionIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsDatabaseIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
||||||
@@ -1885,20 +1560,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"onResizeStop": [Function],
|
"onResizeStop": [Function],
|
||||||
"splitterId": "h_splitter1",
|
"splitterId": "h_splitter1",
|
||||||
},
|
},
|
||||||
"stringInputPane": StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
"openedTabs": [Function],
|
"openedTabs": [Function],
|
||||||
@@ -2074,40 +1735,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
CassandraAddCollectionPane {
|
CassandraAddCollectionPane {
|
||||||
"autoPilotUsageCost": [Function],
|
"autoPilotUsageCost": [Function],
|
||||||
"canConfigureThroughput": [Function],
|
"canConfigureThroughput": [Function],
|
||||||
@@ -2130,9 +1757,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -2155,20 +1780,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"userTableQuery": [Function],
|
"userTableQuery": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
@@ -2323,9 +1934,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"keyspaceHasSharedOffer": [Function],
|
"keyspaceHasSharedOffer": [Function],
|
||||||
"keyspaceId": [Function],
|
"keyspaceId": [Function],
|
||||||
"keyspaceIds": [Function],
|
"keyspaceIds": [Function],
|
||||||
"keyspaceOffers": HashMap {
|
"keyspaceOffers": Map {},
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
"keyspaceThroughput": [Function],
|
"keyspaceThroughput": [Function],
|
||||||
"maxThroughputRU": [Function],
|
"maxThroughputRU": [Function],
|
||||||
"minThroughputRU": [Function],
|
"minThroughputRU": [Function],
|
||||||
@@ -2376,40 +1985,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"defaultExperience": [Function],
|
"defaultExperience": [Function],
|
||||||
"deleteCollectionText": [Function],
|
"deleteCollectionText": [Function],
|
||||||
"deleteDatabaseText": [Function],
|
"deleteDatabaseText": [Function],
|
||||||
"editTableEntityPane": EditTableEntityPane {
|
|
||||||
"addButtonLabel": "Add Property",
|
|
||||||
"attributeNameLabel": "Property Name",
|
|
||||||
"attributeValueLabel": "Value",
|
|
||||||
"canAdd": [Function],
|
|
||||||
"canApply": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"dataTypeLabel": "Type",
|
|
||||||
"displayedAttributes": [Function],
|
|
||||||
"editAttribute": [Function],
|
|
||||||
"editButtonLabel": "Edit",
|
|
||||||
"editingProperty": [Function],
|
|
||||||
"edmTypes": [Function],
|
|
||||||
"finishEditingAttribute": [Function],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "edittableentitypane",
|
|
||||||
"insertAttribute": [Function],
|
|
||||||
"isEditing": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"onAddPropertyKeyDown": [Function],
|
|
||||||
"onBackButtonKeyDown": [Function],
|
|
||||||
"onDeletePropertyKeyDown": [Function],
|
|
||||||
"onEditPropertyKeyDown": [Function],
|
|
||||||
"onKeyUp": [Function],
|
|
||||||
"removeAttribute": [Function],
|
|
||||||
"removeButtonLabel": "Remove",
|
|
||||||
"scrollId": [Function],
|
|
||||||
"submitButtonText": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"graphStylingPane": GraphStylingPane {
|
"graphStylingPane": GraphStylingPane {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"firstFieldHasFocus": [Function],
|
"firstFieldHasFocus": [Function],
|
||||||
@@ -2441,7 +2016,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isMongoIndexingEnabled": [Function],
|
"isMongoIndexingEnabled": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isPreferredApiMongoDB": [Function],
|
|
||||||
"isPublishNotebookPaneEnabled": [Function],
|
"isPublishNotebookPaneEnabled": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
"isResourceTokenCollectionNodeSelected": [Function],
|
||||||
"isRightPanelV2Enabled": [Function],
|
"isRightPanelV2Enabled": [Function],
|
||||||
@@ -2473,21 +2047,9 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"resourceTree": ResourceTreeAdapter {
|
"resourceTree": ResourceTreeAdapter {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"copyNotebook": [Function],
|
"copyNotebook": [Function],
|
||||||
"databaseCollectionIdMap": ArrayHashMap {
|
"databaseCollectionIdMap": Map {},
|
||||||
"store": HashMap {
|
"koSubsCollectionIdMap": Map {},
|
||||||
"container": Object {},
|
"koSubsDatabaseIdMap": Map {},
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsCollectionIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"koSubsDatabaseIdMap": ArrayHashMap {
|
|
||||||
"store": HashMap {
|
|
||||||
"container": Object {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
"resourceTreeForResourceToken": ResourceTreeAdapterForResourceToken {
|
||||||
@@ -2513,20 +2075,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"onResizeStop": [Function],
|
"onResizeStop": [Function],
|
||||||
"splitterId": "h_splitter1",
|
"splitterId": "h_splitter1",
|
||||||
},
|
},
|
||||||
"stringInputPane": StringInputPane {
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"id": "stringinputpane",
|
|
||||||
"inputLabel": [Function],
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"stringInput": [Function],
|
|
||||||
"submitButtonLabel": [Function],
|
|
||||||
"title": [Function],
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
"openedTabs": [Function],
|
"openedTabs": [Function],
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ exports[`SettingsUtils functions render 1`] = `
|
|||||||
</Text>
|
</Text>
|
||||||
<Text>
|
<Text>
|
||||||
<em>
|
<em>
|
||||||
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
||||||
</em>
|
</em>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -11,10 +11,6 @@
|
|||||||
padding: 0 @LargeSpace 0 @SmallSpace;
|
padding: 0 @LargeSpace 0 @SmallSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.throughputInputSpacing {
|
.throughputInputSpacing > :not(:last-child) {
|
||||||
margin-bottom: @SmallSpace;
|
margin-bottom: @DefaultSpace;
|
||||||
|
|
||||||
& > * {
|
|
||||||
margin-bottom: @SmallSpace;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ import React from "react";
|
|||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import * as SharedConstants from "../../../Shared/Constants";
|
import * as SharedConstants from "../../../Shared/Constants";
|
||||||
import { userContext } from "../../../UserContext";
|
import { userContext } from "../../../UserContext";
|
||||||
|
import { getCollectionName } from "../../../Utils/APITypeUtils";
|
||||||
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
||||||
import * as PricingUtils from "../../../Utils/PricingUtils";
|
import * as PricingUtils from "../../../Utils/PricingUtils";
|
||||||
|
|
||||||
export interface ThroughputInputProps {
|
export interface ThroughputInputProps {
|
||||||
isDatabase: boolean;
|
isDatabase: boolean;
|
||||||
|
isSharded: boolean;
|
||||||
showFreeTierExceedThroughputTooltip: boolean;
|
showFreeTierExceedThroughputTooltip: boolean;
|
||||||
setThroughputValue: (throughput: number) => void;
|
setThroughputValue: (throughput: number) => void;
|
||||||
setIsAutoscale: (isAutoscale: boolean) => void;
|
setIsAutoscale: (isAutoscale: boolean) => void;
|
||||||
@@ -18,6 +20,7 @@ export interface ThroughputInputState {
|
|||||||
isAutoscaleSelected: boolean;
|
isAutoscaleSelected: boolean;
|
||||||
throughput: number;
|
throughput: number;
|
||||||
isCostAcknowledged: boolean;
|
isCostAcknowledged: boolean;
|
||||||
|
throughputError: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ThroughputInput extends React.Component<ThroughputInputProps, ThroughputInputState> {
|
export class ThroughputInput extends React.Component<ThroughputInputProps, ThroughputInputState> {
|
||||||
@@ -28,6 +31,7 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
isAutoscaleSelected: true,
|
isAutoscaleSelected: true,
|
||||||
throughput: AutoPilotUtils.minAutoPilotThroughput,
|
throughput: AutoPilotUtils.minAutoPilotThroughput,
|
||||||
isCostAcknowledged: false,
|
isCostAcknowledged: false,
|
||||||
|
throughputError: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.props.setThroughputValue(AutoPilotUtils.minAutoPilotThroughput);
|
this.props.setThroughputValue(AutoPilotUtils.minAutoPilotThroughput);
|
||||||
@@ -39,11 +43,11 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
<div className="throughputInputContainer throughputInputSpacing">
|
<div className="throughputInputContainer throughputInputSpacing">
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<span className="mandatoryStar">* </span>
|
<span className="mandatoryStar">* </span>
|
||||||
<Text variant="small" style={{ lineHeight: "20px" }}>
|
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600 }}>
|
||||||
{this.getThroughputLabelText()}
|
{this.getThroughputLabelText()}
|
||||||
</Text>
|
</Text>
|
||||||
<TooltipHost directionalHint={DirectionalHint.bottomLeftEdge} content={PricingUtils.getRuToolTipText()}>
|
<TooltipHost directionalHint={DirectionalHint.bottomLeftEdge} content={PricingUtils.getRuToolTipText()}>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -74,7 +78,7 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
{this.state.isAutoscaleSelected && (
|
{this.state.isAutoscaleSelected && (
|
||||||
<Stack className="throughputInputSpacing">
|
<Stack className="throughputInputSpacing">
|
||||||
<Text variant="small">
|
<Text variant="small">
|
||||||
Provision maximum RU/s required by this resource. Estimate your required RU/s with
|
Estimate your required RU/s with
|
||||||
<Link target="_blank" href="https://cosmos.azure.com/capacitycalculator/">
|
<Link target="_blank" href="https://cosmos.azure.com/capacitycalculator/">
|
||||||
capacity calculator
|
capacity calculator
|
||||||
</Link>
|
</Link>
|
||||||
@@ -82,11 +86,11 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<Text variant="small" style={{ lineHeight: "20px" }}>
|
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600 }}>
|
||||||
Max RU/s
|
{this.props.isDatabase ? "Database" : getCollectionName()} max RU/s
|
||||||
</Text>
|
</Text>
|
||||||
<TooltipHost directionalHint={DirectionalHint.bottomLeftEdge} content={this.getAutoScaleTooltip()}>
|
<TooltipHost directionalHint={DirectionalHint.bottomLeftEdge} content={this.getAutoScaleTooltip()}>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -101,11 +105,12 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
min={AutoPilotUtils.minAutoPilotThroughput}
|
min={AutoPilotUtils.minAutoPilotThroughput}
|
||||||
value={this.state.throughput.toString()}
|
value={this.state.throughput.toString()}
|
||||||
aria-label="Max request units per second"
|
aria-label="Max request units per second"
|
||||||
required={true}
|
errorMessage={this.state.throughputError}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Text variant="small">
|
<Text variant="small">
|
||||||
Your {this.props.isDatabase ? "database" : "container"} throughput will automatically scale from{" "}
|
Your {this.props.isDatabase ? "database" : getCollectionName().toLocaleLowerCase()} throughput will
|
||||||
|
automatically scale from{" "}
|
||||||
<b>
|
<b>
|
||||||
{AutoPilotUtils.getMinRUsBasedOnUserInput(this.state.throughput)} RU/s (10% of max RU/s) -{" "}
|
{AutoPilotUtils.getMinRUsBasedOnUserInput(this.state.throughput)} RU/s (10% of max RU/s) -{" "}
|
||||||
{this.state.throughput} RU/s
|
{this.state.throughput} RU/s
|
||||||
@@ -147,6 +152,7 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
value={this.state.throughput.toString()}
|
value={this.state.throughput.toString()}
|
||||||
aria-label="Max request units per second"
|
aria-label="Max request units per second"
|
||||||
required={true}
|
required={true}
|
||||||
|
errorMessage={this.state.throughputError}
|
||||||
/>
|
/>
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -156,6 +162,7 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
|
|
||||||
{this.state.throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && (
|
{this.state.throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && (
|
||||||
<Stack horizontal verticalAlign="start">
|
<Stack horizontal verticalAlign="start">
|
||||||
|
<span className="mandatoryStar">* </span>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={this.state.isCostAcknowledged}
|
checked={this.state.isCostAcknowledged}
|
||||||
styles={{
|
styles={{
|
||||||
@@ -177,30 +184,35 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getThroughputLabelText(): string {
|
private getThroughputLabelText(): string {
|
||||||
|
let throughputHeaderText: string;
|
||||||
if (this.state.isAutoscaleSelected) {
|
if (this.state.isAutoscaleSelected) {
|
||||||
return AutoPilotUtils.getAutoPilotHeaderText();
|
throughputHeaderText = AutoPilotUtils.getAutoPilotHeaderText().toLocaleLowerCase();
|
||||||
|
} else {
|
||||||
|
const minRU: string = SharedConstants.CollectionCreation.DefaultCollectionRUs400.toLocaleString();
|
||||||
|
const maxRU: string = userContext.isTryCosmosDBSubscription
|
||||||
|
? Constants.TryCosmosExperience.maxRU.toLocaleString()
|
||||||
|
: "unlimited";
|
||||||
|
throughputHeaderText = `throughput (${minRU} - ${maxRU} RU/s)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const minRU: string = SharedConstants.CollectionCreation.DefaultCollectionRUs400.toLocaleString();
|
return `${this.props.isDatabase ? "Database" : getCollectionName()} ${throughputHeaderText}`;
|
||||||
const maxRU: string = userContext.isTryCosmosDBSubscription
|
|
||||||
? Constants.TryCosmosExperience.maxRU.toLocaleString()
|
|
||||||
: "unlimited";
|
|
||||||
return this.state.isAutoscaleSelected
|
|
||||||
? AutoPilotUtils.getAutoPilotHeaderText()
|
|
||||||
: `Throughput (${minRU} - ${maxRU} RU/s)`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onThroughputValueChange(newInput: string): void {
|
private onThroughputValueChange(newInput: string): void {
|
||||||
const newThroughput = parseInt(newInput);
|
const newThroughput = parseInt(newInput);
|
||||||
this.setState({ throughput: newThroughput });
|
this.setState({ throughput: newThroughput });
|
||||||
this.props.setThroughputValue(newThroughput);
|
this.props.setThroughputValue(newThroughput);
|
||||||
|
|
||||||
|
if (!this.props.isSharded && newThroughput > 10000) {
|
||||||
|
this.setState({ throughputError: "Unsharded collections support up to 10,000 RUs" });
|
||||||
|
} else {
|
||||||
|
this.setState({ throughputError: undefined });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getAutoScaleTooltip(): string {
|
private getAutoScaleTooltip(): string {
|
||||||
return `After the first ${AutoPilotUtils.getStorageBasedOnUserInput(
|
const collectionName = getCollectionName().toLocaleLowerCase();
|
||||||
this.state.throughput
|
return `Set the max RU/s to the highest RU/s you want your ${collectionName} to scale to. The ${collectionName} will scale between 10% of max RU/s to the max RU/s based on usage.`;
|
||||||
)} GB of data stored, the max
|
|
||||||
RU/s will be automatically upgraded based on the new storage value.`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCostAcknowledgeText(): string {
|
private getCostAcknowledgeText(): string {
|
||||||
@@ -271,10 +283,20 @@ const CostEstimateText: React.FunctionComponent<CostEstimateTextProps> = (props:
|
|||||||
? PricingUtils.getAutoscalePricePerRu(serverId, multiplier) * multiplier
|
? PricingUtils.getAutoscalePricePerRu(serverId, multiplier) * multiplier
|
||||||
: PricingUtils.getPricePerRu(serverId) * multiplier;
|
: PricingUtils.getPricePerRu(serverId) * multiplier;
|
||||||
|
|
||||||
|
const iconWithEstimatedCostDisclaimer: JSX.Element = (
|
||||||
|
<TooltipHost
|
||||||
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
|
content={PricingUtils.estimatedCostDisclaimer}
|
||||||
|
styles={{ root: { verticalAlign: "bottom" } }}
|
||||||
|
>
|
||||||
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
|
</TooltipHost>
|
||||||
|
);
|
||||||
|
|
||||||
if (isAutoscale) {
|
if (isAutoscale) {
|
||||||
return (
|
return (
|
||||||
<Text variant="small">
|
<Text variant="small">
|
||||||
Estimated monthly cost ({currency}):{" "}
|
Estimated monthly cost ({currency}){iconWithEstimatedCostDisclaimer}:{" "}
|
||||||
<b>
|
<b>
|
||||||
{currencySign + PricingUtils.calculateEstimateNumber(monthlyPrice / 10)} -{" "}
|
{currencySign + PricingUtils.calculateEstimateNumber(monthlyPrice / 10)} -{" "}
|
||||||
{currencySign + PricingUtils.calculateEstimateNumber(monthlyPrice)}{" "}
|
{currencySign + PricingUtils.calculateEstimateNumber(monthlyPrice)}{" "}
|
||||||
@@ -287,7 +309,7 @@ const CostEstimateText: React.FunctionComponent<CostEstimateTextProps> = (props:
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Text variant="small">
|
<Text variant="small">
|
||||||
Cost ({currency}):{" "}
|
Estimated cost ({currency}){iconWithEstimatedCostDisclaimer}:{" "}
|
||||||
<b>
|
<b>
|
||||||
{currencySign + PricingUtils.calculateEstimateNumber(hourlyPrice)} hourly /{" "}
|
{currencySign + PricingUtils.calculateEstimateNumber(hourlyPrice)} hourly /{" "}
|
||||||
{currencySign + PricingUtils.calculateEstimateNumber(dailyPrice)} daily /{" "}
|
{currencySign + PricingUtils.calculateEstimateNumber(dailyPrice)} daily /{" "}
|
||||||
@@ -295,8 +317,6 @@ const CostEstimateText: React.FunctionComponent<CostEstimateTextProps> = (props:
|
|||||||
</b>
|
</b>
|
||||||
({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits}RU/s,{" "}
|
({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits}RU/s,{" "}
|
||||||
{currencySign + pricePerRu}/RU)
|
{currencySign + pricePerRu}/RU)
|
||||||
<br />
|
|
||||||
<em>{PricingUtils.estimatedCostDisclaimer}</em>
|
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ describe("ContainerSampleGenerator", () => {
|
|||||||
const createExplorerStub = (database: ViewModels.Database): Explorer => {
|
const createExplorerStub = (database: ViewModels.Database): Explorer => {
|
||||||
const explorerStub = {} as Explorer;
|
const explorerStub = {} as Explorer;
|
||||||
explorerStub.databases = ko.observableArray<ViewModels.Database>([database]);
|
explorerStub.databases = ko.observableArray<ViewModels.Database>([database]);
|
||||||
explorerStub.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
|
||||||
explorerStub.canExceedMaximumValue = ko.computed<boolean>(() => false);
|
explorerStub.canExceedMaximumValue = ko.computed<boolean>(() => false);
|
||||||
explorerStub.findDatabaseWithId = () => database;
|
explorerStub.findDatabaseWithId = () => database;
|
||||||
explorerStub.refreshAllDatabases = () => Q.resolve();
|
explorerStub.refreshAllDatabases = () => Q.resolve();
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import React from "react";
|
|||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
||||||
import { ReactAdapter } from "../Bindings/ReactBindingHandler";
|
|
||||||
import * as Constants from "../Common/Constants";
|
import * as Constants from "../Common/Constants";
|
||||||
import { ExplorerMetrics } from "../Common/Constants";
|
import { ExplorerMetrics } from "../Common/Constants";
|
||||||
import { readCollection } from "../Common/dataAccess/readCollection";
|
import { readCollection } from "../Common/dataAccess/readCollection";
|
||||||
@@ -26,27 +25,28 @@ import { ResourceProviderClientFactory } from "../ResourceProvider/ResourceProvi
|
|||||||
import { RouteHandler } from "../RouteHandlers/RouteHandler";
|
import { RouteHandler } from "../RouteHandlers/RouteHandler";
|
||||||
import { trackEvent } from "../Shared/appInsights";
|
import { trackEvent } from "../Shared/appInsights";
|
||||||
import * as SharedConstants from "../Shared/Constants";
|
import * as SharedConstants from "../Shared/Constants";
|
||||||
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
|
||||||
import { ExplorerSettings } from "../Shared/ExplorerSettings";
|
import { ExplorerSettings } from "../Shared/ExplorerSettings";
|
||||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { ArcadiaResourceManager } from "../SparkClusterManager/ArcadiaResourceManager";
|
import { ArcadiaResourceManager } from "../SparkClusterManager/ArcadiaResourceManager";
|
||||||
import { updateUserContext, userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
|
import { getCollectionName } from "../Utils/APITypeUtils";
|
||||||
import { decryptJWTToken, getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
import { decryptJWTToken, getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
||||||
import { stringToBlob } from "../Utils/BlobUtils";
|
import { stringToBlob } from "../Utils/BlobUtils";
|
||||||
import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils";
|
import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils";
|
||||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../Utils/NotificationConsoleUtils";
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../Utils/NotificationConsoleUtils";
|
||||||
import * as PricingUtils from "../Utils/PricingUtils";
|
|
||||||
import * as ComponentRegisterer from "./ComponentRegisterer";
|
import * as ComponentRegisterer from "./ComponentRegisterer";
|
||||||
import { ArcadiaWorkspaceItem } from "./Controls/Arcadia/ArcadiaMenuPicker";
|
import { ArcadiaWorkspaceItem } from "./Controls/Arcadia/ArcadiaMenuPicker";
|
||||||
import { CommandButtonComponentProps } from "./Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "./Controls/CommandButton/CommandButtonComponent";
|
||||||
import { DialogProps, TextFieldProps } from "./Controls/Dialog";
|
import { DialogProps, TextFieldProps } from "./Controls/Dialog";
|
||||||
import { GalleryTab } from "./Controls/NotebookGallery/GalleryViewerComponent";
|
import { GalleryTab as GalleryTabKind } from "./Controls/NotebookGallery/GalleryViewerComponent";
|
||||||
import { CommandBarComponentAdapter } from "./Menus/CommandBar/CommandBarComponentAdapter";
|
import { CommandBarComponentAdapter } from "./Menus/CommandBar/CommandBarComponentAdapter";
|
||||||
import { ConsoleData } from "./Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleData } from "./Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import * as FileSystemUtil from "./Notebook/FileSystemUtil";
|
import * as FileSystemUtil from "./Notebook/FileSystemUtil";
|
||||||
import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem";
|
import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem";
|
||||||
|
import type NotebookManager from "./Notebook/NotebookManager";
|
||||||
|
import type { NotebookPaneContent } from "./Notebook/NotebookManager";
|
||||||
import { NotebookUtil } from "./Notebook/NotebookUtil";
|
import { NotebookUtil } from "./Notebook/NotebookUtil";
|
||||||
import AddCollectionPane from "./Panes/AddCollectionPane";
|
import AddCollectionPane from "./Panes/AddCollectionPane";
|
||||||
import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
|
import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
|
||||||
@@ -62,9 +62,9 @@ import { LoadQueryPane } from "./Panes/LoadQueryPane/LoadQueryPane";
|
|||||||
import { SaveQueryPane } from "./Panes/SaveQueryPane/SaveQueryPane";
|
import { SaveQueryPane } from "./Panes/SaveQueryPane/SaveQueryPane";
|
||||||
import { SettingsPane } from "./Panes/SettingsPane/SettingsPane";
|
import { SettingsPane } from "./Panes/SettingsPane/SettingsPane";
|
||||||
import { SetupNoteBooksPanel } from "./Panes/SetupNotebooksPanel/SetupNotebooksPanel";
|
import { SetupNoteBooksPanel } from "./Panes/SetupNotebooksPanel/SetupNotebooksPanel";
|
||||||
import { StringInputPane } from "./Panes/StringInputPane";
|
import { StringInputPane } from "./Panes/StringInputPane/StringInputPane";
|
||||||
import { AddTableEntityPanel } from "./Panes/Tables/AddTableEntityPanel";
|
import { AddTableEntityPanel } from "./Panes/Tables/AddTableEntityPanel";
|
||||||
import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane";
|
import { EditTableEntityPanel } from "./Panes/Tables/EditTableEntityPanel";
|
||||||
import { TableQuerySelectPanel } from "./Panes/Tables/TableQuerySelectPanel";
|
import { TableQuerySelectPanel } from "./Panes/Tables/TableQuerySelectPanel";
|
||||||
import { UploadFilePane } from "./Panes/UploadFilePane/UploadFilePane";
|
import { UploadFilePane } from "./Panes/UploadFilePane/UploadFilePane";
|
||||||
import { UploadItemsPane } from "./Panes/UploadItemsPane/UploadItemsPane";
|
import { UploadItemsPane } from "./Panes/UploadItemsPane/UploadItemsPane";
|
||||||
@@ -73,7 +73,6 @@ import QueryViewModel from "./Tables/QueryBuilder/QueryViewModel";
|
|||||||
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
|
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
|
||||||
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
|
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
|
||||||
import QueryTablesTab from "./Tabs/QueryTablesTab";
|
import QueryTablesTab from "./Tabs/QueryTablesTab";
|
||||||
import TabsBase from "./Tabs/TabsBase";
|
|
||||||
import { TabsManager } from "./Tabs/TabsManager";
|
import { TabsManager } from "./Tabs/TabsManager";
|
||||||
import TerminalTab from "./Tabs/TerminalTab";
|
import TerminalTab from "./Tabs/TerminalTab";
|
||||||
import Database from "./Tree/Database";
|
import Database from "./Tree/Database";
|
||||||
@@ -118,11 +117,6 @@ export default class Explorer {
|
|||||||
* Use userContext.apiType instead
|
* Use userContext.apiType instead
|
||||||
* */
|
* */
|
||||||
public defaultExperience: ko.Observable<string>;
|
public defaultExperience: ko.Observable<string>;
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* Compare a string with userContext.apiType instead: userContext.apiType === "Mongo"
|
|
||||||
* */
|
|
||||||
public isPreferredApiMongoDB: ko.Computed<boolean>;
|
|
||||||
public isFixedCollectionWithSharedThroughputSupported: ko.Computed<boolean>;
|
public isFixedCollectionWithSharedThroughputSupported: ko.Computed<boolean>;
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
@@ -165,19 +159,14 @@ export default class Explorer {
|
|||||||
|
|
||||||
// Tabs
|
// Tabs
|
||||||
public isTabsContentExpanded: ko.Observable<boolean>;
|
public isTabsContentExpanded: ko.Observable<boolean>;
|
||||||
public galleryTab: any;
|
|
||||||
public notebookViewerTab: any;
|
|
||||||
public tabsManager: TabsManager;
|
public tabsManager: TabsManager;
|
||||||
|
|
||||||
// Contextual panes
|
// Contextual panes
|
||||||
public addDatabasePane: AddDatabasePane;
|
public addDatabasePane: AddDatabasePane;
|
||||||
public addCollectionPane: AddCollectionPane;
|
public addCollectionPane: AddCollectionPane;
|
||||||
public graphStylingPane: GraphStylingPane;
|
public graphStylingPane: GraphStylingPane;
|
||||||
public editTableEntityPane: EditTableEntityPane;
|
|
||||||
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
||||||
public stringInputPane: StringInputPane;
|
|
||||||
public gitHubReposPane: ContextualPaneBase;
|
public gitHubReposPane: ContextualPaneBase;
|
||||||
public publishNotebookPaneAdapter: ReactAdapter;
|
|
||||||
|
|
||||||
// features
|
// features
|
||||||
public isGitHubPaneEnabled: ko.Observable<boolean>;
|
public isGitHubPaneEnabled: ko.Observable<boolean>;
|
||||||
@@ -203,7 +192,7 @@ export default class Explorer {
|
|||||||
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
||||||
public isSynapseLinkUpdating: ko.Observable<boolean>;
|
public isSynapseLinkUpdating: ko.Observable<boolean>;
|
||||||
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
|
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
|
||||||
public notebookManager?: any; // This is dynamically loaded
|
public notebookManager?: NotebookManager;
|
||||||
public openDialog: ExplorerParams["openDialog"];
|
public openDialog: ExplorerParams["openDialog"];
|
||||||
public closeDialog: ExplorerParams["closeDialog"];
|
public closeDialog: ExplorerParams["closeDialog"];
|
||||||
|
|
||||||
@@ -383,16 +372,16 @@ export default class Explorer {
|
|||||||
direction: SplitterDirection.Vertical,
|
direction: SplitterDirection.Vertical,
|
||||||
});
|
});
|
||||||
this.defaultExperience = ko.observable<string>();
|
this.defaultExperience = ko.observable<string>();
|
||||||
this.databaseAccount.subscribe((databaseAccount) => {
|
// this.databaseAccount.subscribe((databaseAccount) => {
|
||||||
const defaultExperience: string = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(
|
// const defaultExperience: string = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(
|
||||||
databaseAccount
|
// databaseAccount
|
||||||
);
|
// );
|
||||||
this.defaultExperience(defaultExperience);
|
// this.defaultExperience(defaultExperience);
|
||||||
// TODO. Remove this entirely
|
// // TODO. Remove this entirely
|
||||||
updateUserContext({
|
// updateUserContext({
|
||||||
defaultExperience: DefaultExperienceUtility.mapDefaultExperienceStringToEnum(defaultExperience),
|
// apiType: DefaultExperienceUtility.mapDefaultExperienceStringToEnum(defaultExperience),
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.isFixedCollectionWithSharedThroughputSupported = ko.computed(() => {
|
this.isFixedCollectionWithSharedThroughputSupported = ko.computed(() => {
|
||||||
if (userContext.features.enableFixedCollectionWithSharedThroughput) {
|
if (userContext.features.enableFixedCollectionWithSharedThroughput) {
|
||||||
@@ -414,27 +403,6 @@ export default class Explorer {
|
|||||||
) !== undefined
|
) !== undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
this.isPreferredApiMongoDB = ko.computed(() => {
|
|
||||||
const defaultExperience = (this.defaultExperience && this.defaultExperience()) || "";
|
|
||||||
if (defaultExperience.toLowerCase() === Constants.DefaultAccountExperience.MongoDB.toLowerCase()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultExperience.toLowerCase() === Constants.DefaultAccountExperience.ApiForMongoDB.toLowerCase()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
this.databaseAccount &&
|
|
||||||
this.databaseAccount() &&
|
|
||||||
this.databaseAccount().kind.toLowerCase() === Constants.AccountKind.MongoDB
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.isEnableMongoCapabilityPresent = ko.computed(() => {
|
this.isEnableMongoCapabilityPresent = ko.computed(() => {
|
||||||
const capabilities = this.databaseAccount && this.databaseAccount()?.properties?.capabilities;
|
const capabilities = this.databaseAccount && this.databaseAccount()?.properties?.capabilities;
|
||||||
if (!capabilities) {
|
if (!capabilities) {
|
||||||
@@ -500,13 +468,6 @@ export default class Explorer {
|
|||||||
container: this,
|
container: this,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.editTableEntityPane = new EditTableEntityPane({
|
|
||||||
id: "edittableentitypane",
|
|
||||||
visible: ko.observable<boolean>(false),
|
|
||||||
|
|
||||||
container: this,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.cassandraAddCollectionPane = new CassandraAddCollectionPane({
|
this.cassandraAddCollectionPane = new CassandraAddCollectionPane({
|
||||||
id: "cassandraaddcollectionpane",
|
id: "cassandraaddcollectionpane",
|
||||||
visible: ko.observable<boolean>(false),
|
visible: ko.observable<boolean>(false),
|
||||||
@@ -514,13 +475,6 @@ export default class Explorer {
|
|||||||
container: this,
|
container: this,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.stringInputPane = new StringInputPane({
|
|
||||||
id: "stringinputpane",
|
|
||||||
visible: ko.observable<boolean>(false),
|
|
||||||
|
|
||||||
container: this,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.tabsManager = params?.tabsManager ?? new TabsManager();
|
this.tabsManager = params?.tabsManager ?? new TabsManager();
|
||||||
this.tabsManager.openedTabs.subscribe((tabs) => {
|
this.tabsManager.openedTabs.subscribe((tabs) => {
|
||||||
if (tabs.length === 0) {
|
if (tabs.length === 0) {
|
||||||
@@ -533,9 +487,7 @@ export default class Explorer {
|
|||||||
this.addDatabasePane,
|
this.addDatabasePane,
|
||||||
this.addCollectionPane,
|
this.addCollectionPane,
|
||||||
this.graphStylingPane,
|
this.graphStylingPane,
|
||||||
this.editTableEntityPane,
|
|
||||||
this.cassandraAddCollectionPane,
|
this.cassandraAddCollectionPane,
|
||||||
this.stringInputPane,
|
|
||||||
];
|
];
|
||||||
this.addDatabaseText.subscribe((addDatabaseText: string) => this.addDatabasePane.title(addDatabaseText));
|
this.addDatabaseText.subscribe((addDatabaseText: string) => this.addDatabasePane.title(addDatabaseText));
|
||||||
this.isTabsContentExpanded = ko.observable(false);
|
this.isTabsContentExpanded = ko.observable(false);
|
||||||
@@ -604,7 +556,6 @@ export default class Explorer {
|
|||||||
this.addCollectionPane.collectionIdTitle("Table id");
|
this.addCollectionPane.collectionIdTitle("Table id");
|
||||||
this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table");
|
this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table");
|
||||||
this.refreshTreeTitle("Refresh tables");
|
this.refreshTreeTitle("Refresh tables");
|
||||||
this.editTableEntityPane.title("Edit Table Entity");
|
|
||||||
this.tableDataClient = new TablesAPIDataClient();
|
this.tableDataClient = new TablesAPIDataClient();
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case "Cassandra":
|
||||||
@@ -618,7 +569,6 @@ export default class Explorer {
|
|||||||
this.addCollectionPane.collectionIdTitle("Table id");
|
this.addCollectionPane.collectionIdTitle("Table id");
|
||||||
this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table");
|
this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table");
|
||||||
this.refreshTreeTitle("Refresh tables");
|
this.refreshTreeTitle("Refresh tables");
|
||||||
this.editTableEntityPane.title("Edit Table Row");
|
|
||||||
this.tableDataClient = new CassandraAPIDataClient();
|
this.tableDataClient = new CassandraAPIDataClient();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -636,10 +586,10 @@ export default class Explorer {
|
|||||||
this.isNotebookEnabled = ko.observable(false);
|
this.isNotebookEnabled = ko.observable(false);
|
||||||
this.isNotebookEnabled.subscribe(async () => {
|
this.isNotebookEnabled.subscribe(async () => {
|
||||||
if (!this.notebookManager) {
|
if (!this.notebookManager) {
|
||||||
const notebookManagerModule = await import(
|
const NotebookManager = await (
|
||||||
/* webpackChunkName: "NotebookManager" */ "./Notebook/NotebookManager"
|
await import(/* webpackChunkName: "NotebookManager" */ "./Notebook/NotebookManager")
|
||||||
);
|
).default;
|
||||||
this.notebookManager = new notebookManagerModule.default();
|
this.notebookManager = new NotebookManager();
|
||||||
this.notebookManager.initialize({
|
this.notebookManager.initialize({
|
||||||
container: this,
|
container: this,
|
||||||
notebookBasePath: this.notebookBasePath,
|
notebookBasePath: this.notebookBasePath,
|
||||||
@@ -1424,10 +1374,13 @@ export default class Explorer {
|
|||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async publishNotebook(name: string, content: string | unknown, parentDomElement?: HTMLElement): Promise<void> {
|
public async publishNotebook(
|
||||||
|
name: string,
|
||||||
|
content: NotebookPaneContent,
|
||||||
|
parentDomElement?: HTMLElement
|
||||||
|
): Promise<void> {
|
||||||
if (this.notebookManager) {
|
if (this.notebookManager) {
|
||||||
await this.notebookManager.openPublishNotebookPane(name, content, parentDomElement);
|
await this.notebookManager.openPublishNotebookPane(name, content, parentDomElement);
|
||||||
this.publishNotebookPaneAdapter = this.notebookManager.publishNotebookPaneAdapter;
|
|
||||||
this.isPublishNotebookPaneEnabled(true);
|
this.isPublishNotebookPaneEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1540,7 +1493,7 @@ export default class Explorer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public renameNotebook(notebookFile: NotebookContentItem): Q.Promise<NotebookContentItem> {
|
public renameNotebook(notebookFile: NotebookContentItem): void {
|
||||||
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
||||||
const error = "Attempt to rename notebook, but notebook is not enabled";
|
const error = "Attempt to rename notebook, but notebook is not enabled";
|
||||||
handleError(error, "Explorer/renameNotebook");
|
handleError(error, "Explorer/renameNotebook");
|
||||||
@@ -1556,57 +1509,59 @@ export default class Explorer {
|
|||||||
);
|
);
|
||||||
if (openedNotebookTabs.length > 0) {
|
if (openedNotebookTabs.length > 0) {
|
||||||
this.showOkModalDialog("Unable to rename file", "This file is being edited. Please close the tab and try again.");
|
this.showOkModalDialog("Unable to rename file", "This file is being edited. Please close the tab and try again.");
|
||||||
return Q.reject();
|
} else {
|
||||||
|
this.openSidePanel(
|
||||||
|
"",
|
||||||
|
<StringInputPane
|
||||||
|
explorer={this}
|
||||||
|
closePanel={() => {
|
||||||
|
this.closeSidePanel();
|
||||||
|
this.resourceTree.triggerRender();
|
||||||
|
}}
|
||||||
|
inputLabel="Enter new notebook name"
|
||||||
|
submitButtonLabel="Rename"
|
||||||
|
errorMessage="Could not rename notebook"
|
||||||
|
inProgressMessage="Renaming notebook to"
|
||||||
|
successMessage="Renamed notebook to"
|
||||||
|
paneTitle="Rename Notebook"
|
||||||
|
defaultInput={FileSystemUtil.stripExtension(notebookFile.name, "ipynb")}
|
||||||
|
onSubmit={(notebookFile: NotebookContentItem, input: string): Promise<NotebookContentItem> =>
|
||||||
|
this.notebookManager?.notebookContentClient.renameNotebook(notebookFile, input)
|
||||||
|
}
|
||||||
|
notebookFile={notebookFile}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const originalPath = notebookFile.path;
|
|
||||||
const result = this.stringInputPane
|
|
||||||
.openWithOptions<NotebookContentItem>({
|
|
||||||
errorMessage: "Could not rename notebook",
|
|
||||||
inProgressMessage: "Renaming notebook to",
|
|
||||||
successMessage: "Renamed notebook to",
|
|
||||||
inputLabel: "Enter new notebook name",
|
|
||||||
paneTitle: "Rename Notebook",
|
|
||||||
submitButtonLabel: "Rename",
|
|
||||||
defaultInput: FileSystemUtil.stripExtension(notebookFile.name, "ipynb"),
|
|
||||||
onSubmit: (input: string) => this.notebookManager?.notebookContentClient.renameNotebook(notebookFile, input),
|
|
||||||
})
|
|
||||||
.then((newNotebookFile) => {
|
|
||||||
const notebookTabs = this.tabsManager.getTabs(
|
|
||||||
ViewModels.CollectionTabKind.NotebookV2,
|
|
||||||
(tab: NotebookV2Tab) => tab.notebookPath && FileSystemUtil.isPathEqual(tab.notebookPath(), originalPath)
|
|
||||||
);
|
|
||||||
notebookTabs.forEach((tab) => {
|
|
||||||
tab.tabTitle(newNotebookFile.name);
|
|
||||||
tab.tabPath(newNotebookFile.path);
|
|
||||||
(tab as NotebookV2Tab).notebookPath(newNotebookFile.path);
|
|
||||||
});
|
|
||||||
|
|
||||||
return newNotebookFile;
|
|
||||||
});
|
|
||||||
result.then(() => this.resourceTree.triggerRender());
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onCreateDirectory(parent: NotebookContentItem): Q.Promise<NotebookContentItem> {
|
public onCreateDirectory(parent: NotebookContentItem): void {
|
||||||
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
||||||
const error = "Attempt to create notebook directory, but notebook is not enabled";
|
const error = "Attempt to create notebook directory, but notebook is not enabled";
|
||||||
handleError(error, "Explorer/onCreateDirectory");
|
handleError(error, "Explorer/onCreateDirectory");
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = this.stringInputPane.openWithOptions<NotebookContentItem>({
|
this.openSidePanel(
|
||||||
errorMessage: "Could not create directory ",
|
"",
|
||||||
inProgressMessage: "Creating directory ",
|
<StringInputPane
|
||||||
successMessage: "Created directory ",
|
explorer={this}
|
||||||
inputLabel: "Enter new directory name",
|
closePanel={() => {
|
||||||
paneTitle: "Create new directory",
|
this.closeSidePanel();
|
||||||
submitButtonLabel: "Create",
|
this.resourceTree.triggerRender();
|
||||||
defaultInput: "",
|
}}
|
||||||
onSubmit: (input: string) => this.notebookManager?.notebookContentClient.createDirectory(parent, input),
|
errorMessage="Could not create directory "
|
||||||
});
|
inProgressMessage="Creating directory "
|
||||||
result.then(() => this.resourceTree.triggerRender());
|
successMessage="Created directory "
|
||||||
return result;
|
inputLabel="Enter new directory name"
|
||||||
|
paneTitle="Create new directory"
|
||||||
|
submitButtonLabel="Create"
|
||||||
|
defaultInput=""
|
||||||
|
onSubmit={(notebookFile: NotebookContentItem, input: string): Promise<NotebookContentItem> =>
|
||||||
|
this.notebookManager?.notebookContentClient.createDirectory(notebookFile, input)
|
||||||
|
}
|
||||||
|
notebookFile={parent}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readFile(notebookFile: NotebookContentItem): Promise<string> {
|
public readFile(notebookFile: NotebookContentItem): Promise<string> {
|
||||||
@@ -1922,86 +1877,68 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async openGallery(
|
public async openGallery(
|
||||||
selectedTab?: GalleryTab,
|
selectedTab?: GalleryTabKind,
|
||||||
notebookUrl?: string,
|
notebookUrl?: string,
|
||||||
galleryItem?: IGalleryItem,
|
galleryItem?: IGalleryItem,
|
||||||
isFavorite?: boolean
|
isFavorite?: boolean
|
||||||
) {
|
) {
|
||||||
let title: string = "Gallery";
|
const title = "Gallery";
|
||||||
let hashLocation: string = "gallery";
|
const hashLocation = "gallery";
|
||||||
|
const GalleryTab = await (await import(/* webpackChunkName: "GalleryTab" */ "./Tabs/GalleryTab")).default;
|
||||||
|
const galleryTab = this.tabsManager
|
||||||
|
.getTabs(ViewModels.CollectionTabKind.Gallery)
|
||||||
|
.find((tab) => tab.hashLocation() == hashLocation);
|
||||||
|
|
||||||
const galleryTabOptions: any = {
|
if (galleryTab instanceof GalleryTab) {
|
||||||
// GalleryTabOptions
|
|
||||||
account: userContext.databaseAccount,
|
|
||||||
container: this,
|
|
||||||
junoClient: this.notebookManager?.junoClient,
|
|
||||||
selectedTab: selectedTab || GalleryTab.PublicGallery,
|
|
||||||
notebookUrl,
|
|
||||||
galleryItem,
|
|
||||||
isFavorite,
|
|
||||||
// TabOptions
|
|
||||||
tabKind: ViewModels.CollectionTabKind.Gallery,
|
|
||||||
title: title,
|
|
||||||
tabPath: title,
|
|
||||||
documentClientUtility: null,
|
|
||||||
isActive: ko.observable(false),
|
|
||||||
hashLocation: hashLocation,
|
|
||||||
onUpdateTabsButtons: this.onUpdateTabsButtons,
|
|
||||||
isTabsContentExpanded: ko.observable(true),
|
|
||||||
onLoadStartKey: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const galleryTabs = this.tabsManager.getTabs(
|
|
||||||
ViewModels.CollectionTabKind.Gallery,
|
|
||||||
(tab) => tab.hashLocation() == hashLocation
|
|
||||||
);
|
|
||||||
let galleryTab = galleryTabs && galleryTabs[0];
|
|
||||||
|
|
||||||
if (galleryTab) {
|
|
||||||
this.tabsManager.activateTab(galleryTab);
|
this.tabsManager.activateTab(galleryTab);
|
||||||
(galleryTab as any).reset(galleryTabOptions);
|
|
||||||
} else {
|
} else {
|
||||||
if (!this.galleryTab) {
|
this.tabsManager.activateNewTab(
|
||||||
this.galleryTab = await import(/* webpackChunkName: "GalleryTab" */ "./Tabs/GalleryTab");
|
new GalleryTab(
|
||||||
}
|
{
|
||||||
const newTab = new this.galleryTab.default(galleryTabOptions);
|
tabKind: ViewModels.CollectionTabKind.Gallery,
|
||||||
this.tabsManager.activateNewTab(newTab);
|
title: title,
|
||||||
|
tabPath: title,
|
||||||
|
hashLocation: hashLocation,
|
||||||
|
onUpdateTabsButtons: this.onUpdateTabsButtons,
|
||||||
|
onLoadStartKey: null,
|
||||||
|
isTabsContentExpanded: ko.observable(true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
account: userContext.databaseAccount,
|
||||||
|
container: this,
|
||||||
|
junoClient: this.notebookManager?.junoClient,
|
||||||
|
selectedTab: selectedTab || GalleryTabKind.PublicGallery,
|
||||||
|
notebookUrl,
|
||||||
|
galleryItem,
|
||||||
|
isFavorite,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async openNotebookViewer(notebookUrl: string) {
|
public async openNotebookViewer(notebookUrl: string) {
|
||||||
const title = path.basename(notebookUrl);
|
const title = path.basename(notebookUrl);
|
||||||
const hashLocation = notebookUrl;
|
const hashLocation = notebookUrl;
|
||||||
|
const NotebookViewerTab = await (
|
||||||
|
await import(/* webpackChunkName: "NotebookViewerTab" */ "./Tabs/NotebookViewerTab")
|
||||||
|
).default;
|
||||||
|
|
||||||
if (!this.notebookViewerTab) {
|
const notebookViewerTab = this.tabsManager.getTabs(ViewModels.CollectionTabKind.NotebookV2).find((tab) => {
|
||||||
this.notebookViewerTab = await import(/* webpackChunkName: "NotebookViewerTab" */ "./Tabs/NotebookViewerTab");
|
return tab.hashLocation() == hashLocation && tab instanceof NotebookViewerTab && tab.notebookUrl === notebookUrl;
|
||||||
}
|
|
||||||
|
|
||||||
const notebookViewerTabModule = this.notebookViewerTab;
|
|
||||||
|
|
||||||
let isNotebookViewerOpen = (tab: TabsBase) => {
|
|
||||||
const notebookViewerTab = tab as typeof notebookViewerTabModule.default;
|
|
||||||
return notebookViewerTab.notebookUrl === notebookUrl;
|
|
||||||
};
|
|
||||||
|
|
||||||
const notebookViewerTabs = this.tabsManager.getTabs(ViewModels.CollectionTabKind.NotebookV2, (tab) => {
|
|
||||||
return tab.hashLocation() == hashLocation && isNotebookViewerOpen(tab);
|
|
||||||
});
|
});
|
||||||
let notebookViewerTab = notebookViewerTabs && notebookViewerTabs[0];
|
|
||||||
|
|
||||||
if (notebookViewerTab) {
|
if (notebookViewerTab) {
|
||||||
this.tabsManager.activateNewTab(notebookViewerTab);
|
this.tabsManager.activateNewTab(notebookViewerTab);
|
||||||
} else {
|
} else {
|
||||||
notebookViewerTab = new this.notebookViewerTab.default({
|
const notebookViewerTab = new NotebookViewerTab({
|
||||||
account: userContext.databaseAccount,
|
account: userContext.databaseAccount,
|
||||||
tabKind: ViewModels.CollectionTabKind.NotebookViewer,
|
tabKind: ViewModels.CollectionTabKind.NotebookViewer,
|
||||||
node: null,
|
node: null,
|
||||||
title: title,
|
title: title,
|
||||||
tabPath: title,
|
tabPath: title,
|
||||||
documentClientUtility: null,
|
|
||||||
collection: null,
|
collection: null,
|
||||||
hashLocation: hashLocation,
|
hashLocation: hashLocation,
|
||||||
isActive: ko.observable(false),
|
|
||||||
isTabsContentExpanded: ko.observable(true),
|
isTabsContentExpanded: ko.observable(true),
|
||||||
onLoadStartKey: null,
|
onLoadStartKey: null,
|
||||||
onUpdateTabsButtons: this.onUpdateTabsButtons,
|
onUpdateTabsButtons: this.onUpdateTabsButtons,
|
||||||
@@ -2013,14 +1950,14 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onNewCollectionClicked(): void {
|
public onNewCollectionClicked(databaseId?: string): void {
|
||||||
if (userContext.apiType === "Cassandra") {
|
if (userContext.apiType === "Cassandra") {
|
||||||
this.cassandraAddCollectionPane.open();
|
this.cassandraAddCollectionPane.open();
|
||||||
} else if (userContext.features.enableReactPane) {
|
} else if (userContext.features.enableKOPanel) {
|
||||||
this.openAddCollectionPanel();
|
|
||||||
} else {
|
|
||||||
this.addCollectionPane.open(this.selectedDatabaseId());
|
this.addCollectionPane.open(this.selectedDatabaseId());
|
||||||
document.getElementById("linkAddCollection").focus();
|
document.getElementById("linkAddCollection").focus();
|
||||||
|
} else {
|
||||||
|
this.openAddCollectionPanel(databaseId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2124,14 +2061,9 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public openDeleteCollectionConfirmationPane(): void {
|
public openDeleteCollectionConfirmationPane(): void {
|
||||||
let collectionName = PricingUtils.getCollectionName(userContext.defaultExperience);
|
|
||||||
this.openSidePanel(
|
this.openSidePanel(
|
||||||
"Delete " + collectionName,
|
"Delete " + getCollectionName(),
|
||||||
<DeleteCollectionConfirmationPane
|
<DeleteCollectionConfirmationPane explorer={this} closePanel={this.closeSidePanel} />
|
||||||
explorer={this}
|
|
||||||
collectionName={collectionName}
|
|
||||||
closePanel={this.closeSidePanel}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2152,28 +2084,32 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public openSettingPane(): void {
|
public openSettingPane(): void {
|
||||||
this.openSidePanel("Settings", <SettingsPane explorer={this} closePanel={this.closeSidePanel} />);
|
this.openSidePanel(
|
||||||
|
"Settings",
|
||||||
|
<SettingsPane expandConsole={() => this.expandConsole()} closePanel={this.closeSidePanel} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public openExecuteSprocParamsPanel(storedProcedure: StoredProcedure): void {
|
public openExecuteSprocParamsPanel(storedProcedure: StoredProcedure): void {
|
||||||
this.openSidePanel(
|
this.openSidePanel(
|
||||||
"Input parameters",
|
"Input parameters",
|
||||||
<ExecuteSprocParamsPane
|
<ExecuteSprocParamsPane
|
||||||
explorer={this}
|
|
||||||
storedProcedure={storedProcedure}
|
storedProcedure={storedProcedure}
|
||||||
|
expandConsole={() => this.expandConsole()}
|
||||||
closePanel={() => this.closeSidePanel()}
|
closePanel={() => this.closeSidePanel()}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async openAddCollectionPanel(): Promise<void> {
|
public async openAddCollectionPanel(databaseId?: string): Promise<void> {
|
||||||
await this.loadDatabaseOffers();
|
await this.loadDatabaseOffers();
|
||||||
this.openSidePanel(
|
this.openSidePanel(
|
||||||
"New Collection",
|
"New " + getCollectionName(),
|
||||||
<AddCollectionPanel
|
<AddCollectionPanel
|
||||||
explorer={this}
|
explorer={this}
|
||||||
closePanel={() => this.closeSidePanel()}
|
closePanel={() => this.closeSidePanel()}
|
||||||
openNotificationConsole={() => this.expandConsole()}
|
openNotificationConsole={() => this.expandConsole()}
|
||||||
|
databaseId={databaseId}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2195,7 +2131,7 @@ export default class Explorer {
|
|||||||
this.openSidePanel(
|
this.openSidePanel(
|
||||||
"Upload File",
|
"Upload File",
|
||||||
<UploadFilePane
|
<UploadFilePane
|
||||||
explorer={this}
|
expandConsole={() => this.expandConsole()}
|
||||||
closePanel={this.closeSidePanel}
|
closePanel={this.closeSidePanel}
|
||||||
uploadFile={(name: string, content: string) => this.uploadFile(name, content, parent)}
|
uploadFile={(name: string, content: string) => this.uploadFile(name, content, parent)}
|
||||||
/>
|
/>
|
||||||
@@ -2227,6 +2163,19 @@ export default class Explorer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public openTableSelectQueryPanel(queryViewModal: QueryViewModel): void {
|
public openTableSelectQueryPanel(queryViewModal: QueryViewModel): void {
|
||||||
this.openSidePanel(
|
this.openSidePanel(
|
||||||
"Select Column",
|
"Select Column",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import * as ko from "knockout";
|
|||||||
import Q from "q";
|
import Q from "q";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { HashMap } from "../../../Common/HashMap";
|
|
||||||
import { NeighborType } from "../../../Contracts/ViewModels";
|
import { NeighborType } from "../../../Contracts/ViewModels";
|
||||||
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { GraphConfig } from "../../Tabs/GraphTab";
|
import { GraphConfig } from "../../Tabs/GraphTab";
|
||||||
@@ -195,8 +194,8 @@ export class D3ForceGraph implements GraphRenderer {
|
|||||||
* Count edges and store in a hashmap: vertex id <--> number of links
|
* Count edges and store in a hashmap: vertex id <--> number of links
|
||||||
* @param linkSelection
|
* @param linkSelection
|
||||||
*/
|
*/
|
||||||
public static countEdges(links: D3Link[]): HashMap<number> {
|
public static countEdges(links: D3Link[]): Map<string, number> {
|
||||||
const countMap = new HashMap<number>();
|
const countMap = new Map<string, number>();
|
||||||
links.forEach((l: D3Link) => {
|
links.forEach((l: D3Link) => {
|
||||||
let val = countMap.get(l.inV) || 0;
|
let val = countMap.get(l.inV) || 0;
|
||||||
val += 1;
|
val += 1;
|
||||||
@@ -407,7 +406,7 @@ export class D3ForceGraph implements GraphRenderer {
|
|||||||
const rootId = graph.findRootNodeId();
|
const rootId = graph.findRootNodeId();
|
||||||
|
|
||||||
// Remember nodes current position
|
// Remember nodes current position
|
||||||
const posMap = new HashMap<Point2D>();
|
const posMap = new Map<string, Point2D>();
|
||||||
this.simulation.nodes().forEach((d: D3Node) => {
|
this.simulation.nodes().forEach((d: D3Node) => {
|
||||||
if (d.x == undefined || d.y == undefined) {
|
if (d.x == undefined || d.y == undefined) {
|
||||||
return;
|
return;
|
||||||
@@ -501,8 +500,8 @@ export class D3ForceGraph implements GraphRenderer {
|
|||||||
if (!nodes || nodes.length === 0) {
|
if (!nodes || nodes.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nodeFinalPositionMap = new HashMap<Point2D>();
|
|
||||||
|
|
||||||
|
const nodeFinalPositionMap = new Map<string, Point2D>();
|
||||||
const viewCenter = this.viewCenter;
|
const viewCenter = this.viewCenter;
|
||||||
const nonFixedNodes = _.filter(nodes, (node: D3Node) => {
|
const nonFixedNodes = _.filter(nodes, (node: D3Node) => {
|
||||||
return !node._isFixedPosition && node.x === viewCenter.x && node.y === viewCenter.y;
|
return !node._isFixedPosition && node.x === viewCenter.x && node.y === viewCenter.y;
|
||||||
@@ -559,7 +558,7 @@ export class D3ForceGraph implements GraphRenderer {
|
|||||||
newNodes.selectAll(".loadmore").attr("visibility", "hidden").transition().delay(600).attr("visibility", "visible");
|
newNodes.selectAll(".loadmore").attr("visibility", "hidden").transition().delay(600).attr("visibility", "visible");
|
||||||
}
|
}
|
||||||
|
|
||||||
private restartSimulation(graph: GraphData<D3Node, D3Link>, posMap: HashMap<Point2D>) {
|
private restartSimulation(graph: GraphData<D3Node, D3Link>, posMap: Map<string, Point2D>) {
|
||||||
if (!graph) {
|
if (!graph) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ObjectCache } from "../../../Common/ObjectCache";
|
import { ObjectCache } from "../../../Common/ObjectCache";
|
||||||
import { GremlinVertex, GraphData } from "./GraphData";
|
import { GraphData, GremlinVertex } from "./GraphData";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remember vertex edge information
|
* Remember vertex edge information
|
||||||
@@ -10,9 +10,8 @@ export class EdgeInfoCache extends ObjectCache<GremlinVertex> {
|
|||||||
* @param vertex
|
* @param vertex
|
||||||
*/
|
*/
|
||||||
public addVertex(vertex: GremlinVertex): void {
|
public addVertex(vertex: GremlinVertex): void {
|
||||||
let v: GremlinVertex;
|
let v = super.get(vertex.id);
|
||||||
if (super.has(vertex.id)) {
|
if (super.has(vertex.id) && v) {
|
||||||
v = super.get(vertex.id);
|
|
||||||
GraphData.addEdgeInfoToVertex(v, vertex);
|
GraphData.addEdgeInfoToVertex(v, vertex);
|
||||||
v._outEdgeIds = vertex._outEdgeIds;
|
v._outEdgeIds = vertex._outEdgeIds;
|
||||||
v._inEdgeIds = vertex._inEdgeIds;
|
v._inEdgeIds = vertex._inEdgeIds;
|
||||||
@@ -29,8 +28,8 @@ export class EdgeInfoCache extends ObjectCache<GremlinVertex> {
|
|||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
public mergeEdgeInfo(target: GremlinVertex): void {
|
public mergeEdgeInfo(target: GremlinVertex): void {
|
||||||
if (super.has(target.id)) {
|
const cachedVertex = super.get(target.id);
|
||||||
const cachedVertex = super.get(target.id);
|
if (super.has(target.id) && cachedVertex) {
|
||||||
GraphData.addEdgeInfoToVertex(target, cachedVertex);
|
GraphData.addEdgeInfoToVertex(target, cachedVertex);
|
||||||
target._outEdgeIds = cachedVertex._outEdgeIds;
|
target._outEdgeIds = cachedVertex._outEdgeIds;
|
||||||
target._inEdgeIds = cachedVertex._inEdgeIds;
|
target._inEdgeIds = cachedVertex._inEdgeIds;
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
|
||||||
import { GraphConfig } from "../../Tabs/GraphTab";
|
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
|
||||||
import { GraphExplorer, GraphAccessor } from "./GraphExplorer";
|
|
||||||
|
|
||||||
interface Parameter {
|
|
||||||
onIsNewVertexDisabledChange: (isEnabled: boolean) => void;
|
|
||||||
onGraphAccessorCreated: (instance: GraphAccessor) => void;
|
|
||||||
onIsFilterQueryLoading: (isFilterQueryLoading: boolean) => void;
|
|
||||||
onIsValidQuery: (isValidQuery: boolean) => void;
|
|
||||||
onIsPropertyEditing: (isEditing: boolean) => void;
|
|
||||||
onIsGraphDisplayed: (isDisplayed: boolean) => void;
|
|
||||||
onResetDefaultGraphConfigValues: () => void;
|
|
||||||
|
|
||||||
graphConfigUiData: ViewModels.GraphConfigUiData;
|
|
||||||
graphConfig?: GraphConfig;
|
|
||||||
|
|
||||||
collectionPartitionKeyProperty: string;
|
|
||||||
graphBackendEndpoint: string;
|
|
||||||
databaseId: string;
|
|
||||||
collectionId: string;
|
|
||||||
masterKey: string;
|
|
||||||
|
|
||||||
onLoadStartKey: number;
|
|
||||||
onLoadStartKeyChange: (newKey: number) => void;
|
|
||||||
resourceId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GraphExplorerAdapter implements ReactAdapter {
|
|
||||||
public params: Parameter;
|
|
||||||
public parameters = {};
|
|
||||||
public isNewVertexDisabled: boolean;
|
|
||||||
|
|
||||||
public constructor(params: Parameter) {
|
|
||||||
this.params = params;
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderComponent(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<GraphExplorer
|
|
||||||
onIsNewVertexDisabledChange={this.params.onIsNewVertexDisabledChange}
|
|
||||||
onGraphAccessorCreated={this.params.onGraphAccessorCreated}
|
|
||||||
onIsFilterQueryLoadingChange={this.params.onIsFilterQueryLoading}
|
|
||||||
onIsValidQueryChange={this.params.onIsValidQuery}
|
|
||||||
onIsPropertyEditing={this.params.onIsPropertyEditing}
|
|
||||||
onIsGraphDisplayed={this.params.onIsGraphDisplayed}
|
|
||||||
onResetDefaultGraphConfigValues={this.params.onResetDefaultGraphConfigValues}
|
|
||||||
collectionPartitionKeyProperty={this.params.collectionPartitionKeyProperty}
|
|
||||||
graphBackendEndpoint={this.params.graphBackendEndpoint}
|
|
||||||
databaseId={this.params.databaseId}
|
|
||||||
collectionId={this.params.collectionId}
|
|
||||||
masterKey={this.params.masterKey}
|
|
||||||
onLoadStartKey={this.params.onLoadStartKey}
|
|
||||||
onLoadStartKeyChange={this.params.onLoadStartKeyChange}
|
|
||||||
resourceId={this.params.resourceId}
|
|
||||||
/* TODO Figure out how to make this Knockout-free */
|
|
||||||
graphConfigUiData={this.params.graphConfigUiData}
|
|
||||||
graphConfig={this.params.graphConfig}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as sinon from "sinon";
|
import * as sinon from "sinon";
|
||||||
import { GremlinClient, GremlinClientParameters } from "./GremlinClient";
|
|
||||||
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
|
||||||
import * as Logger from "../../../Common/Logger";
|
import * as Logger from "../../../Common/Logger";
|
||||||
|
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
||||||
|
import { GremlinClient, GremlinClientParameters } from "./GremlinClient";
|
||||||
|
|
||||||
describe("Gremlin Client", () => {
|
describe("Gremlin Client", () => {
|
||||||
const emptyParams: GremlinClientParameters = {
|
const emptyParams: GremlinClientParameters = {
|
||||||
@@ -70,7 +70,7 @@ describe("Gremlin Client", () => {
|
|||||||
gremlinClient.execute("fake query");
|
gremlinClient.execute("fake query");
|
||||||
gremlinClient.execute("fake query");
|
gremlinClient.execute("fake query");
|
||||||
gremlinClient.execute("fake query");
|
gremlinClient.execute("fake query");
|
||||||
expect(gremlinClient.pendingResults.size()).toBe(3);
|
expect(gremlinClient.pendingResults.size).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should clean up pending request ids after success", async () => {
|
it("should clean up pending request ids after success", async () => {
|
||||||
@@ -89,7 +89,7 @@ describe("Gremlin Client", () => {
|
|||||||
return requestId;
|
return requestId;
|
||||||
});
|
});
|
||||||
await gremlinClient.execute("fake query");
|
await gremlinClient.execute("fake query");
|
||||||
expect(gremlinClient.pendingResults.size()).toBe(0);
|
expect(gremlinClient.pendingResults.size).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should log and display error out on unknown requestId", () => {
|
it("should log and display error out on unknown requestId", () => {
|
||||||
@@ -247,7 +247,7 @@ describe("Gremlin Client", () => {
|
|||||||
sinon.stub(gremlinClient.client, "executeGremlinQuery").callsFake((query: string): string => requestId);
|
sinon.stub(gremlinClient.client, "executeGremlinQuery").callsFake((query: string): string => requestId);
|
||||||
gremlinClient.execute("fake query").finally(() => {
|
gremlinClient.execute("fake query").finally(() => {
|
||||||
try {
|
try {
|
||||||
expect(gremlinClient.pendingResults.size()).toBe(0);
|
expect(gremlinClient.pendingResults.size).toBe(0);
|
||||||
done();
|
done();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
done(e);
|
done(e);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import * as Q from "q";
|
import * as Q from "q";
|
||||||
import { getErrorMessage, handleError } from "../../../Common/ErrorHandlingUtils";
|
import { getErrorMessage, handleError } from "../../../Common/ErrorHandlingUtils";
|
||||||
import { HashMap } from "../../../Common/HashMap";
|
|
||||||
import { logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
|
import { logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { GremlinSimpleClient, Result } from "./GremlinSimpleClient";
|
import { GremlinSimpleClient, Result } from "./GremlinSimpleClient";
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ interface PendingResultData {
|
|||||||
|
|
||||||
export class GremlinClient {
|
export class GremlinClient {
|
||||||
public client: GremlinSimpleClient;
|
public client: GremlinSimpleClient;
|
||||||
public pendingResults: HashMap<PendingResultData>; // public for testing purposes
|
public pendingResults: Map<string, PendingResultData>; // public for testing purposes
|
||||||
private maxResultSize: number;
|
private maxResultSize: number;
|
||||||
private static readonly PENDING_REQUEST_TIMEOUT_MS = 6 /* minutes */ * 60 /* seconds */ * 1000 /* ms */;
|
private static readonly PENDING_REQUEST_TIMEOUT_MS = 6 /* minutes */ * 60 /* seconds */ * 1000 /* ms */;
|
||||||
private static readonly TIMEOUT_ERROR_MSG = `Pending request timed out (${GremlinClient.PENDING_REQUEST_TIMEOUT_MS} ms)`;
|
private static readonly TIMEOUT_ERROR_MSG = `Pending request timed out (${GremlinClient.PENDING_REQUEST_TIMEOUT_MS} ms)`;
|
||||||
@@ -38,7 +37,7 @@ export class GremlinClient {
|
|||||||
|
|
||||||
public initialize(params: GremlinClientParameters) {
|
public initialize(params: GremlinClientParameters) {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
this.pendingResults = new HashMap();
|
this.pendingResults = new Map();
|
||||||
this.maxResultSize = params.maxResultSize;
|
this.maxResultSize = params.maxResultSize;
|
||||||
|
|
||||||
this.client = new GremlinSimpleClient({
|
this.client = new GremlinSimpleClient({
|
||||||
@@ -68,9 +67,9 @@ export class GremlinClient {
|
|||||||
|
|
||||||
// Fail all pending requests if no request id (fatal)
|
// Fail all pending requests if no request id (fatal)
|
||||||
if (!requestId) {
|
if (!requestId) {
|
||||||
this.pendingResults.keys().forEach((reqId: string) => {
|
for (const reqId of this.pendingResults.keys()) {
|
||||||
this.abortPendingRequest(reqId, errorMessage, null);
|
this.abortPendingRequest(reqId, errorMessage, null);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.abortPendingRequest(requestId, errorMessage, result.requestCharge);
|
this.abortPendingRequest(requestId, errorMessage, result.requestCharge);
|
||||||
|
|||||||
5
src/Explorer/LazyMonaco.ts
Normal file
5
src/Explorer/LazyMonaco.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import type * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
||||||
|
export type { monaco };
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
export const loadMonaco = () => import(/* webpackChunkName: "lazy-monaco" */ "monaco-editor/esm/vs/editor/editor.api");
|
||||||
@@ -29,7 +29,6 @@ export class CommandBarComponentAdapter implements ReactAdapter {
|
|||||||
|
|
||||||
// These are the parameters watched by the react binding that will trigger a renderComponent() if one of the ko mutates
|
// These are the parameters watched by the react binding that will trigger a renderComponent() if one of the ko mutates
|
||||||
const toWatch = [
|
const toWatch = [
|
||||||
container.isPreferredApiMongoDB,
|
|
||||||
container.deleteCollectionText,
|
container.deleteCollectionText,
|
||||||
container.deleteDatabaseText,
|
container.deleteDatabaseText,
|
||||||
container.addCollectionText,
|
container.addCollectionText,
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
},
|
},
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
|
||||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
|
|
||||||
@@ -67,7 +66,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
},
|
},
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
@@ -128,6 +126,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockExplorer = {} as Explorer;
|
mockExplorer = {} as Explorer;
|
||||||
|
mockExplorer.addDatabaseText = ko.observable("mockText");
|
||||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
@@ -143,16 +142,25 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
mockExplorer.isServerlessEnabled = ko.computed<boolean>(() => false);
|
mockExplorer.isServerlessEnabled = ko.computed<boolean>(() => false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
updateUserContext({
|
||||||
|
apiType: "SQL",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => true);
|
updateUserContext({
|
||||||
|
apiType: "Mongo",
|
||||||
|
});
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||||
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Mongo Api not available - button should be hidden", () => {
|
it("Mongo Api not available - button should be hidden", () => {
|
||||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
updateUserContext({
|
||||||
|
apiType: "SQL",
|
||||||
|
});
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeUndefined();
|
expect(openMongoShellBtn).toBeUndefined();
|
||||||
@@ -222,7 +230,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
},
|
},
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||||
|
|
||||||
@@ -321,7 +328,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
},
|
},
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
|
||||||
|
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export function createStaticCommandBarButtons(container: Explorer): CommandButto
|
|||||||
buttons.push(createEnableNotebooksButton(container));
|
buttons.push(createEnableNotebooksButton(container));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
buttons.push(createOpenMongoTerminalButton(container));
|
buttons.push(createOpenMongoTerminalButton(container));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ export function createStaticCommandBarButtons(container: Explorer): CommandButto
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isSupportedOpenQueryApi =
|
const isSupportedOpenQueryApi =
|
||||||
userContext.apiType === "SQL" || container.isPreferredApiMongoDB() || userContext.apiType === "Gremlin";
|
userContext.apiType === "SQL" || userContext.apiType === "Mongo" || userContext.apiType === "Gremlin";
|
||||||
const isSupportedOpenQueryFromDiskApi = userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
const isSupportedOpenQueryFromDiskApi = userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
||||||
if (isSupportedOpenQueryApi && container.selectedNode() && container.findSelectedCollection()) {
|
if (isSupportedOpenQueryApi && container.selectedNode() && container.findSelectedCollection()) {
|
||||||
const openQueryBtn = createOpenQueryButton(container);
|
const openQueryBtn = createOpenQueryButton(container);
|
||||||
@@ -133,7 +133,7 @@ export function createStaticCommandBarButtons(container: Explorer): CommandButto
|
|||||||
export function createContextCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
|
export function createContextCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
|
||||||
const buttons: CommandButtonComponentProps[] = [];
|
const buttons: CommandButtonComponentProps[] = [];
|
||||||
|
|
||||||
if (!container.isDatabaseNodeOrNoneSelected() && container.isPreferredApiMongoDB()) {
|
if (!container.isDatabaseNodeOrNoneSelected() && userContext.apiType === "Mongo") {
|
||||||
const label = "New Shell";
|
const label = "New Shell";
|
||||||
const newMongoShellBtn: CommandButtonComponentProps = {
|
const newMongoShellBtn: CommandButtonComponentProps = {
|
||||||
iconSrc: HostedTerminalIcon,
|
iconSrc: HostedTerminalIcon,
|
||||||
@@ -145,7 +145,7 @@ export function createContextCommandBarButtons(container: Explorer): CommandButt
|
|||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected() && container.isPreferredApiMongoDB(),
|
disabled: container.isDatabaseNodeOrNoneSelected() && userContext.apiType === "Mongo",
|
||||||
};
|
};
|
||||||
buttons.push(newMongoShellBtn);
|
buttons.push(newMongoShellBtn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ let fakeAjaxResponse: AjaxResponse = {
|
|||||||
responseType: "json",
|
responseType: "json",
|
||||||
};
|
};
|
||||||
export const sessions = {
|
export const sessions = {
|
||||||
create: (serverConfig: unknown, body: object): Observable<AjaxResponse> => of(fakeAjaxResponse),
|
create: (): Observable<AjaxResponse> => of(fakeAjaxResponse),
|
||||||
__setResponse: (response: AjaxResponse) => {
|
__setResponse: (response: AjaxResponse) => {
|
||||||
fakeAjaxResponse = response;
|
fakeAjaxResponse = response;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ export class NotebookContentClient {
|
|||||||
return this.contentProvider
|
return this.contentProvider
|
||||||
.remove(this.getServerConfig(), path)
|
.remove(this.getServerConfig(), path)
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then((xhr: AjaxResponse) => path);
|
.then(() => path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ImmutableNotebook } from "@nteract/commutable";
|
import { ImmutableNotebook } from "@nteract/commutable";
|
||||||
import { IContentProvider } from "@nteract/core";
|
import type { IContentProvider } from "@nteract/core";
|
||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { contents } from "rx-jupyter";
|
import { contents } from "rx-jupyter";
|
||||||
@@ -22,12 +22,16 @@ import Explorer from "../Explorer";
|
|||||||
import { ContextualPaneBase } from "../Panes/ContextualPaneBase";
|
import { ContextualPaneBase } from "../Panes/ContextualPaneBase";
|
||||||
import { CopyNotebookPane } from "../Panes/CopyNotebookPane/CopyNotebookPane";
|
import { CopyNotebookPane } from "../Panes/CopyNotebookPane/CopyNotebookPane";
|
||||||
import { GitHubReposPane } from "../Panes/GitHubReposPane";
|
import { GitHubReposPane } from "../Panes/GitHubReposPane";
|
||||||
import { PublishNotebookPaneAdapter } from "../Panes/PublishNotebookPaneAdapter";
|
import { PublishNotebookPane } from "../Panes/PublishNotebookPane/PublishNotebookPane";
|
||||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
||||||
import { NotebookContentProvider } from "./NotebookComponent/NotebookContentProvider";
|
import { NotebookContentProvider } from "./NotebookComponent/NotebookContentProvider";
|
||||||
import { NotebookContainerClient } from "./NotebookContainerClient";
|
import { NotebookContainerClient } from "./NotebookContainerClient";
|
||||||
import { NotebookContentClient } from "./NotebookContentClient";
|
import { NotebookContentClient } from "./NotebookContentClient";
|
||||||
|
|
||||||
|
type NotebookPaneContent = string | ImmutableNotebook;
|
||||||
|
|
||||||
|
export type { NotebookPaneContent };
|
||||||
|
|
||||||
export interface NotebookManagerOptions {
|
export interface NotebookManagerOptions {
|
||||||
container: Explorer;
|
container: Explorer;
|
||||||
notebookBasePath: ko.Observable<string>;
|
notebookBasePath: ko.Observable<string>;
|
||||||
@@ -49,7 +53,6 @@ export default class NotebookManager {
|
|||||||
private gitHubClient: GitHubClient;
|
private gitHubClient: GitHubClient;
|
||||||
|
|
||||||
public gitHubReposPane: ContextualPaneBase;
|
public gitHubReposPane: ContextualPaneBase;
|
||||||
public publishNotebookPaneAdapter: PublishNotebookPaneAdapter;
|
|
||||||
|
|
||||||
public initialize(params: NotebookManagerOptions): void {
|
public initialize(params: NotebookManagerOptions): void {
|
||||||
this.params = params;
|
this.params = params;
|
||||||
@@ -87,8 +90,6 @@ export default class NotebookManager {
|
|||||||
this.notebookContentProvider
|
this.notebookContentProvider
|
||||||
);
|
);
|
||||||
|
|
||||||
this.publishNotebookPaneAdapter = new PublishNotebookPaneAdapter(this.params.container, this.junoClient);
|
|
||||||
|
|
||||||
this.gitHubOAuthService.getTokenObservable().subscribe((token) => {
|
this.gitHubOAuthService.getTokenObservable().subscribe((token) => {
|
||||||
this.gitHubClient.setToken(token?.access_token);
|
this.gitHubClient.setToken(token?.access_token);
|
||||||
|
|
||||||
@@ -116,10 +117,23 @@ export default class NotebookManager {
|
|||||||
|
|
||||||
public async openPublishNotebookPane(
|
public async openPublishNotebookPane(
|
||||||
name: string,
|
name: string,
|
||||||
content: string | ImmutableNotebook,
|
content: NotebookPaneContent,
|
||||||
parentDomElement: HTMLElement
|
parentDomElement: HTMLElement
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.publishNotebookPaneAdapter.open(name, getFullName(), content, parentDomElement);
|
const explorer = this.params.container;
|
||||||
|
explorer.openSidePanel(
|
||||||
|
"New Collection",
|
||||||
|
<PublishNotebookPane
|
||||||
|
explorer={this.params.container}
|
||||||
|
junoClient={this.junoClient}
|
||||||
|
closePanel={this.params.container.closeSidePanel}
|
||||||
|
openNotificationConsole={this.params.container.expandConsole}
|
||||||
|
name={name}
|
||||||
|
author={getFullName()}
|
||||||
|
notebookContent={content}
|
||||||
|
parentDomElement={parentDomElement}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public openCopyNotebookPane(name: string, content: string): void {
|
public openCopyNotebookPane(name: string, content: string): void {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { ActionContracts } from "../Contracts/ExplorerContracts";
|
|||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import Explorer from "./Explorer";
|
import Explorer from "./Explorer";
|
||||||
import { handleOpenAction } from "./OpenActions";
|
import { handleOpenAction } from "./OpenActions";
|
||||||
import AddCollectionPane from "./Panes/AddCollectionPane";
|
|
||||||
import CassandraAddCollectionPane from "./Panes/CassandraAddCollectionPane";
|
import CassandraAddCollectionPane from "./Panes/CassandraAddCollectionPane";
|
||||||
|
|
||||||
describe("OpenActions", () => {
|
describe("OpenActions", () => {
|
||||||
@@ -15,8 +14,7 @@ describe("OpenActions", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
explorer = {} as Explorer;
|
explorer = {} as Explorer;
|
||||||
explorer.addCollectionPane = {} as AddCollectionPane;
|
explorer.onNewCollectionClicked = jest.fn();
|
||||||
explorer.addCollectionPane.open = jest.fn();
|
|
||||||
explorer.cassandraAddCollectionPane = {} as CassandraAddCollectionPane;
|
explorer.cassandraAddCollectionPane = {} as CassandraAddCollectionPane;
|
||||||
explorer.cassandraAddCollectionPane.open = jest.fn();
|
explorer.cassandraAddCollectionPane.open = jest.fn();
|
||||||
explorer.closeAllPanes = () => {};
|
explorer.closeAllPanes = () => {};
|
||||||
@@ -90,24 +88,24 @@ describe("OpenActions", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("AddCollection pane kind", () => {
|
describe("AddCollection pane kind", () => {
|
||||||
it("string value should call addCollectionPane.open", () => {
|
it("string value should call explorer.onNewCollectionClicked", () => {
|
||||||
const action = {
|
const action = {
|
||||||
actionType: "OpenPane",
|
actionType: "OpenPane",
|
||||||
paneKind: "AddCollection",
|
paneKind: "AddCollection",
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionHandled = handleOpenAction(action, [], explorer);
|
const actionHandled = handleOpenAction(action, [], explorer);
|
||||||
expect(explorer.addCollectionPane.open).toHaveBeenCalled();
|
expect(explorer.onNewCollectionClicked).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("enum value should call addCollectionPane.open", () => {
|
it("enum value should call explorer.onNewCollectionClicked", () => {
|
||||||
const action = {
|
const action = {
|
||||||
actionType: "OpenPane",
|
actionType: "OpenPane",
|
||||||
paneKind: ActionContracts.PaneKind.AddCollection,
|
paneKind: ActionContracts.PaneKind.AddCollection,
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionHandled = handleOpenAction(action, [], explorer);
|
const actionHandled = handleOpenAction(action, [], explorer);
|
||||||
expect(explorer.addCollectionPane.open).toHaveBeenCalled();
|
expect(explorer.onNewCollectionClicked).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ function openPane(action: ActionContracts.OpenPane, explorer: Explorer) {
|
|||||||
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.AddCollection]
|
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.AddCollection]
|
||||||
) {
|
) {
|
||||||
explorer.closeAllPanes();
|
explorer.closeAllPanes();
|
||||||
explorer.addCollectionPane.open();
|
explorer.onNewCollectionClicked();
|
||||||
} else if (
|
} else if (
|
||||||
action.paneKind === ActionContracts.PaneKind.CassandraAddCollection ||
|
action.paneKind === ActionContracts.PaneKind.CassandraAddCollection ||
|
||||||
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.CassandraAddCollection]
|
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.CassandraAddCollection]
|
||||||
|
|||||||
@@ -143,7 +143,6 @@
|
|||||||
size="40"
|
size="40"
|
||||||
class="collid"
|
class="collid"
|
||||||
data-bind="visible: databaseCreateNew, textInput: databaseId, hasFocus: firstFieldHasFocus"
|
data-bind="visible: databaseCreateNew, textInput: databaseId, hasFocus: firstFieldHasFocus"
|
||||||
aria-label="Database id"
|
|
||||||
autofocus
|
autofocus
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -161,7 +160,6 @@
|
|||||||
size="40"
|
size="40"
|
||||||
class="collid"
|
class="collid"
|
||||||
data-bind="visible: !databaseCreateNew(), textInput: databaseId, hasFocus: firstFieldHasFocus"
|
data-bind="visible: !databaseCreateNew(), textInput: databaseId, hasFocus: firstFieldHasFocus"
|
||||||
aria-label="Database id"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<datalist id="databasesList" data-bind="foreach: databaseIds" data-bind="visible: databaseCreateNew">
|
<datalist id="databasesList" data-bind="foreach: databaseIds" data-bind="visible: databaseCreateNew">
|
||||||
@@ -246,15 +244,12 @@
|
|||||||
placeholder="e.g., Container1"
|
placeholder="e.g., Container1"
|
||||||
size="40"
|
size="40"
|
||||||
class="textfontclr collid"
|
class="textfontclr collid"
|
||||||
data-bind="value: collectionId, attr: { 'aria-label': collectionIdTitle }"
|
data-bind="value: collectionId"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Indexing For Shared Throughput - start -->
|
<!-- Indexing For Shared Throughput - start -->
|
||||||
<div
|
<div class="seconddivpadding" data-bind="visible: showIndexingOptionsForSharedThroughput() && !isMongo()">
|
||||||
class="seconddivpadding"
|
|
||||||
data-bind="visible: showIndexingOptionsForSharedThroughput() && !container.isPreferredApiMongoDB()"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="useIndexingForSharedThroughput createNewDatabaseOrUseExisting"
|
class="useIndexingForSharedThroughput createNewDatabaseOrUseExisting"
|
||||||
aria-label="Indexing For Shared Throughput"
|
aria-label="Indexing For Shared Throughput"
|
||||||
@@ -297,7 +292,7 @@
|
|||||||
|
|
||||||
<p
|
<p
|
||||||
class="seconddivpadding"
|
class="seconddivpadding"
|
||||||
data-bind="visible: container.isPreferredApiMongoDB() && !databaseHasSharedOffer() || container.isFixedCollectionWithSharedThroughputSupported"
|
data-bind="visible: isMongo() && !databaseHasSharedOffer() || container.isFixedCollectionWithSharedThroughputSupported"
|
||||||
>
|
>
|
||||||
<span class="mandatoryStar">*</span>
|
<span class="mandatoryStar">*</span>
|
||||||
<span class="addCollectionLabel">Storage capacity</span>
|
<span class="addCollectionLabel">Storage capacity</span>
|
||||||
@@ -312,7 +307,7 @@
|
|||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
data-bind="event: { keydown: onStorageOptionsKeyDown }, visible: container.isPreferredApiMongoDB() && !databaseHasSharedOffer() || container.isFixedCollectionWithSharedThroughputSupported"
|
data-bind="event: { keydown: onStorageOptionsKeyDown }, visible: isMongo() && !databaseHasSharedOffer() || container.isFixedCollectionWithSharedThroughputSupported"
|
||||||
aria-label="Storage capacity"
|
aria-label="Storage capacity"
|
||||||
>
|
>
|
||||||
<!-- Fixed option button - Start -->
|
<!-- Fixed option button - Start -->
|
||||||
@@ -355,7 +350,6 @@
|
|||||||
attr: {
|
attr: {
|
||||||
placeholder: partitionKeyPlaceholder,
|
placeholder: partitionKeyPlaceholder,
|
||||||
required: partitionKeyVisible(),
|
required: partitionKeyVisible(),
|
||||||
'aria-label': partitionKeyName,
|
|
||||||
pattern: partitionKeyPattern,
|
pattern: partitionKeyPattern,
|
||||||
title: partitionKeyTitle
|
title: partitionKeyTitle
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
this.isPreferredApiTable = options.isPreferredApiTable;
|
this.isPreferredApiTable = options.isPreferredApiTable;
|
||||||
this.partitionKey = ko.observable<string>();
|
this.partitionKey = ko.observable<string>();
|
||||||
this.partitionKey.subscribe((newPartitionKey: string) => {
|
this.partitionKey.subscribe((newPartitionKey: string) => {
|
||||||
if (this.container.isPreferredApiMongoDB() || !newPartitionKey || newPartitionKey[0] === "/") {
|
if (userContext.apiType === "Mongo" || !newPartitionKey || newPartitionKey[0] === "/") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +354,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
|
|
||||||
// TODO: Create derived classes for Tables and Mongo to replace the If statements below
|
// TODO: Create derived classes for Tables and Mongo to replace the If statements below
|
||||||
this.partitionKeyName = ko.computed<string>(() => {
|
this.partitionKeyName = ko.computed<string>(() => {
|
||||||
if (this.container && !!this.container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return "Shard key";
|
return "Shard key";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +364,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
this.lowerCasePartitionKeyName = ko.computed<string>(() => this.partitionKeyName().toLowerCase());
|
this.lowerCasePartitionKeyName = ko.computed<string>(() => this.partitionKeyName().toLowerCase());
|
||||||
|
|
||||||
this.partitionKeyPlaceholder = ko.computed<string>(() => {
|
this.partitionKeyPlaceholder = ko.computed<string>(() => {
|
||||||
if (this.container && !!this.container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return "e.g., address.zipCode";
|
return "e.g., address.zipCode";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +376,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.uniqueKeysPlaceholder = ko.pureComputed<string>(() => {
|
this.uniqueKeysPlaceholder = ko.pureComputed<string>(() => {
|
||||||
if (this.container && !!this.container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return "Comma separated paths e.g. firstName,address.zipCode";
|
return "Comma separated paths e.g. firstName,address.zipCode";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,11 +396,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (userContext.apiType === "Mongo" && !this.isUnlimitedStorageSelected() && this.databaseHasSharedOffer()) {
|
||||||
this.container.isPreferredApiMongoDB() &&
|
|
||||||
!this.isUnlimitedStorageSelected() &&
|
|
||||||
this.databaseHasSharedOffer()
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +476,6 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
userContext.portalEnv,
|
userContext.portalEnv,
|
||||||
this.isFreeTierAccount(),
|
this.isFreeTierAccount(),
|
||||||
this.container.isFirstResourceCreated(),
|
this.container.isFirstResourceCreated(),
|
||||||
this.container.defaultExperience(),
|
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -589,7 +584,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,6 +723,10 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isMongo(): boolean {
|
||||||
|
return userContext.apiType === "Mongo";
|
||||||
|
}
|
||||||
|
|
||||||
private _onDatabasesChange(newDatabaseIds: ViewModels.Database[]) {
|
private _onDatabasesChange(newDatabaseIds: ViewModels.Database[]) {
|
||||||
this.databaseIds(newDatabaseIds?.map((database: ViewModels.Database) => database.id()));
|
this.databaseIds(newDatabaseIds?.map((database: ViewModels.Database) => database.id()));
|
||||||
}
|
}
|
||||||
@@ -810,7 +809,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
let indexingPolicy: DataModels.IndexingPolicy;
|
let indexingPolicy: DataModels.IndexingPolicy;
|
||||||
let createMongoWildcardIndex: boolean;
|
let createMongoWildcardIndex: boolean;
|
||||||
// todo - remove mongo indexing policy ticket # 616274
|
// todo - remove mongo indexing policy ticket # 616274
|
||||||
if (this.container.isPreferredApiMongoDB() && this.container.isEnableMongoCapabilityPresent()) {
|
if (userContext.apiType === "Mongo" && this.container.isEnableMongoCapabilityPresent()) {
|
||||||
createMongoWildcardIndex = this.shouldCreateMongoWildcardIndex();
|
createMongoWildcardIndex = this.shouldCreateMongoWildcardIndex();
|
||||||
} else if (this.showIndexingOptionsForSharedThroughput()) {
|
} else if (this.showIndexingOptionsForSharedThroughput()) {
|
||||||
if (this.useIndexingForSharedThroughput()) {
|
if (this.useIndexingForSharedThroughput()) {
|
||||||
@@ -1145,7 +1144,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
let transform = (value: string) => {
|
let transform = (value: string) => {
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
if (this.container.isPreferredApiMongoDB()) {
|
if (userContext.apiType === "Mongo") {
|
||||||
transform = (value: string) => {
|
transform = (value: string) => {
|
||||||
return this._convertShardKeyToPartitionKey(value);
|
return this._convertShardKeyToPartitionKey(value);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
IDropdownOption,
|
IDropdownOption,
|
||||||
Link,
|
Link,
|
||||||
|
Separator,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TooltipHost,
|
TooltipHost,
|
||||||
@@ -19,11 +20,11 @@ import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils"
|
|||||||
import { configContext, Platform } from "../../ConfigContext";
|
import { configContext, Platform } from "../../ConfigContext";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { SubscriptionType } from "../../Contracts/SubscriptionType";
|
import { SubscriptionType } from "../../Contracts/SubscriptionType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { CollectionCreation, IndexingPolicies } from "../../Shared/Constants";
|
import { CollectionCreation, IndexingPolicies } from "../../Shared/Constants";
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
import { getCollectionName } from "../../Utils/APITypeUtils";
|
||||||
import { getUpsellMessage } from "../../Utils/PricingUtils";
|
import { getUpsellMessage } from "../../Utils/PricingUtils";
|
||||||
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
||||||
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
|
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
|
||||||
@@ -36,6 +37,7 @@ export interface AddCollectionPanelProps {
|
|||||||
explorer: Explorer;
|
explorer: Explorer;
|
||||||
closePanel: () => void;
|
closePanel: () => void;
|
||||||
openNotificationConsole: () => void;
|
openNotificationConsole: () => void;
|
||||||
|
databaseId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AddCollectionPanelState {
|
export interface AddCollectionPanelState {
|
||||||
@@ -49,7 +51,7 @@ export interface AddCollectionPanelState {
|
|||||||
partitionKey: string;
|
partitionKey: string;
|
||||||
enableDedicatedThroughput: boolean;
|
enableDedicatedThroughput: boolean;
|
||||||
createMongoWildCardIndex: boolean;
|
createMongoWildCardIndex: boolean;
|
||||||
useHashV1: boolean;
|
useHashV2: boolean;
|
||||||
enableAnalyticalStore: boolean;
|
enableAnalyticalStore: boolean;
|
||||||
uniqueKeys: string[];
|
uniqueKeys: string[];
|
||||||
errorMessage: string;
|
errorMessage: string;
|
||||||
@@ -68,20 +70,18 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
createNewDatabase: userContext.defaultExperience !== DefaultAccountExperienceType.Table,
|
createNewDatabase: userContext.apiType !== "Tables" && !this.props.databaseId,
|
||||||
newDatabaseId: "",
|
newDatabaseId: "",
|
||||||
isSharedThroughputChecked: this.getSharedThroughputDefault(),
|
isSharedThroughputChecked: this.getSharedThroughputDefault(),
|
||||||
selectedDatabaseId:
|
selectedDatabaseId:
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.Table
|
userContext.apiType === "Tables" ? CollectionCreation.TablesAPIDefaultDatabase : this.props.databaseId,
|
||||||
? CollectionCreation.TablesAPIDefaultDatabase
|
|
||||||
: undefined,
|
|
||||||
collectionId: "",
|
collectionId: "",
|
||||||
enableIndexing: true,
|
enableIndexing: true,
|
||||||
isSharded: userContext.defaultExperience !== DefaultAccountExperienceType.Table,
|
isSharded: userContext.apiType !== "Tables",
|
||||||
partitionKey: "",
|
partitionKey: "",
|
||||||
enableDedicatedThroughput: false,
|
enableDedicatedThroughput: false,
|
||||||
createMongoWildCardIndex: true,
|
createMongoWildCardIndex: true,
|
||||||
useHashV1: false,
|
useHashV2: false,
|
||||||
enableAnalyticalStore: false,
|
enableAnalyticalStore: false,
|
||||||
uniqueKeys: [],
|
uniqueKeys: [],
|
||||||
errorMessage: "",
|
errorMessage: "",
|
||||||
@@ -104,13 +104,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
|
|
||||||
{!this.state.errorMessage && this.isFreeTierAccount() && (
|
{!this.state.errorMessage && this.isFreeTierAccount() && (
|
||||||
<PanelInfoErrorComponent
|
<PanelInfoErrorComponent
|
||||||
message={getUpsellMessage(
|
message={getUpsellMessage(userContext.portalEnv, true, this.props.explorer.isFirstResourceCreated(), true)}
|
||||||
userContext.portalEnv,
|
|
||||||
true,
|
|
||||||
this.props.explorer.isFirstResourceCreated(),
|
|
||||||
userContext.defaultExperience,
|
|
||||||
true
|
|
||||||
)}
|
|
||||||
messageType="info"
|
messageType="info"
|
||||||
showErrorDetails={false}
|
showErrorDetails={false}
|
||||||
openNotificationConsole={this.props.openNotificationConsole}
|
openNotificationConsole={this.props.openNotificationConsole}
|
||||||
@@ -120,17 +114,19 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="panelMainContent">
|
<div className="panelMainContent">
|
||||||
<Stack hidden={userContext.defaultExperience === DefaultAccountExperienceType.Table}>
|
<Stack hidden={userContext.apiType === "Tables"}>
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<span className="mandatoryStar">* </span>
|
<span className="mandatoryStar">* </span>
|
||||||
<Text className="panelTextBold" variant="small">
|
<Text className="panelTextBold" variant="small">
|
||||||
Database id
|
Database {userContext.apiType === "Mongo" ? "name" : "id"}
|
||||||
</Text>
|
</Text>
|
||||||
<TooltipHost
|
<TooltipHost
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content="A database is analogous to a namespace. It is the unit of management for a set of containers."
|
content={`A database is analogous to a namespace. It is the unit of management for a set of ${getCollectionName(
|
||||||
|
true
|
||||||
|
).toLocaleLowerCase()}.`}
|
||||||
>
|
>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -144,7 +140,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
role="radio"
|
||||||
id="databaseCreateNew"
|
id="databaseCreateNew"
|
||||||
data-test="addCollection-createNewDatabase"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
|
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
|
||||||
/>
|
/>
|
||||||
@@ -158,8 +153,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
name="databaseType"
|
name="databaseType"
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
role="radio"
|
||||||
id="databaseUseExisting"
|
|
||||||
data-test="addCollection-existingDatabase"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
|
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
|
||||||
/>
|
/>
|
||||||
@@ -170,8 +163,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
<Stack className="panelGroupSpacing">
|
<Stack className="panelGroupSpacing">
|
||||||
<input
|
<input
|
||||||
name="newDatabaseId"
|
name="newDatabaseId"
|
||||||
id="databaseId"
|
id="newDatabaseId"
|
||||||
data-test="addCollection-newDatabaseId"
|
|
||||||
aria-required
|
aria-required
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
@@ -181,7 +173,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
placeholder="Type a new database id"
|
placeholder="Type a new database id"
|
||||||
size={40}
|
size={40}
|
||||||
className="panelTextField"
|
className="panelTextField"
|
||||||
aria-label="Database id"
|
aria-label="New database id"
|
||||||
autoFocus
|
autoFocus
|
||||||
value={this.state.newDatabaseId}
|
value={this.state.newDatabaseId}
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
@@ -192,7 +184,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
{!this.isServerlessAccount() && (
|
{!this.isServerlessAccount() && (
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Provision database throughput"
|
label={`Share throughput across ${getCollectionName(true).toLocaleLowerCase()}`}
|
||||||
checked={this.state.isSharedThroughputChecked}
|
checked={this.state.isSharedThroughputChecked}
|
||||||
styles={{
|
styles={{
|
||||||
text: { fontSize: 12 },
|
text: { fontSize: 12 },
|
||||||
@@ -205,9 +197,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
/>
|
/>
|
||||||
<TooltipHost
|
<TooltipHost
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content="Provisioned throughput at the database level will be shared across all containers within the database."
|
content={`Throughput configured at the database level will be shared across all ${getCollectionName(
|
||||||
|
true
|
||||||
|
).toLocaleLowerCase()} within the database.`}
|
||||||
>
|
>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
@@ -218,6 +212,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
this.isFreeTierAccount() && !this.props.explorer.isFirstResourceCreated()
|
this.isFreeTierAccount() && !this.props.explorer.isFirstResourceCreated()
|
||||||
}
|
}
|
||||||
isDatabase={true}
|
isDatabase={true}
|
||||||
|
isSharded={this.state.isSharded}
|
||||||
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
||||||
onCostAcknowledgeChange={(isAcknowledge: boolean) => (this.isCostAcknowledged = isAcknowledge)}
|
onCostAcknowledgeChange={(isAcknowledge: boolean) => (this.isCostAcknowledged = isAcknowledge)}
|
||||||
@@ -234,38 +229,40 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
onChange={(event: React.FormEvent<HTMLDivElement>, database: IDropdownOption) =>
|
onChange={(event: React.FormEvent<HTMLDivElement>, database: IDropdownOption) =>
|
||||||
this.setState({ selectedDatabaseId: database.key as string })
|
this.setState({ selectedDatabaseId: database.key as string })
|
||||||
}
|
}
|
||||||
|
defaultSelectedKey={this.props.databaseId}
|
||||||
|
responsiveMode={999}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<Separator className="panelSeparator" />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack>
|
<Stack>
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<span className="mandatoryStar">* </span>
|
<span className="mandatoryStar">* </span>
|
||||||
<Text className="panelTextBold" variant="small">
|
<Text className="panelTextBold" variant="small">
|
||||||
{`${this.getCollectionName()} id`}
|
{`${getCollectionName()} ${userContext.apiType === "Mongo" ? "name" : "id"}`}
|
||||||
</Text>
|
</Text>
|
||||||
<TooltipHost
|
<TooltipHost
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content="Unique identifier for the container and used for id-based routing through REST and all SDKs."
|
content={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
|
||||||
>
|
>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
name="collectionId"
|
name="collectionId"
|
||||||
id="containerId"
|
id="collectionId"
|
||||||
data-test="addCollection-collectionId"
|
|
||||||
type="text"
|
type="text"
|
||||||
aria-required
|
aria-required
|
||||||
required
|
required
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
pattern="[^/?#\\]*[^/?# \\]"
|
pattern="[^/?#\\]*[^/?# \\]"
|
||||||
title="May not end with space nor contain characters '\' '/' '#' '?'"
|
title="May not end with space nor contain characters '\' '/' '#' '?'"
|
||||||
placeholder={`e.g., ${this.getCollectionName()}1`}
|
placeholder={`e.g., ${getCollectionName()}1`}
|
||||||
size={40}
|
size={40}
|
||||||
className="panelTextField"
|
className="panelTextField"
|
||||||
aria-label={`${this.getCollectionName()} id`}
|
aria-label={`${getCollectionName()} id`}
|
||||||
value={this.state.collectionId}
|
value={this.state.collectionId}
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
this.setState({ collectionId: event.target.value })
|
this.setState({ collectionId: event.target.value })
|
||||||
@@ -317,20 +314,22 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{userContext.defaultExperience === DefaultAccountExperienceType.MongoDB &&
|
{userContext.apiType === "Mongo" &&
|
||||||
(!this.state.isSharedThroughputChecked ||
|
(!this.state.isSharedThroughputChecked ||
|
||||||
this.props.explorer.isFixedCollectionWithSharedThroughputSupported()) && (
|
this.props.explorer.isFixedCollectionWithSharedThroughputSupported()) && (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<span className="mandatoryStar">* </span>
|
<span className="mandatoryStar">* </span>
|
||||||
<Text className="panelTextBold" variant="small">
|
<Text className="panelTextBold" variant="small">
|
||||||
Sharding options
|
Sharding
|
||||||
</Text>
|
</Text>
|
||||||
<TooltipHost
|
<TooltipHost
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content="Unique identifier for the container and used for id-based routing through REST and all SDKs."
|
content={
|
||||||
|
"Sharded collections split your data across many replica sets (shards) to achieve unlimited scalability. Sharded collections require choosing a shard key (field) to evenly distribute your data."
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -375,34 +374,35 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
</Text>
|
</Text>
|
||||||
<TooltipHost
|
<TooltipHost
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content={`The ${this.getPartitionKeyName()} is used to automatically partition data among
|
content={this.getPartitionKeyTooltipText()}
|
||||||
multiple servers for scalability. Choose a JSON property name that has a wide range of values and is
|
|
||||||
likely to have evenly distributed access patterns.`}
|
|
||||||
>
|
>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="addCollection-partitionKeyValue"
|
id="addCollection-partitionKeyValue"
|
||||||
data-test="addCollection-partitionKeyValue"
|
|
||||||
aria-required
|
aria-required
|
||||||
required
|
required
|
||||||
size={40}
|
size={40}
|
||||||
className="panelTextField"
|
className="panelTextField"
|
||||||
placeholder={this.getPartitionKeyPlaceHolder()}
|
placeholder={this.getPartitionKeyPlaceHolder()}
|
||||||
aria-label={this.getPartitionKeyName()}
|
aria-label={this.getPartitionKeyName()}
|
||||||
pattern={userContext.defaultExperience === DefaultAccountExperienceType.Graph ? "^/[^/]*" : ".*"}
|
pattern={userContext.apiType === "Gremlin" ? "^/[^/]*" : ".*"}
|
||||||
title={
|
title={userContext.apiType === "Gremlin" ? "May not use composite partition key" : ""}
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.Graph
|
|
||||||
? "May not use composite partition key"
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
value={this.state.partitionKey}
|
value={this.state.partitionKey}
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({ partitionKey: event.target.value })
|
if (
|
||||||
}
|
userContext.apiType !== "Mongo" &&
|
||||||
|
this.state.partitionKey === "" &&
|
||||||
|
!event.target.value.startsWith("/")
|
||||||
|
) {
|
||||||
|
this.setState({ partitionKey: "/" + event.target.value });
|
||||||
|
} else {
|
||||||
|
this.setState({ partitionKey: event.target.value });
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
@@ -410,7 +410,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
{!this.isServerlessAccount() && !this.state.createNewDatabase && this.isSelectedDatabaseSharedThroughput() && (
|
{!this.isServerlessAccount() && !this.state.createNewDatabase && this.isSelectedDatabaseSharedThroughput() && (
|
||||||
<Stack horizontal verticalAlign="center">
|
<Stack horizontal verticalAlign="center">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={`Provision dedicated throughput for this ${this.getCollectionName()}`}
|
label={`Provision dedicated throughput for this ${getCollectionName().toLocaleLowerCase()}`}
|
||||||
checked={this.state.enableDedicatedThroughput}
|
checked={this.state.enableDedicatedThroughput}
|
||||||
styles={{
|
styles={{
|
||||||
text: { fontSize: 12 },
|
text: { fontSize: 12 },
|
||||||
@@ -423,12 +423,14 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
/>
|
/>
|
||||||
<TooltipHost
|
<TooltipHost
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content="You can optionally provision dedicated throughput for a container within a database that has throughput
|
content={`You can optionally provision dedicated throughput for a ${getCollectionName().toLocaleLowerCase()} within a database that has throughput
|
||||||
provisioned. This dedicated throughput amount will not be shared with other containers in the database and
|
provisioned. This dedicated throughput amount will not be shared with other ${getCollectionName(
|
||||||
|
true
|
||||||
|
).toLocaleLowerCase()} in the database and
|
||||||
does not count towards the throughput you provisioned for the database. This throughput amount will be
|
does not count towards the throughput you provisioned for the database. This throughput amount will be
|
||||||
billed in addition to the throughput amount you provisioned at the database level."
|
billed in addition to the throughput amount you provisioned at the database level.`}
|
||||||
>
|
>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
@@ -439,6 +441,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
this.isFreeTierAccount() && !this.props.explorer.isFirstResourceCreated()
|
this.isFreeTierAccount() && !this.props.explorer.isFirstResourceCreated()
|
||||||
}
|
}
|
||||||
isDatabase={false}
|
isDatabase={false}
|
||||||
|
isSharded={this.state.isSharded}
|
||||||
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
||||||
onCostAcknowledgeChange={(isAcknowledged: boolean) => {
|
onCostAcknowledgeChange={(isAcknowledged: boolean) => {
|
||||||
@@ -447,7 +450,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB && (
|
{userContext.apiType === "SQL" && (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<Text className="panelTextBold" variant="small">
|
<Text className="panelTextBold" variant="small">
|
||||||
@@ -459,7 +462,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
creating a unique key policy when a container is created, you ensure the uniqueness of one or more values
|
creating a unique key policy when a container is created, you ensure the uniqueness of one or more values
|
||||||
per partition key."
|
per partition key."
|
||||||
>
|
>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -471,7 +474,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
type="text"
|
type="text"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
placeholder={
|
placeholder={
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.MongoDB
|
userContext.apiType === "Mongo"
|
||||||
? "Comma separated paths e.g. firstName,address.zipCode"
|
? "Comma separated paths e.g. firstName,address.zipCode"
|
||||||
: "Comma separated paths e.g. /firstName,/address/zipCode"
|
: "Comma separated paths e.g. /firstName,/address/zipCode"
|
||||||
}
|
}
|
||||||
@@ -512,134 +515,129 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<CollapsibleSectionComponent title="Advanced" isExpandedByDefault={false}>
|
{userContext.apiType !== "Tables" && (
|
||||||
<Stack className="panelGroupSpacing">
|
<CollapsibleSectionComponent
|
||||||
{this.props.explorer.isEnableMongoCapabilityPresent() && (
|
title="Advanced"
|
||||||
<Stack>
|
isExpandedByDefault={false}
|
||||||
<Stack horizontal>
|
onExpand={() => {
|
||||||
<span className="mandatoryStar">* </span>
|
TelemetryProcessor.traceOpen(Action.ExpandAddCollectionPaneAdvancedSection);
|
||||||
<Text className="panelTextBold" variant="small">
|
this.scrollToAdvancedSection();
|
||||||
Indexing
|
}}
|
||||||
</Text>
|
>
|
||||||
<TooltipHost
|
<Stack className="panelGroupSpacing" id="collapsibleSectionContent">
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
{this.props.explorer.isEnableMongoCapabilityPresent() && (
|
||||||
content="By default, only the field _id is indexed. Creating a wildcard index on all fields will quickly optimize
|
<Stack className="panelGroupSpacing">
|
||||||
query performance and is recommended during development."
|
<Stack horizontal>
|
||||||
>
|
<span className="mandatoryStar">* </span>
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
<Text className="panelTextBold" variant="small">
|
||||||
</TooltipHost>
|
Indexing
|
||||||
</Stack>
|
</Text>
|
||||||
|
<TooltipHost
|
||||||
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
|
content="The _id field is indexed by default. Creating a wildcard index for all fields will optimize queries and is recommended for development."
|
||||||
|
>
|
||||||
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
|
</TooltipHost>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Checkbox
|
||||||
|
label="Create a Wildcard Index on all fields"
|
||||||
|
checked={this.state.createMongoWildCardIndex}
|
||||||
|
styles={{
|
||||||
|
text: { fontSize: 12 },
|
||||||
|
checkbox: { width: 12, height: 12 },
|
||||||
|
label: { padding: 0, alignItems: "center" },
|
||||||
|
}}
|
||||||
|
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
||||||
|
this.setState({ createMongoWildCardIndex: isChecked })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{userContext.apiType === "SQL" && (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Create a Wildcard Index on all fields"
|
label="My partition key is larger than 100 bytes"
|
||||||
checked={this.state.createMongoWildCardIndex}
|
checked={this.state.useHashV2}
|
||||||
styles={{
|
styles={{
|
||||||
text: { fontSize: 12 },
|
text: { fontSize: 12 },
|
||||||
checkbox: { width: 12, height: 12 },
|
checkbox: { width: 12, height: 12 },
|
||||||
label: { padding: 0, alignItems: "center" },
|
label: { padding: 0, alignItems: "center" },
|
||||||
}}
|
}}
|
||||||
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
||||||
this.setState({ createMongoWildCardIndex: isChecked })
|
this.setState({ useHashV2: isChecked })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
)}
|
||||||
)}
|
|
||||||
|
|
||||||
{userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB && (
|
{this.shouldShowAnalyticalStoreOptions() && (
|
||||||
<Stack className="panelGroupSpacing">
|
<Stack className="panelGroupSpacing">
|
||||||
<Stack horizontal verticalAlign="start">
|
<Stack horizontal>
|
||||||
<Checkbox
|
<Text className="panelTextBold" variant="small">
|
||||||
checked={this.state.useHashV1}
|
Analytical store
|
||||||
styles={{
|
|
||||||
checkbox: { width: 12, height: 12 },
|
|
||||||
label: { padding: 0, margin: "4px 4px 0 0" },
|
|
||||||
}}
|
|
||||||
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
|
||||||
this.setState({ useHashV1: isChecked })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Text variant="small" style={{ lineHeight: "20px" }}>
|
|
||||||
My application uses an older Cosmos .NET or Java SDK version (.NET V1 or Java V2)
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Text variant="small">
|
|
||||||
To ensure compatibility with older SDKs, the created container will use a legacy partitioning scheme
|
|
||||||
that supports partition key values of size up to 100 bytes.{" "}
|
|
||||||
<Link target="_blank" href="https://aka.ms/cosmosdb/pkv2">
|
|
||||||
Learn more
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{this.shouldShowAnalyticalStoreOptions() && (
|
|
||||||
<Stack className="panelGroupSpacing">
|
|
||||||
<Stack horizontal>
|
|
||||||
<Text className="panelTextBold" variant="small">
|
|
||||||
Analytical store
|
|
||||||
</Text>
|
|
||||||
<TooltipHost
|
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
|
||||||
content="Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads. Learn more"
|
|
||||||
>
|
|
||||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
|
||||||
</TooltipHost>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Stack horizontal verticalAlign="center">
|
|
||||||
<input
|
|
||||||
className="panelRadioBtn"
|
|
||||||
checked={this.state.enableAnalyticalStore}
|
|
||||||
disabled={!this.isSynapseLinkEnabled()}
|
|
||||||
aria-label="Enable analytical store"
|
|
||||||
aria-checked={this.state.enableAnalyticalStore}
|
|
||||||
name="analyticalStore"
|
|
||||||
type="radio"
|
|
||||||
role="radio"
|
|
||||||
id="enableAnalyticalStoreBtn"
|
|
||||||
tabIndex={0}
|
|
||||||
onChange={this.onEnableAnalyticalStoreRadioBtnChange.bind(this)}
|
|
||||||
/>
|
|
||||||
<span className="panelRadioBtnLabel">On</span>
|
|
||||||
|
|
||||||
<input
|
|
||||||
className="panelRadioBtn"
|
|
||||||
checked={!this.state.enableAnalyticalStore}
|
|
||||||
disabled={!this.isSynapseLinkEnabled()}
|
|
||||||
aria-label="Disable analytical store"
|
|
||||||
aria-checked={!this.state.enableAnalyticalStore}
|
|
||||||
name="analyticalStore"
|
|
||||||
type="radio"
|
|
||||||
role="radio"
|
|
||||||
id="disableAnalyticalStoreBtn"
|
|
||||||
tabIndex={0}
|
|
||||||
onChange={this.onDisableAnalyticalStoreRadioBtnChange.bind(this)}
|
|
||||||
/>
|
|
||||||
<span className="panelRadioBtnLabel">Off</span>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
{!this.isSynapseLinkEnabled() && (
|
|
||||||
<Stack className="panelGroupSpacing">
|
|
||||||
<Text variant="small">
|
|
||||||
Azure Synapse Link is required for creating an analytical store container. Enable Synapse Link
|
|
||||||
for this Cosmos DB account.{" "}
|
|
||||||
<Link href="https://aka.ms/cosmosdb-synapselink" target="_blank">
|
|
||||||
Learn more
|
|
||||||
</Link>
|
|
||||||
</Text>
|
</Text>
|
||||||
<DefaultButton
|
<TooltipHost
|
||||||
text="Enable"
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
onClick={() => this.props.explorer.openEnableSynapseLinkDialog()}
|
content={this.getAnalyticalStorageTooltipContent()}
|
||||||
style={{ height: 27, width: 80 }}
|
>
|
||||||
styles={{ label: { fontSize: 12 } }}
|
<Icon iconName="Info" className="panelInfoIcon" />
|
||||||
/>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
|
||||||
</Stack>
|
<Stack horizontal verticalAlign="center">
|
||||||
)}
|
<input
|
||||||
</Stack>
|
className="panelRadioBtn"
|
||||||
</CollapsibleSectionComponent>
|
checked={this.state.enableAnalyticalStore}
|
||||||
|
disabled={!this.isSynapseLinkEnabled()}
|
||||||
|
aria-label="Enable analytical store"
|
||||||
|
aria-checked={this.state.enableAnalyticalStore}
|
||||||
|
name="analyticalStore"
|
||||||
|
type="radio"
|
||||||
|
role="radio"
|
||||||
|
id="enableAnalyticalStoreBtn"
|
||||||
|
tabIndex={0}
|
||||||
|
onChange={this.onEnableAnalyticalStoreRadioBtnChange.bind(this)}
|
||||||
|
/>
|
||||||
|
<span className="panelRadioBtnLabel">On</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className="panelRadioBtn"
|
||||||
|
checked={!this.state.enableAnalyticalStore}
|
||||||
|
disabled={!this.isSynapseLinkEnabled()}
|
||||||
|
aria-label="Disable analytical store"
|
||||||
|
aria-checked={!this.state.enableAnalyticalStore}
|
||||||
|
name="analyticalStore"
|
||||||
|
type="radio"
|
||||||
|
role="radio"
|
||||||
|
id="disableAnalyticalStoreBtn"
|
||||||
|
tabIndex={0}
|
||||||
|
onChange={this.onDisableAnalyticalStoreRadioBtnChange.bind(this)}
|
||||||
|
/>
|
||||||
|
<span className="panelRadioBtnLabel">Off</span>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
{!this.isSynapseLinkEnabled() && (
|
||||||
|
<Stack className="panelGroupSpacing">
|
||||||
|
<Text variant="small">
|
||||||
|
Azure Synapse Link is required for creating an analytical store{" "}
|
||||||
|
{getCollectionName().toLocaleLowerCase()}. Enable Synapse Link for this Cosmos DB account.{" "}
|
||||||
|
<Link href="https://aka.ms/cosmosdb-synapselink" target="_blank">
|
||||||
|
Learn more
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
<DefaultButton
|
||||||
|
text="Enable"
|
||||||
|
onClick={() => this.props.explorer.openEnableSynapseLinkDialog()}
|
||||||
|
style={{ height: 27, width: 80 }}
|
||||||
|
styles={{ label: { fontSize: 12 } }}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</CollapsibleSectionComponent>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PanelFooterComponent buttonLabel="OK" />
|
<PanelFooterComponent buttonLabel="OK" />
|
||||||
@@ -656,31 +654,17 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCollectionName(): string {
|
private getPartitionKeyName(isLowerCase?: boolean): string {
|
||||||
switch (userContext.defaultExperience) {
|
const partitionKeyName = userContext.apiType === "Mongo" ? "Shard key" : "Partition key";
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
|
||||||
return "Container";
|
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
|
||||||
return "Collection";
|
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
|
||||||
case DefaultAccountExperienceType.Table:
|
|
||||||
return "Table";
|
|
||||||
case DefaultAccountExperienceType.Graph:
|
|
||||||
return "Graph";
|
|
||||||
default:
|
|
||||||
throw new Error(`Unsupported default experience type: ${userContext.defaultExperience}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getPartitionKeyName(): string {
|
return isLowerCase ? partitionKeyName.toLocaleLowerCase() : partitionKeyName;
|
||||||
return userContext.defaultExperience === DefaultAccountExperienceType.MongoDB ? "Shard key" : "Partition key";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPartitionKeyPlaceHolder(): string {
|
private getPartitionKeyPlaceHolder(): string {
|
||||||
switch (userContext.defaultExperience) {
|
switch (userContext.apiType) {
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return "e.g., address.zipCode";
|
return "e.g., address.zipCode";
|
||||||
case DefaultAccountExperienceType.Graph:
|
case "Gremlin":
|
||||||
return "e.g., /address";
|
return "e.g., /address";
|
||||||
default:
|
default:
|
||||||
return "e.g., /address/zipCode";
|
return "e.g., /address/zipCode";
|
||||||
@@ -782,6 +766,34 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
: "Indexing will be turned off. Recommended if you don't need to run queries or only have key value operations.";
|
: "Indexing will be turned off. Recommended if you don't need to run queries or only have key value operations.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getPartitionKeyTooltipText(): string {
|
||||||
|
if (userContext.apiType === "Mongo") {
|
||||||
|
return "The shard key (field) is used to split your data across many replica sets (shards) to achieve unlimited scalability. It’s critical to choose a field that will evenly distribute your data.";
|
||||||
|
}
|
||||||
|
|
||||||
|
let tooltipText = `The ${this.getPartitionKeyName(
|
||||||
|
true
|
||||||
|
)} is used to automatically distribute data across partitions for scalability. Choose a property in your JSON document that has a wide range of values and evenly distributes request volume.`;
|
||||||
|
|
||||||
|
if (userContext.apiType === "SQL") {
|
||||||
|
tooltipText += " For small read-heavy workloads or write-heavy workloads of any size, id is often a good choice.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return tooltipText;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAnalyticalStorageTooltipContent(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Text variant="small">
|
||||||
|
Enable analytical store capability to perform near real-time analytics on your operational data, without
|
||||||
|
impacting the performance of transactional workloads.{" "}
|
||||||
|
<Link target="_blank" href="https://aka.ms/analytical-store-overview">
|
||||||
|
Learn more
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private shouldShowCollectionThroughputInput(): boolean {
|
private shouldShowCollectionThroughputInput(): boolean {
|
||||||
if (this.isServerlessAccount()) {
|
if (this.isServerlessAccount()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -817,11 +829,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (userContext.defaultExperience) {
|
switch (userContext.apiType) {
|
||||||
case DefaultAccountExperienceType.DocumentDB:
|
case "SQL":
|
||||||
case DefaultAccountExperienceType.MongoDB:
|
case "Mongo":
|
||||||
return true;
|
return true;
|
||||||
case DefaultAccountExperienceType.Cassandra:
|
case "Cassandra":
|
||||||
return this.props.explorer.hasStorageAnalyticsAfecFeature();
|
return this.props.explorer.hasStorageAnalyticsAfecFeature();
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -855,7 +867,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
const validPaths: string[] = uniqueKey.split(",")?.filter((path) => path?.length > 0);
|
const validPaths: string[] = uniqueKey.split(",")?.filter((path) => path?.length > 0);
|
||||||
const trimmedPaths: string[] = validPaths?.map((path) => path.trim());
|
const trimmedPaths: string[] = validPaths?.map((path) => path.trim());
|
||||||
if (trimmedPaths?.length > 0) {
|
if (trimmedPaths?.length > 0) {
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
if (userContext.apiType === "Mongo") {
|
||||||
trimmedPaths.map((path) => {
|
trimmedPaths.map((path) => {
|
||||||
const transformedPath = path.split(".").join("/");
|
const transformedPath = path.split(".").join("/");
|
||||||
if (transformedPath[0] !== "/") {
|
if (transformedPath[0] !== "/") {
|
||||||
@@ -887,8 +899,13 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (throughput > CollectionCreation.MaxRUPerPartition && !this.state.isSharded) {
|
||||||
|
this.setState({ errorMessage: "Unsharded collections support up to 10,000 RUs" });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
userContext.defaultExperience === DefaultAccountExperienceType.Graph &&
|
userContext.apiType === "Gremlin" &&
|
||||||
(this.state.partitionKey === "/id" || this.state.partitionKey === "/label")
|
(this.state.partitionKey === "/id" || this.state.partitionKey === "/label")
|
||||||
) {
|
) {
|
||||||
this.setState({ errorMessage: "/id and /label as partition keys are not allowed for graph." });
|
this.setState({ errorMessage: "/id and /label as partition keys are not allowed for graph." });
|
||||||
@@ -913,6 +930,10 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
return Constants.AnalyticalStorageTtl.Disabled;
|
return Constants.AnalyticalStorageTtl.Disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private scrollToAdvancedSection(): void {
|
||||||
|
document.getElementById("collapsibleSectionContent")?.scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
private async submit(event: React.FormEvent<HTMLFormElement>): Promise<void> {
|
private async submit(event: React.FormEvent<HTMLFormElement>): Promise<void> {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@@ -924,14 +945,14 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
let databaseId = this.state.createNewDatabase ? this.state.newDatabaseId.trim() : this.state.selectedDatabaseId;
|
let databaseId = this.state.createNewDatabase ? this.state.newDatabaseId.trim() : this.state.selectedDatabaseId;
|
||||||
let partitionKeyString = this.state.partitionKey.trim();
|
let partitionKeyString = this.state.partitionKey.trim();
|
||||||
|
|
||||||
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
if (userContext.apiType === "Tables") {
|
||||||
// Table require fixed Database: TablesDB, and fixed Partition Key: /'$pk'
|
// Table require fixed Database: TablesDB, and fixed Partition Key: /'$pk'
|
||||||
databaseId = CollectionCreation.TablesAPIDefaultDatabase;
|
databaseId = CollectionCreation.TablesAPIDefaultDatabase;
|
||||||
partitionKeyString = "/'$pk'";
|
partitionKeyString = "/'$pk'";
|
||||||
}
|
}
|
||||||
|
|
||||||
const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = this.parseUniqueKeys();
|
const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = this.parseUniqueKeys();
|
||||||
const partitionKeyVersion = this.state.useHashV1 ? undefined : 2;
|
const partitionKeyVersion = this.state.useHashV2 ? 2 : undefined;
|
||||||
const partitionKey: DataModels.PartitionKey = partitionKeyString
|
const partitionKey: DataModels.PartitionKey = partitionKeyString
|
||||||
? {
|
? {
|
||||||
paths: [partitionKeyString],
|
paths: [partitionKeyString],
|
||||||
|
|||||||
@@ -238,7 +238,6 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||||||
userContext.portalEnv,
|
userContext.portalEnv,
|
||||||
this.isFreeTierAccount(),
|
this.isFreeTierAccount(),
|
||||||
this.container.isFirstResourceCreated(),
|
this.container.isFirstResourceCreated(),
|
||||||
this.container.defaultExperience(),
|
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import * as ko from "knockout";
|
|||||||
import * as _ from "underscore";
|
import * as _ from "underscore";
|
||||||
import * as Constants from "../../Common/Constants";
|
import * as Constants from "../../Common/Constants";
|
||||||
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
||||||
import { HashMap } from "../../Common/HashMap";
|
|
||||||
import { configContext, Platform } from "../../ConfigContext";
|
import { configContext, Platform } from "../../ConfigContext";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
@@ -51,7 +50,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||||||
public ruToolTipText: ko.Computed<string>;
|
public ruToolTipText: ko.Computed<string>;
|
||||||
public canConfigureThroughput: ko.PureComputed<boolean>;
|
public canConfigureThroughput: ko.PureComputed<boolean>;
|
||||||
|
|
||||||
private keyspaceOffers: HashMap<DataModels.Offer>;
|
private keyspaceOffers: Map<string, DataModels.Offer>;
|
||||||
|
|
||||||
constructor(options: ViewModels.PaneOptions) {
|
constructor(options: ViewModels.PaneOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -60,7 +59,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||||||
this.keyspaceCreateNew = ko.observable<boolean>(true);
|
this.keyspaceCreateNew = ko.observable<boolean>(true);
|
||||||
this.ruToolTipText = ko.pureComputed(() => PricingUtils.getRuToolTipText());
|
this.ruToolTipText = ko.pureComputed(() => PricingUtils.getRuToolTipText());
|
||||||
this.canConfigureThroughput = ko.pureComputed(() => !this.container.isServerlessEnabled());
|
this.canConfigureThroughput = ko.pureComputed(() => !this.container.isServerlessEnabled());
|
||||||
this.keyspaceOffers = new HashMap<DataModels.Offer>();
|
this.keyspaceOffers = new Map();
|
||||||
this.keyspaceIds = ko.observableArray<string>();
|
this.keyspaceIds = ko.observableArray<string>();
|
||||||
this.keyspaceHasSharedOffer = ko.observable<boolean>(false);
|
this.keyspaceHasSharedOffer = ko.observable<boolean>(false);
|
||||||
this.keyspaceThroughput = ko.observable<number>();
|
this.keyspaceThroughput = ko.observable<number>();
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const genericPaneProps: GenericRightPaneProps = {
|
const genericPaneProps: GenericRightPaneProps = {
|
||||||
container,
|
|
||||||
formError,
|
formError,
|
||||||
formErrorDetail,
|
formErrorDetail,
|
||||||
id: "copynotebookpane",
|
id: "copynotebookpane",
|
||||||
@@ -140,6 +139,7 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
|
|||||||
submitButtonText: "OK",
|
submitButtonText: "OK",
|
||||||
onClose: closePanel,
|
onClose: closePanel,
|
||||||
onSubmit: () => submit(),
|
onSubmit: () => submit(),
|
||||||
|
expandConsole: () => container.expandConsole(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyNotebookPaneProps: CopyNotebookPaneProps = {
|
const copyNotebookPaneProps: CopyNotebookPaneProps = {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { deleteCollection } from "../../../Common/dataAccess/deleteCollection";
|
|||||||
import DeleteFeedback from "../../../Common/DeleteFeedback";
|
import DeleteFeedback from "../../../Common/DeleteFeedback";
|
||||||
import { ApiKind, DatabaseAccount } from "../../../Contracts/DataModels";
|
import { ApiKind, DatabaseAccount } from "../../../Contracts/DataModels";
|
||||||
import { Collection, Database, TreeNode } from "../../../Contracts/ViewModels";
|
import { Collection, Database, TreeNode } from "../../../Contracts/ViewModels";
|
||||||
import { DefaultAccountExperienceType } from "../../../DefaultAccountExperienceType";
|
|
||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { updateUserContext } from "../../../UserContext";
|
import { updateUserContext } from "../../../UserContext";
|
||||||
@@ -107,7 +106,7 @@ describe("Delete Collection Confirmation Pane", () => {
|
|||||||
},
|
},
|
||||||
id: "testDatabaseAccountId",
|
id: "testDatabaseAccountId",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
(deleteCollection as jest.Mock).mockResolvedValue(undefined);
|
(deleteCollection as jest.Mock).mockResolvedValue(undefined);
|
||||||
(TelemetryProcessor.trace as jest.Mock).mockReturnValue(undefined);
|
(TelemetryProcessor.trace as jest.Mock).mockReturnValue(undefined);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { DefaultExperienceUtility } from "../../../Shared/DefaultExperienceUtili
|
|||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../../UserContext";
|
import { userContext } from "../../../UserContext";
|
||||||
|
import { getCollectionName } from "../../../Utils/APITypeUtils";
|
||||||
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import {
|
import {
|
||||||
@@ -17,14 +18,12 @@ import {
|
|||||||
} from "../GenericRightPaneComponent/GenericRightPaneComponent";
|
} from "../GenericRightPaneComponent/GenericRightPaneComponent";
|
||||||
export interface DeleteCollectionConfirmationPaneProps {
|
export interface DeleteCollectionConfirmationPaneProps {
|
||||||
explorer: Explorer;
|
explorer: Explorer;
|
||||||
collectionName: string;
|
|
||||||
closePanel: () => void;
|
closePanel: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectionConfirmationPaneProps> = ({
|
export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectionConfirmationPaneProps> = ({
|
||||||
explorer,
|
explorer,
|
||||||
closePanel,
|
closePanel,
|
||||||
collectionName,
|
|
||||||
}: DeleteCollectionConfirmationPaneProps) => {
|
}: DeleteCollectionConfirmationPaneProps) => {
|
||||||
const [deleteCollectionFeedback, setDeleteCollectionFeedback] = useState<string>("");
|
const [deleteCollectionFeedback, setDeleteCollectionFeedback] = useState<string>("");
|
||||||
const [inputCollectionName, setInputCollectionName] = useState<string>("");
|
const [inputCollectionName, setInputCollectionName] = useState<string>("");
|
||||||
@@ -34,6 +33,7 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
|
|||||||
const shouldRecordFeedback = (): boolean => {
|
const shouldRecordFeedback = (): boolean => {
|
||||||
return explorer.isLastCollection() && !explorer.isSelectedDatabaseShared();
|
return explorer.isLastCollection() && !explorer.isSelectedDatabaseShared();
|
||||||
};
|
};
|
||||||
|
const collectionName = getCollectionName().toLocaleLowerCase();
|
||||||
const paneTitle = "Delete " + collectionName;
|
const paneTitle = "Delete " + collectionName;
|
||||||
const submit = async (): Promise<void> => {
|
const submit = async (): Promise<void> => {
|
||||||
const collection = explorer.findSelectedCollection();
|
const collection = explorer.findSelectedCollection();
|
||||||
@@ -73,7 +73,7 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
|
|||||||
const deleteFeedback = new DeleteFeedback(
|
const deleteFeedback = new DeleteFeedback(
|
||||||
userContext.databaseAccount?.id,
|
userContext.databaseAccount?.id,
|
||||||
userContext.databaseAccount?.name,
|
userContext.databaseAccount?.name,
|
||||||
DefaultExperienceUtility.getApiKindFromDefaultExperience(userContext.defaultExperience),
|
DefaultExperienceUtility.getApiKindFromDefaultExperience(userContext.apiType),
|
||||||
deleteCollectionFeedback
|
deleteCollectionFeedback
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -101,7 +101,6 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const genericPaneProps: GenericRightPaneProps = {
|
const genericPaneProps: GenericRightPaneProps = {
|
||||||
container: explorer,
|
|
||||||
formError: formError,
|
formError: formError,
|
||||||
formErrorDetail: formError,
|
formErrorDetail: formError,
|
||||||
id: "deleteCollectionpane",
|
id: "deleteCollectionpane",
|
||||||
@@ -110,6 +109,7 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
|
|||||||
submitButtonText: "OK",
|
submitButtonText: "OK",
|
||||||
onClose: closePanel,
|
onClose: closePanel,
|
||||||
onSubmit: submit,
|
onSubmit: submit,
|
||||||
|
expandConsole: () => explorer.expandConsole(),
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<GenericRightPaneComponent {...genericPaneProps}>
|
<GenericRightPaneComponent {...genericPaneProps}>
|
||||||
|
|||||||
@@ -16,16 +16,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<GenericRightPaneComponent
|
<GenericRightPaneComponent
|
||||||
container={
|
expandConsole={[Function]}
|
||||||
Object {
|
|
||||||
"findSelectedCollection": [Function],
|
|
||||||
"isLastCollection": [Function],
|
|
||||||
"isSelectedDatabaseShared": [Function],
|
|
||||||
"refreshAllDatabases": [Function],
|
|
||||||
"selectedCollectionId": [Function],
|
|
||||||
"selectedNode": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
formError=""
|
formError=""
|
||||||
formErrorDetail=""
|
formErrorDetail=""
|
||||||
id="deleteCollectionpane"
|
id="deleteCollectionpane"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
|||||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||||
import { ApiKind, DatabaseAccount } from "../../Contracts/DataModels";
|
import { ApiKind, DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { Collection, Database } from "../../Contracts/ViewModels";
|
import { Collection, Database } from "../../Contracts/ViewModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { updateUserContext } from "../../UserContext";
|
||||||
@@ -68,7 +67,7 @@ describe("Delete Database Confirmation Pane", () => {
|
|||||||
},
|
},
|
||||||
id: "testDatabaseAccountId",
|
id: "testDatabaseAccountId",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
(deleteDatabase as jest.Mock).mockResolvedValue(undefined);
|
(deleteDatabase as jest.Mock).mockResolvedValue(undefined);
|
||||||
(TelemetryProcessor.trace as jest.Mock).mockReturnValue(undefined);
|
(TelemetryProcessor.trace as jest.Mock).mockReturnValue(undefined);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
|
|||||||
const deleteFeedback = new DeleteFeedback(
|
const deleteFeedback = new DeleteFeedback(
|
||||||
userContext?.databaseAccount.id,
|
userContext?.databaseAccount.id,
|
||||||
userContext?.databaseAccount.name,
|
userContext?.databaseAccount.name,
|
||||||
DefaultExperienceUtility.getApiKindFromDefaultExperience(userContext.defaultExperience),
|
DefaultExperienceUtility.getApiKindFromDefaultExperience(userContext.apiType),
|
||||||
databaseFeedbackInput
|
databaseFeedbackInput
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { mount } from "enzyme";
|
import { mount } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import StoredProcedure from "../../Tree/StoredProcedure";
|
import StoredProcedure from "../../Tree/StoredProcedure";
|
||||||
import { ExecuteSprocParamsPane } from "./ExecuteSprocParamsPane";
|
import { ExecuteSprocParamsPane } from "./ExecuteSprocParamsPane";
|
||||||
|
|
||||||
describe("Excute Sproc Param Pane", () => {
|
describe("Excute Sproc Param Pane", () => {
|
||||||
const fakeExplorer = {} as Explorer;
|
|
||||||
const fakeSproc = {} as StoredProcedure;
|
const fakeSproc = {} as StoredProcedure;
|
||||||
const props = {
|
const props = {
|
||||||
explorer: fakeExplorer,
|
|
||||||
storedProcedure: fakeSproc,
|
storedProcedure: fakeSproc,
|
||||||
|
expandConsole: (): void => undefined,
|
||||||
closePanel: (): void => undefined,
|
closePanel: (): void => undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { useBoolean } from "@uifabric/react-hooks";
|
|||||||
import { IDropdownOption, IImageProps, Image, Stack, Text } from "office-ui-fabric-react";
|
import { IDropdownOption, IImageProps, Image, Stack, Text } from "office-ui-fabric-react";
|
||||||
import React, { FunctionComponent, useState } from "react";
|
import React, { FunctionComponent, useState } from "react";
|
||||||
import AddPropertyIcon from "../../../../images/Add-property.svg";
|
import AddPropertyIcon from "../../../../images/Add-property.svg";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import StoredProcedure from "../../Tree/StoredProcedure";
|
import StoredProcedure from "../../Tree/StoredProcedure";
|
||||||
import {
|
import {
|
||||||
GenericRightPaneComponent,
|
GenericRightPaneComponent,
|
||||||
@@ -11,7 +10,7 @@ import {
|
|||||||
import { InputParameter } from "./InputParameter";
|
import { InputParameter } from "./InputParameter";
|
||||||
|
|
||||||
interface ExecuteSprocParamsPaneProps {
|
interface ExecuteSprocParamsPaneProps {
|
||||||
explorer: Explorer;
|
expandConsole: () => void;
|
||||||
storedProcedure: StoredProcedure;
|
storedProcedure: StoredProcedure;
|
||||||
closePanel: () => void;
|
closePanel: () => void;
|
||||||
}
|
}
|
||||||
@@ -27,7 +26,7 @@ interface UnwrappedExecuteSprocParam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ExecuteSprocParamsPane: FunctionComponent<ExecuteSprocParamsPaneProps> = ({
|
export const ExecuteSprocParamsPane: FunctionComponent<ExecuteSprocParamsPaneProps> = ({
|
||||||
explorer,
|
expandConsole,
|
||||||
storedProcedure,
|
storedProcedure,
|
||||||
closePanel,
|
closePanel,
|
||||||
}: ExecuteSprocParamsPaneProps): JSX.Element => {
|
}: ExecuteSprocParamsPaneProps): JSX.Element => {
|
||||||
@@ -43,7 +42,7 @@ export const ExecuteSprocParamsPane: FunctionComponent<ExecuteSprocParamsPanePro
|
|||||||
};
|
};
|
||||||
|
|
||||||
const genericPaneProps: GenericRightPaneProps = {
|
const genericPaneProps: GenericRightPaneProps = {
|
||||||
container: explorer,
|
expandConsole,
|
||||||
formError: formError,
|
formError: formError,
|
||||||
formErrorDetail: formErrorsDetails,
|
formErrorDetail: formErrorsDetails,
|
||||||
id: "executesprocparamspane",
|
id: "executesprocparamspane",
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||||
<ExecuteSprocParamsPane
|
<ExecuteSprocParamsPane
|
||||||
closePanel={[Function]}
|
closePanel={[Function]}
|
||||||
explorer={Object {}}
|
expandConsole={[Function]}
|
||||||
storedProcedure={Object {}}
|
storedProcedure={Object {}}
|
||||||
>
|
>
|
||||||
<GenericRightPaneComponent
|
<GenericRightPaneComponent
|
||||||
container={Object {}}
|
expandConsole={[Function]}
|
||||||
formError=""
|
formError=""
|
||||||
formErrorDetail=""
|
formErrorDetail=""
|
||||||
id="executesprocparamspane"
|
id="executesprocparamspane"
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ import React, { FunctionComponent, ReactNode } from "react";
|
|||||||
import ErrorRedIcon from "../../../../images/error_red.svg";
|
import ErrorRedIcon from "../../../../images/error_red.svg";
|
||||||
import LoadingIndicatorIcon from "../../../../images/LoadingIndicator_3Squares.gif";
|
import LoadingIndicatorIcon from "../../../../images/LoadingIndicator_3Squares.gif";
|
||||||
import { KeyCodes } from "../../../Common/Constants";
|
import { KeyCodes } from "../../../Common/Constants";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
|
|
||||||
export interface GenericRightPaneProps {
|
export interface GenericRightPaneProps {
|
||||||
container: Explorer;
|
expandConsole: () => void;
|
||||||
formError: string;
|
formError: string;
|
||||||
formErrorDetail: string;
|
formErrorDetail: string;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -24,7 +23,7 @@ export interface GenericRightPaneState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const GenericRightPaneComponent: FunctionComponent<GenericRightPaneProps> = ({
|
export const GenericRightPaneComponent: FunctionComponent<GenericRightPaneProps> = ({
|
||||||
container,
|
expandConsole,
|
||||||
formError,
|
formError,
|
||||||
formErrorDetail,
|
formErrorDetail,
|
||||||
id,
|
id,
|
||||||
@@ -72,7 +71,7 @@ export const GenericRightPaneComponent: FunctionComponent<GenericRightPaneProps>
|
|||||||
<span className="formErrors" title={formError}>
|
<span className="formErrors" title={formError}>
|
||||||
{formError}
|
{formError}
|
||||||
</span>
|
</span>
|
||||||
<a className="errorLink" role="link" hidden={!formErrorDetail} onClick={showErrorDetail}>
|
<a className="errorLink" role="link" hidden={!formErrorDetail} onClick={expandConsole}>
|
||||||
More details
|
More details
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@@ -114,10 +113,6 @@ export const GenericRightPaneComponent: FunctionComponent<GenericRightPaneProps>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showErrorDetail = (): void => {
|
|
||||||
container.expandConsole();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div tabIndex={-1} onKeyDown={onKeyDown}>
|
<div tabIndex={-1} onKeyDown={onKeyDown}>
|
||||||
<div className="contextual-pane-out" onClick={onClose}></div>
|
<div className="contextual-pane-out" onClick={onClose}></div>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({
|
|||||||
|
|
||||||
const title = "Load Query";
|
const title = "Load Query";
|
||||||
const genericPaneProps: GenericRightPaneProps = {
|
const genericPaneProps: GenericRightPaneProps = {
|
||||||
container: explorer,
|
expandConsole: () => explorer.expandConsole(),
|
||||||
formError: formError,
|
formError: formError,
|
||||||
formErrorDetail: formErrorsDetails,
|
formErrorDetail: formErrorsDetails,
|
||||||
id: "loadQueryPane",
|
id: "loadQueryPane",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
exports[`Load Query Pane should render Default properly 1`] = `
|
exports[`Load Query Pane should render Default properly 1`] = `
|
||||||
<GenericRightPaneComponent
|
<GenericRightPaneComponent
|
||||||
container={Object {}}
|
expandConsole={[Function]}
|
||||||
formError=""
|
formError=""
|
||||||
formErrorDetail=""
|
formErrorDetail=""
|
||||||
id="loadQueryPane"
|
id="loadQueryPane"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user