mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-06 03:00:23 +00:00
Compare commits
29 Commits
dependabot
...
users/artr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
873712d5c2 | ||
|
|
4f9054ef37 | ||
|
|
d9e142d7a6 | ||
|
|
dfdb44bdc9 | ||
|
|
0a06c1c4f6 | ||
|
|
73b6bdcd3a | ||
|
|
492c42ccda | ||
|
|
e48402ae1b | ||
|
|
a3bd126a21 | ||
|
|
d15feb3478 | ||
|
|
cbc722031c | ||
|
|
b9d93c7070 | ||
|
|
9c04cfcc18 | ||
|
|
7b568df150 | ||
|
|
5c7c0eae61 | ||
|
|
16b05c2a75 | ||
|
|
bb82915cc6 | ||
|
|
c59d31f4c0 | ||
|
|
8fa2721eab | ||
|
|
754354dbf9 | ||
|
|
ae5811306b | ||
|
|
f84deea9bc | ||
|
|
260c99e15c | ||
|
|
c1c12019da | ||
|
|
4e5358185f | ||
|
|
b4bc93ac03 | ||
|
|
c61788198f | ||
|
|
379395567c | ||
|
|
c2d2ff3dee |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -85,6 +85,8 @@ jobs:
|
||||
path: .cache
|
||||
key: ${{ runner.os }}-build-cache
|
||||
- run: npm run pack:prod
|
||||
env:
|
||||
NODE_OPTIONS: '--max-old-space-size=4096'
|
||||
- run: cp -r ./Contracts ./dist/contracts
|
||||
- run: cp -r ./configs ./dist/configs
|
||||
- uses: actions/upload-artifact@v2
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -23,5 +23,6 @@
|
||||
"source.fixAll.eslint": true,
|
||||
"source.organizeImports": true
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative"
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
||||
@SemiboldFont: "Segoe UI Semibold", "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
||||
@GrayScale: "grayscale()";
|
||||
@NoColor: "brightness(0) saturate(100%)";
|
||||
|
||||
@xSmallFontSize: 4px;
|
||||
@smallFontSize: 8px;
|
||||
@@ -147,14 +148,41 @@
|
||||
// CommandBar
|
||||
@CommandBarButtonHeight: 40px;
|
||||
|
||||
/**********************************************************************************
|
||||
Portal Consts
|
||||
/**********************************************************************************/
|
||||
|
||||
@PortalAccentMediumHigh: #0058ad;
|
||||
@PortalAccentMedium: #004e87;
|
||||
@PortalAccentLight: #eef7ff;
|
||||
@PortalAccentAccentExtra: #ddf0ff;
|
||||
|
||||
/**********************************************************************************
|
||||
Fabric Consts
|
||||
/**********************************************************************************/
|
||||
|
||||
@FabricFont: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
|
||||
|
||||
@FabricBoxBorderRadius: 8px;
|
||||
@FabricBoxBorderShadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.14);
|
||||
@FabricBoxMargin: 4px 3px 4px 3px;
|
||||
|
||||
@FabricAccentMediumHigh: #0c695a;
|
||||
@FabricAccentMedium: #117865;
|
||||
@FabricAccentLight: #f5f5f5;
|
||||
@FabricAccentExtra: #ebebeb;
|
||||
|
||||
@FabricButtonBorderRadius: 4px;
|
||||
|
||||
|
||||
/**********************************************************************************
|
||||
Common Flex Property
|
||||
/**********************************************************************************/
|
||||
|
||||
.flex-display(@display: flex) {
|
||||
display: ~"-webkit-@{display}";
|
||||
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
|
||||
display: ~"-ms-@{display}"; // IE11
|
||||
display:~"-webkit-@{display}";
|
||||
display:~"-ms-@{display}box"; // IE10 uses -ms-flexbox
|
||||
display:~"-ms-@{display}"; // IE11
|
||||
display: @display;
|
||||
}
|
||||
|
||||
@@ -168,13 +196,15 @@
|
||||
High contrast mode active
|
||||
**************************************************************************************/
|
||||
|
||||
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||
@media all and (-ms-high-contrast: none),
|
||||
(-ms-high-contrast: active) {
|
||||
|
||||
.selectedRadio,
|
||||
.selectedRadio:hover,
|
||||
.selectedRadio:active,
|
||||
.selectedRadio.dirty,
|
||||
.tab [type="radio"]:checked ~ label,
|
||||
.tab [type="radio"]:checked ~ label:hover {
|
||||
.tab [type="radio"]:checked~label,
|
||||
.tab [type="radio"]:checked~label:hover {
|
||||
-ms-high-contrast-adjust: none;
|
||||
-webkit-text-fill-color: HighlightText;
|
||||
color: HighlightText;
|
||||
@@ -183,6 +213,7 @@
|
||||
}
|
||||
|
||||
.queryMetricsSummaryTuple {
|
||||
|
||||
th,
|
||||
td {
|
||||
&:nth-child(2) {
|
||||
@@ -302,4 +333,4 @@
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: @InfoPointerColor transparent;
|
||||
}
|
||||
}
|
||||
@@ -124,12 +124,13 @@ table.dataTable thead td:active {
|
||||
|
||||
table.dataTable thead th:focus,
|
||||
table.dataTable thead td:focus {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #007ACC;
|
||||
outline: 1px dashed #605E5C;
|
||||
outline-offset: -2px;
|
||||
/*[{datatable-header-cell-focus-background}]*/
|
||||
}
|
||||
|
||||
table.dataTable tbody tr:focus{
|
||||
outline: 1px dashed #605E5C;
|
||||
}
|
||||
table.dataTable thead th:hover,
|
||||
table.dataTable thead td:hover {
|
||||
border: 1px solid #007ACC;
|
||||
|
||||
@@ -2646,6 +2646,11 @@ a:link {
|
||||
width: @ActiveTabWidth;
|
||||
}
|
||||
|
||||
.nav-tabs > li.active > .tabNavContentContainer > .tab_Content > .tabNavText {
|
||||
font-weight: bolder;
|
||||
border-bottom: 2px solid rgba(0,120,212,1);
|
||||
}
|
||||
|
||||
.nav-tabs > li.active:focus > .tabNavContentContainer {
|
||||
.focus();
|
||||
}
|
||||
|
||||
211
less/documentDBFabric.less
Normal file
211
less/documentDBFabric.less
Normal file
@@ -0,0 +1,211 @@
|
||||
@import "./Common/Constants";
|
||||
|
||||
html {
|
||||
font-family: @FabricFont;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: @FabricFont;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
a {
|
||||
color: @FabricAccentMedium;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: @FabricAccentMediumHigh;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#divExplorer {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.resourceTreeAndTabs {
|
||||
border-radius: @FabricBoxBorderRadius;
|
||||
box-shadow: @FabricBoxBorderShadow;
|
||||
margin: @FabricBoxMargin;
|
||||
margin-top: 4px;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.tabsManagerContainer {
|
||||
background-color: #fafafa
|
||||
}
|
||||
|
||||
.nav-tabs-margin {
|
||||
padding-top: 8px;
|
||||
background-color: #fafafa
|
||||
}
|
||||
|
||||
.commandBarContainer {
|
||||
background-color: #ffffff;
|
||||
border-bottom: none;
|
||||
border-radius: @FabricBoxBorderRadius;
|
||||
box-shadow: @FabricBoxBorderShadow;
|
||||
margin: @FabricBoxMargin;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.dividerContainer {
|
||||
padding: @SmallSpace 0px @SmallSpace 0px;
|
||||
.flex-display();
|
||||
|
||||
span {
|
||||
border-left: @ButtonBorderWidth solid @BaseMedium;
|
||||
margin: 0 10px 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.nav-tabs>li>.tabNavContentContainer>.tab_Content:hover {
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-tabs>li.active>.tabNavContentContainer>.tab_Content,
|
||||
.nav-tabs>li.active>.tabNavContentContainer>.tab_Content:hover {
|
||||
border-bottom: 2px solid @FabricAccentMedium;
|
||||
}
|
||||
|
||||
.nav-tabs>li.active>.tabNavContentContainer>.tab_Content>.tabNavText {
|
||||
border-bottom: 0px none transparent;
|
||||
}
|
||||
|
||||
.tabNavContentContainer {
|
||||
padding: @SmallSpace 0px @SmallSpace 0px;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.tab_Content {
|
||||
border-right: 0px none transparent;
|
||||
margin: 0px @SmallSpace 0px @SmallSpace;
|
||||
width: calc(@TabsWidth - (@SmallSpace * 2));
|
||||
padding-bottom: @SmallSpace;
|
||||
|
||||
.statusIconContainer {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.tabIconSection {
|
||||
.cancelButton {
|
||||
padding: 0px 0px 0px @SmallSpace;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.resourceTree {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.accordion {
|
||||
.accordionItemContainer {
|
||||
.accordionItemHeader {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.treeComponent {
|
||||
.nodeItem {
|
||||
&:focus {
|
||||
outline: 2px @FabricAccentMedium;
|
||||
}
|
||||
|
||||
.treeNodeHeader {
|
||||
padding: 5px 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background-color: @FabricAccentLight;
|
||||
|
||||
.treeMenuEllipsis {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.showingMenu {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
&>.treeNodeHeader {
|
||||
background-color: @FabricAccentExtra;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.dataExplorerErrorConsoleContainer {
|
||||
border-radius: @FabricBoxBorderRadius;
|
||||
box-shadow: @FabricBoxBorderShadow;
|
||||
margin: @FabricBoxMargin;
|
||||
width: auto;
|
||||
align-self: auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.filterbtnstyle {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: solid 1px #d1d1d1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.filterbtnstyle:hover {
|
||||
background: @FabricAccentLight;
|
||||
color: #000;
|
||||
border: solid 1px #d1d1d1;
|
||||
}
|
||||
|
||||
.filterbtnstyle:active {
|
||||
background: @FabricAccentLight;
|
||||
color: #000;
|
||||
border: solid 1px #d1d1d1;
|
||||
}
|
||||
|
||||
.filterbtnstyle:focus {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: solid 1px #d1d1d1;
|
||||
}
|
||||
|
||||
|
||||
.gridRowSelected .tabdocumentsGridElement:hover {
|
||||
background-color: @FabricAccentLight !important;
|
||||
}
|
||||
|
||||
|
||||
.refreshcol {
|
||||
filter: brightness(0) saturate(100%);
|
||||
}
|
||||
|
||||
.refreshcol1 {
|
||||
filter: brightness(0) saturate(100%);
|
||||
}
|
||||
|
||||
.fileImportImg img {
|
||||
filter: brightness(0) saturate(100%);
|
||||
}
|
||||
18744
package-lock.json
generated
18744
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
"@babel/plugin-proposal-class-properties": "7.12.1",
|
||||
"@babel/plugin-proposal-decorators": "7.12.12",
|
||||
"@fluentui/react": "8.14.3",
|
||||
"@fluentui/react-components": "9.30.1",
|
||||
"@fluentui/react-components": "9.32.1",
|
||||
"@jupyterlab/services": "6.0.2",
|
||||
"@jupyterlab/terminal": "3.0.3",
|
||||
"@microsoft/applicationinsights-web": "2.6.1",
|
||||
@@ -199,6 +199,7 @@
|
||||
"pack:fast": "webpack --mode development --progress",
|
||||
"copyToConsumers": "node copyToConsumers",
|
||||
"test": "rimraf coverage && jest",
|
||||
"test:debug": "jest --runInBand",
|
||||
"test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",
|
||||
"watch": "npm run start",
|
||||
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
||||
@@ -232,6 +233,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/Azure/cosmos-explorer",
|
||||
"prettier": {
|
||||
"printWidth": 120
|
||||
"printWidth": 120,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,9 +365,6 @@ export const EmulatorMasterKey =
|
||||
//[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Well known public masterKey for emulator")]
|
||||
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
|
||||
|
||||
// A variable @MyVariable defined in Constants.less is accessible as StyleConstants.MyVariable
|
||||
export const StyleConstants = require("less-vars-loader!../../less/Common/Constants.less");
|
||||
|
||||
export class Notebook {
|
||||
public static readonly defaultBasePath = "./notebooks";
|
||||
public static readonly heartbeatDelayMs = 60000;
|
||||
|
||||
@@ -109,7 +109,7 @@ export function client(): Cosmos.CosmosClient {
|
||||
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
|
||||
}
|
||||
|
||||
if (userContext.features.enablePriorityBasedThrottling && userContext.apiType === "SQL") {
|
||||
if (userContext.databaseAccount?.properties?.enablePriorityBasedExecution && userContext.apiType === "SQL") {
|
||||
const plugins = (options as any).plugins || [];
|
||||
plugins.push({ on: "request", plugin: PriorityBasedExecutionUtils.requestPlugin });
|
||||
(options as any).plugins = plugins;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DatePicker, TextField } from "@fluentui/react";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { attributeValueLabel } from "../Explorer/Panes/Tables/Validators/EntityTableHelper";
|
||||
|
||||
export interface TableEntityProps {
|
||||
entityValueLabel?: string;
|
||||
@@ -58,6 +59,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
||||
placeholder={entityValuePlaceholder}
|
||||
value={typeof entityValue === "string" ? entityValue : ""}
|
||||
onChange={onEntityValueChange}
|
||||
ariaLabel={attributeValueLabel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,8 +5,10 @@ import refreshImg from "../../images/refresh-cosmos.svg";
|
||||
import { AuthType } from "../AuthType";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
import { ResourceTokenTree } from "../Explorer/Tree/ResourceTokenTree";
|
||||
import { ResourceTree2 } from "../Explorer/Tree2/ResourceTree";
|
||||
import { userContext } from "../UserContext";
|
||||
import { getApiShortDisplayName } from "../Utils/APITypeUtils";
|
||||
import { Platform, configContext } from "./../ConfigContext";
|
||||
import { NormalizedEventKey } from "./Constants";
|
||||
|
||||
export interface ResourceTreeContainerProps {
|
||||
@@ -76,10 +78,10 @@ export const ResourceTreeContainer: FunctionComponent<ResourceTreeContainerProps
|
||||
<ResourceTokenTree />
|
||||
) : userContext.features.enableKoResourceTree ? (
|
||||
<div style={{ overflowY: "auto" }} data-bind="react:resourceTree" />
|
||||
) : configContext.platform === Platform.Fabric ? (
|
||||
<ResourceTree2 container={container} />
|
||||
) : (
|
||||
<ResourceTree container={container} />
|
||||
// Uncomment the following line to use the fluent ui tree
|
||||
// <ResourceTree2 container={container} />
|
||||
)}
|
||||
</div>
|
||||
{/* Collections Window - End */}
|
||||
|
||||
18
src/Common/StyleConstants.ts
Normal file
18
src/Common/StyleConstants.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Platform, configContext } from "../ConfigContext";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
export const StyleConstants = require("less-vars-loader!../../less/Common/Constants.less");
|
||||
|
||||
export function updateStyles(): void {
|
||||
if (configContext.platform === Platform.Fabric) {
|
||||
StyleConstants.AccentMediumHigh = StyleConstants.FabricAccentMediumHigh;
|
||||
StyleConstants.AccentMedium = StyleConstants.FabricAccentMedium;
|
||||
StyleConstants.AccentLight = StyleConstants.FabricAccentLight;
|
||||
StyleConstants.AccentAccentExtra = StyleConstants.FabricAccentMediumHigh;
|
||||
} else {
|
||||
StyleConstants.AccentMediumHigh = StyleConstants.PortalAccentMediumHigh;
|
||||
StyleConstants.AccentMedium = StyleConstants.PortalAccentMedium;
|
||||
StyleConstants.AccentLight = StyleConstants.PortalAccentLight;
|
||||
StyleConstants.AccentAccentExtra = StyleConstants.PortalAccentMediumHigh;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import React, { FunctionComponent } from "react";
|
||||
import DeleteIcon from "../../images/delete.svg";
|
||||
import EditIcon from "../../images/Edit_entity.svg";
|
||||
import { attributeNameLabel, dataTypeLabel } from "../Explorer/Panes/Tables/Validators/EntityTableHelper";
|
||||
import { CassandraType, TableType } from "../Explorer/Tables/Constants";
|
||||
import { userContext } from "../UserContext";
|
||||
import { EntityValue } from "./EntityValue";
|
||||
@@ -112,6 +113,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
||||
value={entityProperty}
|
||||
onChange={onEntityPropertyChange}
|
||||
required
|
||||
ariaLabel={attributeNameLabel}
|
||||
/>
|
||||
<Dropdown
|
||||
label={entityTypeLabel && entityTypeLabel}
|
||||
@@ -120,6 +122,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
||||
options={options}
|
||||
disabled={isPropertyTypeDisable}
|
||||
styles={dropdownStyles}
|
||||
ariaLabel={dataTypeLabel}
|
||||
/>
|
||||
<EntityValue
|
||||
entityValueLabel={entityValueLabel}
|
||||
|
||||
@@ -16,6 +16,7 @@ export enum Platform {
|
||||
Portal = "Portal",
|
||||
Hosted = "Hosted",
|
||||
Emulator = "Emulator",
|
||||
Fabric = "Fabric",
|
||||
}
|
||||
|
||||
export interface ConfigContext {
|
||||
@@ -60,6 +61,9 @@ let configContext: Readonly<ConfigContext> = {
|
||||
`^https:\\/\\/[\\.\\w]*ext\\.azure\\.(com|cn|us)$`,
|
||||
`^https:\\/\\/[\\.\\w]*\\.ext\\.microsoftazure\\.de$`,
|
||||
`^https:\\/\\/cosmos-db-dataexplorer-germanycentral\\.azurewebsites\\.de$`,
|
||||
`^https:\\/\\/.*\\.fabric\\.microsoft\\.com$`,
|
||||
`^https:\\/\\/.*\\.powerbi\\.com$`,
|
||||
`^https:\\/\\/.*\\.analysis-df\\.net$`,
|
||||
], // Webpack injects this at build time
|
||||
gitSha: process.env.GIT_SHA,
|
||||
hostedExplorerURL: "https://cosmos.azure.com/",
|
||||
@@ -67,7 +71,7 @@ let configContext: Readonly<ConfigContext> = {
|
||||
ARM_AUTH_AREA: "https://management.azure.com/",
|
||||
ARM_ENDPOINT: "https://management.azure.com/",
|
||||
ARM_API_VERSION: "2016-06-01",
|
||||
GRAPH_ENDPOINT: "https://graph.windows.net",
|
||||
GRAPH_ENDPOINT: "https://graph.microsoft.com",
|
||||
GRAPH_API_VERSION: "1.6",
|
||||
ARCADIA_ENDPOINT: "https://workspaceartifacts.projectarcadia.net",
|
||||
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
|
||||
@@ -187,6 +191,7 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
|
||||
console.error(`Invalid platform query parameter: ${platform}`);
|
||||
break;
|
||||
case Platform.Portal:
|
||||
case Platform.Fabric:
|
||||
case Platform.Hosted:
|
||||
case Platform.Emulator:
|
||||
updateConfigContext({ platform });
|
||||
|
||||
@@ -38,6 +38,7 @@ export interface DatabaseAccountExtendedProperties {
|
||||
locations?: DatabaseAccountResponseLocation[];
|
||||
postgresqlEndpoint?: string;
|
||||
publicNetworkAccess?: string;
|
||||
enablePriorityBasedExecution?: boolean;
|
||||
vcoreMongoEndpoint?: string;
|
||||
}
|
||||
|
||||
|
||||
25
src/Contracts/FabricContract.ts
Normal file
25
src/Contracts/FabricContract.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export type FabricMessage =
|
||||
| {
|
||||
type: "newContainer";
|
||||
databaseName: string;
|
||||
}
|
||||
| {
|
||||
type: "initialize";
|
||||
connectionString: string | undefined;
|
||||
}
|
||||
| {
|
||||
type: "openTab";
|
||||
databaseName: string;
|
||||
collectionName: string | undefined;
|
||||
};
|
||||
|
||||
export type DataExploreMessage =
|
||||
| "ready"
|
||||
| {
|
||||
type: number;
|
||||
data: {
|
||||
action: "LoadDatabases";
|
||||
actionModifier: "success" | "start";
|
||||
defaultExperience: "SQL";
|
||||
};
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import dayjs from "dayjs";
|
||||
import * as Plotly from "plotly.js-cartesian-dist-min";
|
||||
import { StyleConstants } from "../../Common/Constants";
|
||||
import { sendCachedDataMessage, sendReadyMessage } from "../../Common/MessageHandler";
|
||||
import { StyleConstants } from "../../Common/StyleConstants";
|
||||
import { MessageTypes } from "../../Contracts/ExplorerContracts";
|
||||
import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation";
|
||||
import "./Heatmap.less";
|
||||
|
||||
@@ -18,6 +18,7 @@ import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { userContext } from "../UserContext";
|
||||
import { getCollectionName, getDatabaseName } from "../Utils/APITypeUtils";
|
||||
import { useSidePanel } from "../hooks/useSidePanel";
|
||||
import { Platform, configContext } from "./../ConfigContext";
|
||||
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
|
||||
import Explorer from "./Explorer";
|
||||
import { useNotebook } from "./Notebook/useNotebook";
|
||||
@@ -99,7 +100,10 @@ export const createCollectionContextMenuButton = (
|
||||
});
|
||||
}
|
||||
|
||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
||||
if (
|
||||
configContext.platform !== Platform.Fabric &&
|
||||
(userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
|
||||
) {
|
||||
items.push({
|
||||
iconSrc: AddStoredProcedureIcon,
|
||||
onClick: () => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {
|
||||
ChoiceGroup,
|
||||
DefaultButton,
|
||||
Dialog as FluentDialog,
|
||||
DialogFooter,
|
||||
DialogType,
|
||||
Dialog as FluentDialog,
|
||||
FontIcon,
|
||||
IButtonProps,
|
||||
IChoiceGroupProps,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
ProgressIndicator,
|
||||
TextField,
|
||||
} from "@fluentui/react";
|
||||
import React, { FC } from "react";
|
||||
import React, { FC, useEffect } from "react";
|
||||
import create, { UseStore } from "zustand";
|
||||
|
||||
export interface DialogState {
|
||||
@@ -157,6 +157,20 @@ export const Dialog: FC = () => {
|
||||
contentHtml,
|
||||
} = props || {};
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === "Escape") {
|
||||
useDialog.getState().closeDialog();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
} else {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
const dialogProps: IDialogProps = {
|
||||
hidden: !visible,
|
||||
dialogContentProps: {
|
||||
|
||||
@@ -32,6 +32,20 @@ const testCassandraAccount: DataModels.DatabaseAccount = {
|
||||
},
|
||||
};
|
||||
|
||||
const testPostgresAccount: DataModels.DatabaseAccount = {
|
||||
...testAccount,
|
||||
properties: {
|
||||
postgresqlEndpoint: "https://testPostgresEndpoint.azure.com/",
|
||||
},
|
||||
};
|
||||
|
||||
const testVCoreMongoAccount: DataModels.DatabaseAccount = {
|
||||
...testAccount,
|
||||
properties: {
|
||||
vcoreMongoEndpoint: "https://testVCoreMongoEndpoint.azure.com/",
|
||||
},
|
||||
};
|
||||
|
||||
const testNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
|
||||
authToken: "authToken",
|
||||
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com",
|
||||
@@ -50,6 +64,18 @@ const testCassandraNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInf
|
||||
forwardingId: "Id",
|
||||
};
|
||||
|
||||
const testPostgresNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
|
||||
authToken: "authToken",
|
||||
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com/postgresql",
|
||||
forwardingId: "Id",
|
||||
};
|
||||
|
||||
const testVCoreMongoNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
|
||||
authToken: "authToken",
|
||||
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com/mongovcore",
|
||||
forwardingId: "Id",
|
||||
};
|
||||
|
||||
describe("NotebookTerminalComponent", () => {
|
||||
it("renders terminal", () => {
|
||||
const props: NotebookTerminalComponentProps = {
|
||||
@@ -94,4 +120,27 @@ describe("NotebookTerminalComponent", () => {
|
||||
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders Postgres shell", () => {
|
||||
const props: NotebookTerminalComponentProps = {
|
||||
databaseAccount: testPostgresAccount,
|
||||
notebookServerInfo: testPostgresNotebookServerInfo,
|
||||
tabId: undefined,
|
||||
};
|
||||
|
||||
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders vCore Mongo shell", () => {
|
||||
const props: NotebookTerminalComponentProps = {
|
||||
databaseAccount: testVCoreMongoAccount,
|
||||
notebookServerInfo: testVCoreMongoNotebookServerInfo,
|
||||
tabId: undefined,
|
||||
username: "username",
|
||||
};
|
||||
|
||||
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`NotebookTerminalComponent renders Postgres shell 1`] = `
|
||||
<div
|
||||
className="notebookTerminalContainer"
|
||||
>
|
||||
<iframe
|
||||
onLoad={[Function]}
|
||||
src="terminal.html"
|
||||
title="Terminal to Notebook Server"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`NotebookTerminalComponent renders cassandra shell 1`] = `
|
||||
<div
|
||||
className="notebookTerminalContainer"
|
||||
@@ -47,3 +59,15 @@ exports[`NotebookTerminalComponent renders terminal 1`] = `
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`NotebookTerminalComponent renders vCore Mongo shell 1`] = `
|
||||
<div
|
||||
className="notebookTerminalContainer"
|
||||
>
|
||||
<iframe
|
||||
onLoad={[Function]}
|
||||
src="terminal.html"
|
||||
title="Terminal to Notebook Server"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -23,9 +23,9 @@ import * as React from "react";
|
||||
import * as _ from "underscore";
|
||||
import SaveQueryBannerIcon from "../../../../images/save_query_banner.png";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||
import { QueriesClient } from "../../../Common/QueriesClient";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
Text,
|
||||
} from "@fluentui/react";
|
||||
import * as React from "react";
|
||||
import { StyleConstants, Urls } from "../../../Common/Constants";
|
||||
import { Urls } from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
import { hoursInAMonth } from "../../../Shared/Constants";
|
||||
import {
|
||||
computeRUUsagePriceHourly,
|
||||
|
||||
@@ -218,6 +218,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
||||
value={this.props.displayedTtlSeconds}
|
||||
onChange={this.onTimeToLiveSecondsChange}
|
||||
suffix="second(s)"
|
||||
ariaLabel={`Time to live in seconds`}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -62,6 +62,7 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
|
||||
}
|
||||
/>
|
||||
<StyledTextFieldBase
|
||||
ariaLabel="Time to live in seconds"
|
||||
id="timeToLiveSeconds"
|
||||
max={2147483647}
|
||||
min={1}
|
||||
@@ -295,6 +296,7 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
|
||||
}
|
||||
/>
|
||||
<StyledTextFieldBase
|
||||
ariaLabel="Time to live in seconds"
|
||||
id="timeToLiveSeconds"
|
||||
max={2147483647}
|
||||
min={1}
|
||||
@@ -583,6 +585,7 @@ exports[`SubSettingsComponent changeFeedPolicy hidden 1`] = `
|
||||
}
|
||||
/>
|
||||
<StyledTextFieldBase
|
||||
ariaLabel="Time to live in seconds"
|
||||
id="timeToLiveSeconds"
|
||||
max={2147483647}
|
||||
min={1}
|
||||
@@ -831,6 +834,7 @@ exports[`SubSettingsComponent renders 1`] = `
|
||||
}
|
||||
/>
|
||||
<StyledTextFieldBase
|
||||
ariaLabel="Time to live in seconds"
|
||||
id="timeToLiveSeconds"
|
||||
max={2147483647}
|
||||
min={1}
|
||||
|
||||
@@ -14,3 +14,7 @@
|
||||
.throughputInputSpacing > :not(:last-child) {
|
||||
margin-bottom: @DefaultSpace;
|
||||
}
|
||||
.capacitycalculator-link:focus{
|
||||
text-decoration: underline;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import LoadingIndicator_3Squares from "../../../../images/LoadingIndicator_3Squa
|
||||
import TriangleDownIcon from "../../../../images/Triangle-down.svg";
|
||||
import TriangleRightIcon from "../../../../images/Triangle-right.svg";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
@@ -237,7 +238,7 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
|
||||
private renderContextMenuButton(node: TreeNode): JSX.Element {
|
||||
const menuItemLabel = "More";
|
||||
const buttonStyles: Partial<IButtonStyles> = {
|
||||
rootFocused: { outline: `1px dashed ${Constants.StyleConstants.FocusColor}` },
|
||||
rootFocused: { outline: `1px dashed ${StyleConstants.FocusColor}` },
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -9,8 +9,11 @@ import {
|
||||
Tree,
|
||||
TreeItem,
|
||||
TreeItemLayout,
|
||||
TreeOpenChangeData,
|
||||
TreeOpenChangeEvent,
|
||||
} from "@fluentui/react-components";
|
||||
import { MoreHorizontal20Regular } from "@fluentui/react-icons";
|
||||
import { tokens } from "@fluentui/react-theme";
|
||||
import * as React from "react";
|
||||
|
||||
export interface TreeNode2MenuItem {
|
||||
@@ -27,7 +30,7 @@ export interface TreeNode2 {
|
||||
children?: TreeNode2[];
|
||||
contextMenu?: TreeNode2MenuItem[];
|
||||
iconSrc?: string;
|
||||
// isExpanded?: boolean;
|
||||
isExpanded?: boolean;
|
||||
className?: string;
|
||||
isAlphaSorted?: boolean;
|
||||
// data?: any; // Piece of data corresponding to this node
|
||||
@@ -37,7 +40,7 @@ export interface TreeNode2 {
|
||||
isScrollable?: boolean;
|
||||
isSelected?: () => boolean;
|
||||
onClick?: () => void; // Only if a leaf, other click will expand/collapse
|
||||
onExpanded?: () => void;
|
||||
onExpanded?: () => Promise<void>;
|
||||
onCollapsed?: () => void;
|
||||
onContextMenuOpen?: () => void;
|
||||
}
|
||||
@@ -46,7 +49,6 @@ export interface TreeNode2ComponentProps {
|
||||
node: TreeNode2;
|
||||
className?: string;
|
||||
treeNodeId: string;
|
||||
globalOpenIds: string[];
|
||||
}
|
||||
|
||||
const getTreeIcon = (iconSrc: string): JSX.Element => <img src={iconSrc} alt="" style={{ width: 20, height: 20 }} />;
|
||||
@@ -54,20 +56,8 @@ const getTreeIcon = (iconSrc: string): JSX.Element => <img src={iconSrc} alt=""
|
||||
export const TreeNode2Component: React.FC<TreeNode2ComponentProps> = ({
|
||||
node,
|
||||
treeNodeId,
|
||||
globalOpenIds,
|
||||
}: TreeNode2ComponentProps): JSX.Element => {
|
||||
// const defaultOpenItems = node.isExpanded ? children?.map((child: TreeNode2) => child.label) : undefined;
|
||||
const [isExpanded, setIsExpanded] = React.useState<boolean>(false);
|
||||
|
||||
// Compute whether node is expanded
|
||||
React.useEffect(() => {
|
||||
const isNowExpanded = globalOpenIds && globalOpenIds.includes(treeNodeId);
|
||||
if (!isExpanded && isNowExpanded) {
|
||||
// Catch the transition non-expanded to expanded
|
||||
node.onExpanded?.();
|
||||
}
|
||||
setIsExpanded(isNowExpanded);
|
||||
}, [globalOpenIds, treeNodeId, node, isExpanded]);
|
||||
const [isLoading, setIsLoading] = React.useState<boolean>(false);
|
||||
|
||||
const getSortedChildren = (treeNode: TreeNode2): TreeNode2[] => {
|
||||
if (!treeNode || !treeNode.children) {
|
||||
@@ -95,8 +85,24 @@ export const TreeNode2Component: React.FC<TreeNode2ComponentProps> = ({
|
||||
return unsortedChildren;
|
||||
};
|
||||
|
||||
const onOpenChange = (_: TreeOpenChangeEvent, data: TreeOpenChangeData) => {
|
||||
if (!node.isExpanded && data.open && node.onExpanded) {
|
||||
// Catch the transition non-expanded to expanded
|
||||
setIsLoading(true);
|
||||
node.onExpanded?.().then(() => setIsLoading(false));
|
||||
} else if (node.isExpanded && !data.open && node.onCollapsed) {
|
||||
// Catch the transition expanded to non-expanded
|
||||
node.onCollapsed?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TreeItem value={treeNodeId} itemType={node.children !== undefined ? "branch" : "leaf"} style={{ height: "100%" }}>
|
||||
<TreeItem
|
||||
value={treeNodeId}
|
||||
itemType={node.children !== undefined ? "branch" : "leaf"}
|
||||
style={{ height: "100%" }}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<TreeItemLayout
|
||||
className={node.className}
|
||||
actions={
|
||||
@@ -117,22 +123,21 @@ export const TreeNode2Component: React.FC<TreeNode2ComponentProps> = ({
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
expandIcon={node.isLoading ? <Spinner size="extra-tiny" /> : undefined}
|
||||
expandIcon={isLoading ? <Spinner size="extra-tiny" /> : undefined}
|
||||
iconBefore={node.iconSrc && getTreeIcon(node.iconSrc)}
|
||||
style={{
|
||||
backgroundColor: node.isSelected && node.isSelected() ? tokens.colorNeutralBackground1Selected : undefined,
|
||||
}}
|
||||
>
|
||||
<span onClick={() => node.onClick?.()}>{node.label}</span>
|
||||
</TreeItemLayout>
|
||||
{!node.isLoading && node.children?.length > 0 && (
|
||||
<Tree
|
||||
// defaultOpenItems={defaultOpenItems}
|
||||
style={{ overflow: node.isScrollable ? "auto" : undefined }}
|
||||
>
|
||||
<Tree style={{ overflow: node.isScrollable ? "auto" : undefined }}>
|
||||
{getSortedChildren(node).map((childNode: TreeNode2) => (
|
||||
<TreeNode2Component
|
||||
key={childNode.label}
|
||||
node={childNode}
|
||||
treeNodeId={`${treeNodeId}/${childNode.label}`}
|
||||
globalOpenIds={globalOpenIds}
|
||||
/>
|
||||
))}
|
||||
</Tree>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Link } from "@fluentui/react/lib/Link";
|
||||
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
|
||||
import { sendMessage } from "Common/MessageHandler";
|
||||
import { Platform } from "ConfigContext";
|
||||
import { Platform, configContext } from "ConfigContext";
|
||||
import { MessageTypes } from "Contracts/ExplorerContracts";
|
||||
import { IGalleryItem } from "Juno/JunoClient";
|
||||
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValidation";
|
||||
@@ -1343,9 +1343,10 @@ export default class Explorer {
|
||||
|
||||
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount
|
||||
const isNotebookEnabled =
|
||||
userContext.features.notebooksDownBanner ||
|
||||
useNotebook.getState().isPhoenixNotebooks ||
|
||||
useNotebook.getState().isPhoenixFeatures;
|
||||
configContext.platform !== Platform.Fabric &&
|
||||
(userContext.features.notebooksDownBanner ||
|
||||
useNotebook.getState().isPhoenixNotebooks ||
|
||||
useNotebook.getState().isPhoenixFeatures);
|
||||
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
|
||||
useNotebook
|
||||
.getState()
|
||||
|
||||
@@ -8,7 +8,9 @@ import { useNotebook } from "Explorer/Notebook/useNotebook";
|
||||
import { userContext } from "UserContext";
|
||||
import * as React from "react";
|
||||
import create, { UseStore } from "zustand";
|
||||
import { ConnectionStatusType, PoolIdType, StyleConstants } from "../../../Common/Constants";
|
||||
import { ConnectionStatusType, PoolIdType } from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
import { Platform, configContext } from "../../../ConfigContext";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import Explorer from "../../Explorer";
|
||||
import { useSelectedNode } from "../../useSelectedNode";
|
||||
@@ -84,15 +86,27 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||
);
|
||||
}
|
||||
|
||||
const rootStyle =
|
||||
configContext.platform === Platform.Fabric
|
||||
? {
|
||||
root: {
|
||||
backgroundColor: "transparent",
|
||||
padding: "0px 14px 0px 14px",
|
||||
},
|
||||
}
|
||||
: {
|
||||
root: {
|
||||
backgroundColor: backgroundColor,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="commandBarContainer">
|
||||
<FluentCommandBar
|
||||
ariaLabel="Use left and right arrow keys to navigate between commands"
|
||||
items={uiFabricStaticButtons.concat(uiFabricTabsButtons)}
|
||||
farItems={uiFabricControlButtons}
|
||||
styles={{
|
||||
root: { backgroundColor: backgroundColor },
|
||||
}}
|
||||
styles={rootStyle}
|
||||
overflowButtonProps={{ ariaLabel: "More commands" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -343,6 +343,31 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Open Postgres and vCore Mongo buttons", () => {
|
||||
const openPostgresShellButtonLabel = "Open PSQL shell";
|
||||
const openVCoreMongoShellButtonLabel = "Open MongoDB (vcore) shell";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = {} as Explorer;
|
||||
});
|
||||
|
||||
it("creates Postgres shell button", () => {
|
||||
const buttons = CommandBarComponentButtonFactory.createPostgreButtons(mockExplorer);
|
||||
const openPostgresShellButton = buttons.find(
|
||||
(button) => button.commandButtonLabel === openPostgresShellButtonLabel
|
||||
);
|
||||
expect(openPostgresShellButton).toBeDefined();
|
||||
});
|
||||
|
||||
it("creates vCore Mongo shell button", () => {
|
||||
const buttons = CommandBarComponentButtonFactory.createVCoreMongoButtons(mockExplorer);
|
||||
const openVCoreMongoShellButton = buttons.find(
|
||||
(button) => button.commandButtonLabel === openVCoreMongoShellButtonLabel
|
||||
);
|
||||
expect(openVCoreMongoShellButton).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("GitHub buttons", () => {
|
||||
const connectToGitHubBtnLabel = "Connect to GitHub";
|
||||
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";
|
||||
|
||||
@@ -54,7 +54,11 @@ export function createStaticCommandBarButtons(
|
||||
const buttons: CommandButtonComponentProps[] = [];
|
||||
|
||||
buttons.push(newCollectionBtn);
|
||||
if (userContext.apiType !== "Tables" && userContext.apiType !== "Cassandra") {
|
||||
if (
|
||||
configContext.platform !== Platform.Fabric &&
|
||||
userContext.apiType !== "Tables" &&
|
||||
userContext.apiType !== "Cassandra"
|
||||
) {
|
||||
const addSynapseLink = createOpenSynapseLinkDialogButton(container);
|
||||
|
||||
if (addSynapseLink) {
|
||||
@@ -257,7 +261,9 @@ export function createDivider(): CommandButtonComponentProps {
|
||||
}
|
||||
|
||||
function areScriptsSupported(): boolean {
|
||||
return userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
||||
return (
|
||||
configContext.platform !== Platform.Fabric && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
|
||||
);
|
||||
}
|
||||
|
||||
function createNewCollectionGroup(container: Explorer): CommandButtonComponentProps {
|
||||
|
||||
@@ -9,7 +9,9 @@ import {
|
||||
import * as React from "react";
|
||||
import _ from "underscore";
|
||||
import ChevronDownIcon from "../../../../images/Chevron_down.svg";
|
||||
import { PoolIdType, StyleConstants } from "../../../Common/Constants";
|
||||
import { PoolIdType } from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
import { configContext, Platform } from "../../../ConfigContext";
|
||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
@@ -24,11 +26,14 @@ import { MemoryTracker } from "./MemoryTrackerComponent";
|
||||
export const convertButton = (btns: CommandButtonComponentProps[], backgroundColor: string): ICommandBarItemProps[] => {
|
||||
const buttonHeightPx = StyleConstants.CommandBarButtonHeight;
|
||||
|
||||
const hoverColor =
|
||||
configContext.platform == Platform.Fabric ? StyleConstants.FabricAccentLight : StyleConstants.AccentLight;
|
||||
|
||||
const getFilter = (isDisabled: boolean): string => {
|
||||
if (isDisabled) {
|
||||
return StyleConstants.GrayScale;
|
||||
}
|
||||
return undefined;
|
||||
return configContext.platform == Platform.Fabric ? StyleConstants.NoColor : undefined;
|
||||
};
|
||||
|
||||
return btns
|
||||
@@ -68,6 +73,7 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
|
||||
height: buttonHeightPx,
|
||||
paddingRight: 0,
|
||||
paddingLeft: 0,
|
||||
borderRadius: configContext.platform == Platform.Fabric ? StyleConstants.FabricButtonBorderRadius : "0px",
|
||||
minWidth: 24,
|
||||
marginLeft: isSplit ? 0 : 5,
|
||||
marginRight: isSplit ? 0 : 5,
|
||||
@@ -79,17 +85,17 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
|
||||
splitButtonMenuButton: {
|
||||
backgroundColor: backgroundColor,
|
||||
selectors: {
|
||||
":hover": { backgroundColor: StyleConstants.AccentLight },
|
||||
":hover": { backgroundColor: hoverColor },
|
||||
},
|
||||
width: 16,
|
||||
},
|
||||
label: { fontSize: StyleConstants.mediumFontSize },
|
||||
rootHovered: { backgroundColor: StyleConstants.AccentLight },
|
||||
rootPressed: { backgroundColor: StyleConstants.AccentLight },
|
||||
rootHovered: { backgroundColor: hoverColor },
|
||||
rootPressed: { backgroundColor: hoverColor },
|
||||
splitButtonMenuButtonExpanded: {
|
||||
backgroundColor: StyleConstants.AccentExtra,
|
||||
selectors: {
|
||||
":hover": { backgroundColor: StyleConstants.AccentLight },
|
||||
":hover": { backgroundColor: hoverColor },
|
||||
},
|
||||
},
|
||||
splitButtonDivider: {
|
||||
@@ -120,7 +126,7 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
|
||||
// TODO Remove all this crazy styling once we adopt Ui-Fabric Azure themes
|
||||
selectors: {
|
||||
".ms-ContextualMenu-itemText": { fontSize: StyleConstants.mediumFontSize },
|
||||
".ms-ContextualMenu-link:hover": { backgroundColor: StyleConstants.AccentLight },
|
||||
".ms-ContextualMenu-link:hover": { backgroundColor: hoverColor },
|
||||
".ms-ContextualMenu-icon": { width: 16, height: 16 },
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import distanceInWordsToNow from "date-fns/distance_in_words_to_now";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
|
||||
interface Props {
|
||||
lastSaved?: Date | null;
|
||||
|
||||
@@ -33,6 +33,7 @@ import { isCapabilityEnabled, isServerlessAccount } from "Utils/CapabilityUtils"
|
||||
import { getUpsellMessage } from "Utils/PricingUtils";
|
||||
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
||||
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
|
||||
import "../Controls/ThroughputInput/ThroughputInput.less";
|
||||
import { ContainerSampleGenerator } from "../DataSamples/ContainerSampleGenerator";
|
||||
import Explorer from "../Explorer";
|
||||
import { useDatabases } from "../useDatabases";
|
||||
@@ -318,7 +319,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
placeholder="Type a new database id"
|
||||
size={40}
|
||||
className="panelTextField"
|
||||
aria-label="New database id"
|
||||
aria-label="New database id, Type a new database id"
|
||||
autoFocus
|
||||
tabIndex={0}
|
||||
value={this.state.newDatabaseId}
|
||||
@@ -424,7 +425,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
placeholder={`e.g., ${getCollectionName()}1`}
|
||||
size={40}
|
||||
className="panelTextField"
|
||||
aria-label={`${getCollectionName()} id`}
|
||||
aria-label={`${getCollectionName()} id, Example ${getCollectionName()}1`}
|
||||
value={this.state.collectionId}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
this.setState({ collectionId: event.target.value })
|
||||
@@ -843,7 +844,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
<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">
|
||||
<Link
|
||||
href="https://aka.ms/cosmosdb-synapselink"
|
||||
target="_blank"
|
||||
className="capacitycalculator-link"
|
||||
>
|
||||
Learn more
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
@@ -307,7 +307,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
||||
multiline
|
||||
id="editor-area"
|
||||
rows={5}
|
||||
aria-label="Table Schema"
|
||||
ariaLabel="Table schema"
|
||||
value={userTableQuery}
|
||||
onChange={(e, newValue) => setUserTableQuery(newValue)}
|
||||
/>
|
||||
|
||||
@@ -52,7 +52,7 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
const shouldShowCrossPartitionOption = userContext.apiType !== "Gremlin";
|
||||
const shouldShowParallelismOption = userContext.apiType !== "Gremlin";
|
||||
const shouldShowPriorityLevelOption =
|
||||
userContext.features.enablePriorityBasedThrottling && userContext.apiType === "SQL";
|
||||
userContext.databaseAccount?.properties?.enablePriorityBasedExecution && userContext.apiType === "SQL";
|
||||
const handlerOnSubmit = (e: MouseEvent<HTMLButtonElement>) => {
|
||||
setIsExecuting(true);
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@fluentui/react";
|
||||
import {
|
||||
DetailsList,
|
||||
DetailsListLayoutMode,
|
||||
DirectionalHint,
|
||||
IColumn,
|
||||
SelectionMode,
|
||||
TooltipHost,
|
||||
} from "@fluentui/react";
|
||||
import { Upload } from "Common/Upload/Upload";
|
||||
import { UploadDetailsRecord } from "Contracts/ViewModels";
|
||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||
import { logConsoleError } from "Utils/NotificationConsoleUtils";
|
||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||
import { getErrorMessage } from "../../Tables/Utilities";
|
||||
import { useSelectedNode } from "../../useSelectedNode";
|
||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||
@@ -74,12 +81,21 @@ export const UploadItemsPane: FunctionComponent = () => {
|
||||
];
|
||||
|
||||
const _renderItemColumn = (item: UploadDetailsRecord, index: number, column: IColumn) => {
|
||||
let fieldContent: string;
|
||||
const tooltipId = `tooltip-${index}-${column.key}`;
|
||||
|
||||
switch (column.key) {
|
||||
case "status":
|
||||
return `${item.numSucceeded} created, ${item.numThrottled} throttled, ${item.numFailed} errors`;
|
||||
fieldContent = `${item.numSucceeded} created, ${item.numThrottled} throttled, ${item.numFailed} errors`;
|
||||
break;
|
||||
default:
|
||||
return item.fileName;
|
||||
fieldContent = item.fileName;
|
||||
}
|
||||
return (
|
||||
<TooltipHost content={fieldContent} id={tooltipId} directionalHint={DirectionalHint.rightCenter}>
|
||||
{fieldContent}
|
||||
</TooltipHost>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -84,7 +84,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
className="panelGroupSpacing"
|
||||
>
|
||||
<input
|
||||
aria-label="New database id"
|
||||
aria-label="New database id, Type a new database id"
|
||||
aria-required={true}
|
||||
autoComplete="off"
|
||||
autoFocus={true}
|
||||
@@ -178,7 +178,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
</StyledTooltipHostBase>
|
||||
</Stack>
|
||||
<input
|
||||
aria-label="Container id"
|
||||
aria-label="Container id, Example Container1"
|
||||
aria-required={true}
|
||||
autoComplete="off"
|
||||
className="panelTextField"
|
||||
@@ -400,6 +400,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
. Enable Synapse Link for this Cosmos DB account.
|
||||
|
||||
<StyledLinkBase
|
||||
className="capacitycalculator-link"
|
||||
href="https://aka.ms/cosmosdb-synapselink"
|
||||
target="_blank"
|
||||
>
|
||||
|
||||
@@ -11,8 +11,9 @@ import {
|
||||
Stack,
|
||||
Text,
|
||||
} from "@fluentui/react";
|
||||
import { QueryCopilotSampleDatabaseId, StyleConstants } from "Common/Constants";
|
||||
import { QueryCopilotSampleDatabaseId } from "Common/Constants";
|
||||
import { handleError } from "Common/ErrorHandlingUtils";
|
||||
import { StyleConstants } from "Common/StyleConstants";
|
||||
import { createCollection } from "Common/dataAccess/createCollection";
|
||||
import * as DataModels from "Contracts/DataModels";
|
||||
import { ContainerSampleGenerator } from "Explorer/DataSamples/ContainerSampleGenerator";
|
||||
|
||||
@@ -60,7 +60,9 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
|
||||
<Text>
|
||||
Ask Copilot to generate a query by describing the query in your words.
|
||||
<br />
|
||||
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-learn-more">
|
||||
Learn more
|
||||
</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item align="center" className="text">
|
||||
@@ -78,7 +80,9 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
|
||||
<Text>
|
||||
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
||||
<br />
|
||||
<Link href="http://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
|
||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-preview-terms">
|
||||
Read preview terms
|
||||
</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item align="center" className="text">
|
||||
@@ -97,7 +101,9 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
|
||||
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you
|
||||
at no cost.
|
||||
<br />
|
||||
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-learn-more">
|
||||
Learn more
|
||||
</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
|
||||
@@ -102,7 +102,8 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
||||
Ask Copilot to generate a query by describing the query in your words.
|
||||
<br />
|
||||
<StyledLinkBase
|
||||
href="http://aka.ms/cdb-copilot-learn-more"
|
||||
href="https://aka.ms/cdb-copilot-learn-more"
|
||||
target="_blank"
|
||||
>
|
||||
Learn more
|
||||
</StyledLinkBase>
|
||||
@@ -138,7 +139,8 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
||||
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
||||
<br />
|
||||
<StyledLinkBase
|
||||
href="http://aka.ms/cdb-copilot-preview-terms"
|
||||
href="https://aka.ms/cdb-copilot-preview-terms"
|
||||
target="_blank"
|
||||
>
|
||||
Read preview terms
|
||||
</StyledLinkBase>
|
||||
@@ -174,7 +176,8 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
||||
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you at no cost.
|
||||
<br />
|
||||
<StyledLinkBase
|
||||
href="http://aka.ms/cdb-copilot-learn-more"
|
||||
href="https://aka.ms/cdb-copilot-learn-more"
|
||||
target="_blank"
|
||||
>
|
||||
Learn more
|
||||
</StyledLinkBase>
|
||||
|
||||
@@ -434,7 +434,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
|
||||
}}
|
||||
>
|
||||
Learn about{" "}
|
||||
<Link target="_blank" href="http://aka.ms/cdb-copilot-writing">
|
||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-writing">
|
||||
writing effective prompts
|
||||
</Link>
|
||||
</Text>
|
||||
@@ -448,7 +448,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
|
||||
<Stack style={{ marginTop: 8, marginBottom: 24 }}>
|
||||
<Text style={{ fontSize: 12 }}>
|
||||
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.{" "}
|
||||
<Link href="http://aka.ms/cdb-copilot-preview-terms" target="_blank">
|
||||
<Link href="https://aka.ms/cdb-copilot-preview-terms" target="_blank">
|
||||
Read preview terms
|
||||
</Link>
|
||||
{showErrorMessageBar && (
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { Text } from "@fluentui/react";
|
||||
import { shallow } from "enzyme";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
import { ExplanationButton } from "./ExplanationButton";
|
||||
|
||||
describe("Explanation Button", () => {
|
||||
const initialStoreState = useQueryCopilot.getState();
|
||||
beforeEach(() => {
|
||||
useQueryCopilot.setState(initialStoreState, true);
|
||||
useQueryCopilot.getState().showExplanationBubble = true;
|
||||
useQueryCopilot.getState().shouldIncludeInMessages = false;
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it("should render explanation bubble with generated comments", () => {
|
||||
useQueryCopilot.getState().shouldIncludeInMessages = true;
|
||||
|
||||
const wrapper = shallow(<ExplanationButton />);
|
||||
|
||||
expect(wrapper.find("Stack")).toHaveLength(1);
|
||||
expect(wrapper.find("Text")).toHaveLength(1);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render 'Explain this query' link", () => {
|
||||
useQueryCopilot.getState().shouldIncludeInMessages = true;
|
||||
const mockSetChatMessages = jest.fn();
|
||||
const mockSetIsGeneratingExplanation = jest.fn();
|
||||
const mockSetShouldIncludeInMessages = jest.fn();
|
||||
const mockSetShowExplanationBubble = jest.fn();
|
||||
useQueryCopilot.getState().setChatMessages = mockSetChatMessages;
|
||||
useQueryCopilot.getState().setIsGeneratingExplanation = mockSetIsGeneratingExplanation;
|
||||
useQueryCopilot.getState().setShouldIncludeInMessages = mockSetShouldIncludeInMessages;
|
||||
useQueryCopilot.getState().setShowExplanationBubble = mockSetShowExplanationBubble;
|
||||
|
||||
const wrapper = shallow(<ExplanationButton />);
|
||||
|
||||
const textElement = wrapper.find(Text);
|
||||
textElement.simulate("click");
|
||||
|
||||
expect(mockSetChatMessages).toHaveBeenCalledWith([
|
||||
...initialStoreState.chatMessages,
|
||||
{ source: 0, message: "Explain this query to me" },
|
||||
]);
|
||||
expect(mockSetIsGeneratingExplanation).toHaveBeenCalledWith(true);
|
||||
expect(mockSetShouldIncludeInMessages).toHaveBeenCalledWith(true);
|
||||
expect(mockSetShowExplanationBubble).toHaveBeenCalledWith(false);
|
||||
|
||||
jest.advanceTimersByTime(3000);
|
||||
|
||||
expect(mockSetIsGeneratingExplanation).toHaveBeenCalledWith(false);
|
||||
expect(mockSetChatMessages).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should render nothing when conditions are not met", () => {
|
||||
useQueryCopilot.getState().showExplanationBubble = false;
|
||||
|
||||
const wrapper = shallow(<ExplanationButton />);
|
||||
|
||||
expect(wrapper.isEmptyRender()).toBe(true);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -2,12 +2,13 @@ import { Stack, Text } from "@fluentui/react";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
|
||||
export const ExplanationBubble: React.FC = (): JSX.Element => {
|
||||
export const ExplanationButton: React.FC = (): JSX.Element => {
|
||||
const {
|
||||
showExplanationBubble,
|
||||
isGeneratingQuery,
|
||||
chatMessages,
|
||||
setChatMessages,
|
||||
generatedQuery,
|
||||
generatedQueryComments,
|
||||
isGeneratingExplanation,
|
||||
setIsGeneratingExplanation,
|
||||
@@ -24,7 +25,7 @@ export const ExplanationBubble: React.FC = (): JSX.Element => {
|
||||
setTimeout(() => {
|
||||
if (useQueryCopilot.getState().shouldIncludeInMessages) {
|
||||
setIsGeneratingExplanation(false);
|
||||
setChatMessages([...chatMessages, { source: 2, message: generatedQueryComments }]);
|
||||
setChatMessages([...chatMessages, { source: 2, message: generatedQueryComments, sqlQuery: generatedQuery }]);
|
||||
}
|
||||
}, 3000);
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Explanation Button should render explanation bubble with generated comments 1`] = `
|
||||
<Stack
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "flex",
|
||||
"margin": "5px",
|
||||
"padding": "5px 5px 5px 50px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"border": "1.5px solid #B0BEFF",
|
||||
"borderRadius": "4px",
|
||||
"cursor": "pointer",
|
||||
"marginBottom": "5px",
|
||||
"padding": "2px",
|
||||
"width": "100%",
|
||||
}
|
||||
}
|
||||
>
|
||||
Explain this query to me
|
||||
</Text>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Explanation Button should render nothing when conditions are not met 1`] = `""`;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Stack, Text } from "@fluentui/react";
|
||||
import { CopilotMessage } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
|
||||
import { FeedbackButtons } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Feedback/FeedbackButtons";
|
||||
import React from "react";
|
||||
|
||||
export const ExplanationBubble = ({ copilotMessage }: { copilotMessage: CopilotMessage }): JSX.Element => {
|
||||
return (
|
||||
<Stack
|
||||
horizontalAlign="start"
|
||||
verticalAlign="start"
|
||||
tokens={{ padding: 8, childrenGap: 8 }}
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
borderRadius: "8px",
|
||||
margin: "5px 10px",
|
||||
textAlign: "start",
|
||||
}}
|
||||
>
|
||||
<Text>{copilotMessage.message}</Text>
|
||||
<FeedbackButtons sqlQuery={copilotMessage.sqlQuery} />
|
||||
<Text style={{ fontWeight: 400, fontSize: "10px", lineHeight: "14px" }}>
|
||||
AI-generated content may be incorrect
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -1,69 +1,17 @@
|
||||
import { Text } from "@fluentui/react";
|
||||
import { CopilotMessage } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
|
||||
import { ExplanationBubble } from "Explorer/QueryCopilot/V2/Bubbles/Explanation/ExplainationBubble";
|
||||
import { shallow } from "enzyme";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
import { ExplanationBubble } from "./ExplanationBubble";
|
||||
|
||||
describe("Explanation Bubble", () => {
|
||||
const initialStoreState = useQueryCopilot.getState();
|
||||
beforeEach(() => {
|
||||
useQueryCopilot.setState(initialStoreState, true);
|
||||
useQueryCopilot.getState().showExplanationBubble = true;
|
||||
useQueryCopilot.getState().shouldIncludeInMessages = false;
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
describe("Explanation Bubble snapshot tests", () => {
|
||||
it("should render", () => {
|
||||
const mockCopilotMessage: CopilotMessage = {
|
||||
source: 2,
|
||||
message: "Mock message",
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
const wrapper = shallow(<ExplanationBubble copilotMessage={mockCopilotMessage} />);
|
||||
|
||||
it("should render explanation bubble with generated comments", () => {
|
||||
useQueryCopilot.getState().shouldIncludeInMessages = true;
|
||||
|
||||
const wrapper = shallow(<ExplanationBubble />);
|
||||
|
||||
expect(wrapper.find("Stack")).toHaveLength(1);
|
||||
expect(wrapper.find("Text")).toHaveLength(1);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render 'Explain this query' link", () => {
|
||||
useQueryCopilot.getState().shouldIncludeInMessages = true;
|
||||
const mockSetChatMessages = jest.fn();
|
||||
const mockSetIsGeneratingExplanation = jest.fn();
|
||||
const mockSetShouldIncludeInMessages = jest.fn();
|
||||
const mockSetShowExplanationBubble = jest.fn();
|
||||
useQueryCopilot.getState().setChatMessages = mockSetChatMessages;
|
||||
useQueryCopilot.getState().setIsGeneratingExplanation = mockSetIsGeneratingExplanation;
|
||||
useQueryCopilot.getState().setShouldIncludeInMessages = mockSetShouldIncludeInMessages;
|
||||
useQueryCopilot.getState().setShowExplanationBubble = mockSetShowExplanationBubble;
|
||||
|
||||
const wrapper = shallow(<ExplanationBubble />);
|
||||
|
||||
const textElement = wrapper.find(Text);
|
||||
textElement.simulate("click");
|
||||
|
||||
expect(mockSetChatMessages).toHaveBeenCalledWith([
|
||||
...initialStoreState.chatMessages,
|
||||
{ source: 0, message: "Explain this query to me" },
|
||||
]);
|
||||
expect(mockSetIsGeneratingExplanation).toHaveBeenCalledWith(true);
|
||||
expect(mockSetShouldIncludeInMessages).toHaveBeenCalledWith(true);
|
||||
expect(mockSetShowExplanationBubble).toHaveBeenCalledWith(false);
|
||||
|
||||
jest.advanceTimersByTime(3000);
|
||||
|
||||
expect(mockSetIsGeneratingExplanation).toHaveBeenCalledWith(false);
|
||||
expect(mockSetChatMessages).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should render nothing when conditions are not met", () => {
|
||||
useQueryCopilot.getState().showExplanationBubble = false;
|
||||
|
||||
const wrapper = shallow(<ExplanationBubble />);
|
||||
|
||||
expect(wrapper.isEmptyRender()).toBe(true);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,32 +1,38 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Explanation Bubble should render explanation bubble with generated comments 1`] = `
|
||||
exports[`Explanation Bubble snapshot tests should render 1`] = `
|
||||
<Stack
|
||||
horizontalAlign="start"
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "flex",
|
||||
"margin": "5px",
|
||||
"padding": "5px 5px 5px 50px",
|
||||
"backgroundColor": "white",
|
||||
"borderRadius": "8px",
|
||||
"margin": "5px 10px",
|
||||
"textAlign": "start",
|
||||
}
|
||||
}
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 8,
|
||||
"padding": 8,
|
||||
}
|
||||
}
|
||||
verticalAlign="start"
|
||||
>
|
||||
<Text>
|
||||
Mock message
|
||||
</Text>
|
||||
<FeedbackButtons />
|
||||
<Text
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"border": "1.5px solid #B0BEFF",
|
||||
"borderRadius": "4px",
|
||||
"cursor": "pointer",
|
||||
"marginBottom": "5px",
|
||||
"padding": "2px",
|
||||
"width": "100%",
|
||||
"fontSize": "10px",
|
||||
"fontWeight": 400,
|
||||
"lineHeight": "14px",
|
||||
}
|
||||
}
|
||||
>
|
||||
Explain this query to me
|
||||
AI-generated content may be incorrect
|
||||
</Text>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Explanation Bubble should render nothing when conditions are not met 1`] = `""`;
|
||||
|
||||
@@ -2,18 +2,31 @@ import { Stack, Text } from "@fluentui/react";
|
||||
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
||||
import { CopilotMessage } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
|
||||
import { OutputBubbleButtons } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/OutputBubbleButtons";
|
||||
import { userContext } from "UserContext";
|
||||
import React, { useState } from "react";
|
||||
|
||||
export const OutputBubble = ({ copilotMessage }: { copilotMessage: CopilotMessage }): JSX.Element => {
|
||||
const [windowHeight, setWindowHeight] = useState<string>();
|
||||
const textHeightWithPadding = 16;
|
||||
|
||||
const calculateQueryWindowHeight = (): string => {
|
||||
const calculatedHeight = document.getElementById("outputBubble")?.clientHeight * (3 / 5);
|
||||
return `${calculatedHeight}px`;
|
||||
const outputWidth = document.getElementById("outputBubble")?.clientWidth;
|
||||
const responseLength = copilotMessage.sqlQuery.length;
|
||||
|
||||
if (outputWidth > responseLength) {
|
||||
return `${textHeightWithPadding * 3}px`;
|
||||
} else {
|
||||
const neededLines = Math.ceil(responseLength / outputWidth);
|
||||
return `${neededLines * textHeightWithPadding}px`;
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
setWindowHeight(calculateQueryWindowHeight());
|
||||
if (userContext.features.copilotChatFixedMonacoEditorHeight) {
|
||||
setWindowHeight(`${textHeightWithPadding * 5}px`);
|
||||
} else {
|
||||
setWindowHeight(calculateQueryWindowHeight());
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -65,7 +65,9 @@ export const WelcomeSidebarModal: React.FC = (): JSX.Element => {
|
||||
<Text>
|
||||
Ask Copilot to generate a query by describing the query in your words.
|
||||
<br />
|
||||
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-learn-more">
|
||||
Learn more
|
||||
</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
@@ -87,7 +89,9 @@ export const WelcomeSidebarModal: React.FC = (): JSX.Element => {
|
||||
<Text>
|
||||
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
||||
<br />
|
||||
<Link href="http://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
|
||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-preview-terms">
|
||||
Read preview terms
|
||||
</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
@@ -109,7 +113,9 @@ export const WelcomeSidebarModal: React.FC = (): JSX.Element => {
|
||||
<Text>
|
||||
Copilot is setup on a sample database we have configured for you at no cost
|
||||
<br />
|
||||
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-learn-more">
|
||||
Learn more
|
||||
</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Stack } from "@fluentui/react";
|
||||
import { QueryCopilotProps } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
|
||||
import { ExplanationBubble } from "Explorer/QueryCopilot/V2/Bubbles/Explanation/ExplanationBubble";
|
||||
import { ExplanationButton } from "Explorer/QueryCopilot/V2/Bubbles/Explanation/Button/ExplanationButton";
|
||||
import { ExplanationBubble } from "Explorer/QueryCopilot/V2/Bubbles/Explanation/ExplainationBubble";
|
||||
import { OutputBubble } from "Explorer/QueryCopilot/V2/Bubbles/Output/OutputBubble";
|
||||
import { RetrievingBubble } from "Explorer/QueryCopilot/V2/Bubbles/Retriveing/RetrievingBubble";
|
||||
import { SampleBubble } from "Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble";
|
||||
@@ -42,27 +43,34 @@ export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: Q
|
||||
}}
|
||||
>
|
||||
<WelcomeBubble />
|
||||
{chatMessages.map((message, index) =>
|
||||
message.source === 0 || message.source === 2 ? (
|
||||
<Stack
|
||||
key={index}
|
||||
horizontalAlign="center"
|
||||
tokens={{ padding: 8, childrenGap: 8 }}
|
||||
style={{
|
||||
backgroundColor: message.source === 0 ? "#E0E7FF" : "white",
|
||||
borderRadius: "8px",
|
||||
margin: "5px 10px",
|
||||
textAlign: "start",
|
||||
}}
|
||||
>
|
||||
{message.message}
|
||||
</Stack>
|
||||
) : (
|
||||
<OutputBubble key={index} copilotMessage={message} />
|
||||
)
|
||||
)}
|
||||
{chatMessages.map((message, index) => {
|
||||
switch (message.source) {
|
||||
case 0:
|
||||
return (
|
||||
<Stack
|
||||
key={index}
|
||||
horizontalAlign="center"
|
||||
tokens={{ padding: 8, childrenGap: 8 }}
|
||||
style={{
|
||||
backgroundColor: "#E0E7FF",
|
||||
borderRadius: "8px",
|
||||
margin: "5px 10px",
|
||||
textAlign: "start",
|
||||
}}
|
||||
>
|
||||
{message.message}
|
||||
</Stack>
|
||||
);
|
||||
case 1:
|
||||
return <OutputBubble key={index} copilotMessage={message} />;
|
||||
case 2:
|
||||
return <ExplanationBubble key={index} copilotMessage={message} />;
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
})}
|
||||
<RetrievingBubble />
|
||||
<ExplanationBubble />
|
||||
<ExplanationButton />
|
||||
|
||||
{chatMessages.length === 0 && !isGeneratingQuery && <SampleBubble />}
|
||||
</Stack>
|
||||
|
||||
@@ -102,7 +102,7 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
|
||||
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.
|
||||
|
||||
<StyledLinkBase
|
||||
href="http://aka.ms/cdb-copilot-preview-terms"
|
||||
href="https://aka.ms/cdb-copilot-preview-terms"
|
||||
target="_blank"
|
||||
>
|
||||
Read preview terms
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import * as ko from "knockout";
|
||||
import * as _ from "underscore";
|
||||
|
||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||
import * as Constants from "../Constants";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import * as Entities from "../Entities";
|
||||
import * as Utilities from "../Utilities";
|
||||
import * as DataTableBuilder from "./DataTableBuilder";
|
||||
import DataTableOperationManager from "./DataTableOperationManager";
|
||||
import * as DataTableOperations from "./DataTableOperations";
|
||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||
import TableEntityListViewModel from "./TableEntityListViewModel";
|
||||
import * as Utilities from "../Utilities";
|
||||
import * as Entities from "../Entities";
|
||||
|
||||
/**
|
||||
* Custom binding manager of datatable
|
||||
@@ -41,7 +40,6 @@ function bindDataTable(element: any, valueAccessor: any, allBindings: any, viewM
|
||||
|
||||
createDataTable(0, tableEntityListViewModel, queryTablesTab); // Fake a DataTable to start.
|
||||
$(window).resize(updateTableScrollableRegionMetrics);
|
||||
operationManager.focusTable(); // Also selects the first row if needed.
|
||||
}
|
||||
|
||||
function onTableColumnChange(enablePrompt: boolean = true, queryTablesTab: QueryTablesTab) {
|
||||
@@ -364,10 +362,6 @@ function updateDataTableFocus(queryTablesTabId: string): void {
|
||||
if ($activeElement.is(".sorting_asc") || $activeElement.is(".sorting_desc")) {
|
||||
// If table header is selected, focus is shifted to the selected element as part of accessibility
|
||||
$activeElement && $activeElement.focus();
|
||||
} else {
|
||||
// If some control is active, we don't give focus back to the table,
|
||||
// just select the first row if needed (empty selection).
|
||||
operationManager.selectFirstIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,17 @@ import {
|
||||
DetailsList,
|
||||
DetailsListLayoutMode,
|
||||
IColumn,
|
||||
Icon,
|
||||
Link,
|
||||
Pivot,
|
||||
PivotItem,
|
||||
SelectionMode,
|
||||
Stack,
|
||||
Text,
|
||||
TooltipHost,
|
||||
} from "@fluentui/react";
|
||||
import { HttpHeaders, NormalizedEventKey } from "Common/Constants";
|
||||
import MongoUtility from "Common/MongoUtility";
|
||||
import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
|
||||
import { QueryMetrics } from "Contracts/DataModels";
|
||||
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
||||
import { IDocument } from "Explorer/Tabs/QueryTab/QueryTabComponent";
|
||||
@@ -51,11 +53,33 @@ export const QueryResultSection: React.FC<QueryResultProps> = ({
|
||||
|
||||
const onRender = (item: IDocument): JSX.Element => (
|
||||
<>
|
||||
<InfoTooltip>{`${item.toolTip}`}</InfoTooltip>
|
||||
<Text style={{ paddingLeft: 10, margin: 0 }}>{`${item.metric}`}</Text>
|
||||
</>
|
||||
);
|
||||
const columns: IColumn[] = [
|
||||
{
|
||||
key: "column1",
|
||||
name: "",
|
||||
minWidth: 10,
|
||||
maxWidth: 12,
|
||||
data: String,
|
||||
fieldName: "",
|
||||
onRender: (item: IDocument) => {
|
||||
if (item.toolTip !== "") {
|
||||
return (
|
||||
<>
|
||||
<TooltipHost content={`${item.toolTip}`}>
|
||||
<Link style={{ color: "#323130" }}>
|
||||
<Icon iconName="Info" ariaLabel={`${item.toolTip}`} className="panelInfoIcon" tabIndex={0} />
|
||||
</Link>
|
||||
</TooltipHost>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "column2",
|
||||
name: "METRIC",
|
||||
|
||||
91
src/Explorer/Tabs/Shared/CheckFirewallRules.test.ts
Normal file
91
src/Explorer/Tabs/Shared/CheckFirewallRules.test.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { DatabaseAccount, FirewallRule } from "Contracts/DataModels";
|
||||
import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules";
|
||||
import { updateUserContext } from "UserContext";
|
||||
import { mockFunction } from "Utils/JestUtils";
|
||||
import { armRequest } from "Utils/arm/request";
|
||||
import React from "react";
|
||||
|
||||
jest.mock("Utils/arm/request");
|
||||
const armRequestMock = mockFunction(armRequest);
|
||||
|
||||
describe("CheckFirewallRule tests", () => {
|
||||
const apiVersion = "2023-03-15-preview";
|
||||
const rulePredicate = (rule: FirewallRule) =>
|
||||
rule.properties.startIpAddress === "0.0.0.0" && rule.properties.endIpAddress === "255.255.255.255";
|
||||
let isAllPublicIPAddressEnabled: boolean;
|
||||
const setIsAllPublicIPAddressEnabled = jest.fn((value) => (isAllPublicIPAddressEnabled = value));
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const useStateMock: any = (initState: any) => [initState, setIsAllPublicIPAddressEnabled];
|
||||
jest.spyOn(React, "useState").mockImplementation(useStateMock);
|
||||
|
||||
beforeAll(() => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
id: "testResourceId",
|
||||
} as DatabaseAccount,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns 'all public IP addresses' is enabled for account with the proper firewall rule", async () => {
|
||||
armRequestMock.mockResolvedValueOnce({
|
||||
value: [
|
||||
{
|
||||
id: "resourceId",
|
||||
name: "AllowAll",
|
||||
type: "Microsoft.DocumentDB/mongoClusters/firewallRules",
|
||||
properties: {
|
||||
provisioningState: "Succeeded",
|
||||
startIpAddress: "0.0.0.0",
|
||||
endIpAddress: "255.255.255.255",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await checkFirewallRules(apiVersion, rulePredicate, setIsAllPublicIPAddressEnabled);
|
||||
|
||||
expect(isAllPublicIPAddressEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("returns 'all public IP addresses' is NOT enabled for account without the proper firewall rule", async () => {
|
||||
armRequestMock.mockResolvedValueOnce([
|
||||
{
|
||||
id: "resourceId",
|
||||
name: "AllowAll",
|
||||
type: "Microsoft.DocumentDB/mongoClusters/firewallRules",
|
||||
properties: {
|
||||
provisioningState: "Succeeded",
|
||||
startIpAddress: "10.10.10.10",
|
||||
endIpAddress: "10.10.10.10",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await checkFirewallRules(apiVersion, rulePredicate, setIsAllPublicIPAddressEnabled);
|
||||
|
||||
expect(isAllPublicIPAddressEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("sets message for account without the proper firewall rule", async () => {
|
||||
armRequestMock.mockResolvedValueOnce([
|
||||
{
|
||||
id: "resourceId",
|
||||
name: "AllowAll",
|
||||
type: "Microsoft.DocumentDB/mongoClusters/firewallRules",
|
||||
properties: {
|
||||
provisioningState: "Succeeded",
|
||||
startIpAddress: "0.0.0.0",
|
||||
endIpAddress: "255.255.255.255",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const warningMessage = "This is a warning message";
|
||||
let warningMessageResult: string;
|
||||
const warningMessageFunc = (msg: string) => (warningMessageResult = msg);
|
||||
|
||||
await checkFirewallRules(apiVersion, rulePredicate, undefined, warningMessageFunc, warningMessage);
|
||||
|
||||
expect(warningMessageResult).toEqual(warningMessage);
|
||||
});
|
||||
});
|
||||
@@ -138,12 +138,7 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
<span
|
||||
className="tabNavText"
|
||||
style={active ? { fontWeight: "bolder", borderBottom: "2px solid rgba(0,120,212,1)" } : {}}
|
||||
>
|
||||
{useObservable(tab?.tabTitle || getReactTabTitle())}
|
||||
</span>
|
||||
<span className="tabNavText">{useObservable(tab?.tabTitle || getReactTabTitle())}</span>
|
||||
{tabKind !== ReactTabKind.Home && (
|
||||
<span className="tabIconSection">
|
||||
<CloseButton tab={tab} active={active} hovering={hovering} tabKind={tabKind} />
|
||||
|
||||
@@ -37,6 +37,7 @@ import QueryTablesTab from "../Tabs/QueryTablesTab";
|
||||
import { CollectionSettingsTabV2 } from "../Tabs/SettingsTabV2";
|
||||
import { useDatabases } from "../useDatabases";
|
||||
import { useSelectedNode } from "../useSelectedNode";
|
||||
import { Platform, configContext } from "./../../ConfigContext";
|
||||
import ConflictId from "./ConflictId";
|
||||
import DocumentId from "./DocumentId";
|
||||
import StoredProcedure from "./StoredProcedure";
|
||||
@@ -205,7 +206,8 @@ export default class Collection implements ViewModels.Collection {
|
||||
.map((node) => <Trigger>node);
|
||||
});
|
||||
|
||||
const showScriptsMenus: boolean = userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
||||
const showScriptsMenus: boolean =
|
||||
configContext.platform != Platform.Fabric && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin");
|
||||
this.showStoredProcedures = ko.observable<boolean>(showScriptsMenus);
|
||||
this.showTriggers = ko.observable<boolean>(showScriptsMenus);
|
||||
this.showUserDefinedFunctions = ko.observable<boolean>(showScriptsMenus);
|
||||
|
||||
@@ -39,6 +39,7 @@ import { GitHubReposPanel } from "../Panes/GitHubReposPanel/GitHubReposPanel";
|
||||
import TabsBase from "../Tabs/TabsBase";
|
||||
import { useDatabases } from "../useDatabases";
|
||||
import { useSelectedNode } from "../useSelectedNode";
|
||||
import { Platform, configContext } from "./../../ConfigContext";
|
||||
import StoredProcedure from "./StoredProcedure";
|
||||
import Trigger from "./Trigger";
|
||||
import UserDefinedFunction from "./UserDefinedFunction";
|
||||
@@ -69,7 +70,8 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
||||
shallow
|
||||
);
|
||||
const { activeTab, refreshActiveTab } = useTabs();
|
||||
const showScriptNodes = userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
||||
const showScriptNodes =
|
||||
configContext.platform !== Platform.Fabric && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin");
|
||||
const pseudoDirPath = "PsuedoDir";
|
||||
|
||||
const buildGalleryCallout = (): JSX.Element => {
|
||||
|
||||
@@ -40,6 +40,7 @@ import { GitHubReposPanel } from "../Panes/GitHubReposPanel/GitHubReposPanel";
|
||||
import TabsBase from "../Tabs/TabsBase";
|
||||
import { useDatabases } from "../useDatabases";
|
||||
import { useSelectedNode } from "../useSelectedNode";
|
||||
import { Platform, configContext } from "./../../ConfigContext";
|
||||
import StoredProcedure from "./StoredProcedure";
|
||||
import Trigger from "./Trigger";
|
||||
import UserDefinedFunction from "./UserDefinedFunction";
|
||||
@@ -249,7 +250,9 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||
* @param container
|
||||
*/
|
||||
private static showScriptNodes(container: Explorer): boolean {
|
||||
return userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
||||
return (
|
||||
configContext.platform !== Platform.Fabric && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
|
||||
);
|
||||
}
|
||||
|
||||
private buildCollectionNode(database: ViewModels.Database, collection: ViewModels.Collection): TreeNode {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
TreeOpenChangeEvent,
|
||||
createLightTheme,
|
||||
} from "@fluentui/react-components";
|
||||
import { TreeNode2Component } from "Explorer/Controls/TreeComponent2/TreeNode2Component";
|
||||
import { TreeNode2, TreeNode2Component } from "Explorer/Controls/TreeComponent2/TreeNode2Component";
|
||||
import { useDatabaseTreeNodes } from "Explorer/Tree2/useDatabaseTreeNodes";
|
||||
import * as React from "react";
|
||||
import shallow from "zustand/shallow";
|
||||
@@ -69,16 +69,45 @@ export const ResourceTree2: React.FC<ResourceTreeProps> = ({ container }: Resour
|
||||
);
|
||||
// const { activeTab } = useTabs();
|
||||
const databaseTreeNodes = useDatabaseTreeNodes(container, isNotebookEnabled);
|
||||
const dataNodeTree = {
|
||||
const [openItems, setOpenItems] = React.useState<Iterable<TreeItemValue>>([DATA_TREE_LABEL]);
|
||||
|
||||
const dataNodeTree: TreeNode2 = {
|
||||
id: "data",
|
||||
label: DATA_TREE_LABEL,
|
||||
isExpanded: true,
|
||||
className: "accordionItemHeader",
|
||||
children: databaseTreeNodes,
|
||||
isScrollable: true,
|
||||
};
|
||||
|
||||
const [openItems, setOpenItems] = React.useState<Iterable<TreeItemValue>>([DATA_TREE_LABEL]);
|
||||
React.useEffect(() => {
|
||||
// Compute open items based on node.isExpanded
|
||||
const updateOpenItems = (node: TreeNode2, parentNodeId: string): void => {
|
||||
// This will look for ANY expanded node, event if its parent node isn't expanded
|
||||
// and add it to the openItems list
|
||||
const globalId = parentNodeId === undefined ? node.label : `${parentNodeId}/${node.label}`;
|
||||
|
||||
if (node.isExpanded) {
|
||||
let found = false;
|
||||
for (const id of openItems) {
|
||||
if (id === globalId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
setOpenItems((prevOpenItems) => [...prevOpenItems, globalId]);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children) {
|
||||
for (const child of node.children) {
|
||||
updateOpenItems(child, globalId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateOpenItems(dataNodeTree, undefined);
|
||||
}, [databaseTreeNodes]);
|
||||
|
||||
const handleOpenChange = (event: TreeOpenChangeEvent, data: TreeOpenChangeData) => setOpenItems(data.openItems);
|
||||
|
||||
@@ -89,17 +118,11 @@ export const ResourceTree2: React.FC<ResourceTreeProps> = ({ container }: Resour
|
||||
aria-label="CosmosDB resources"
|
||||
openItems={openItems}
|
||||
onOpenChange={handleOpenChange}
|
||||
size="small"
|
||||
style={{ height: "100%" }}
|
||||
size="medium"
|
||||
style={{ height: "100%", width: "290px" }}
|
||||
>
|
||||
{[dataNodeTree].map((node) => (
|
||||
<TreeNode2Component
|
||||
key={node.label}
|
||||
className="dataResourceTree"
|
||||
node={node}
|
||||
treeNodeId={node.label}
|
||||
globalOpenIds={[...openItems].map((item) => item.toString())}
|
||||
/>
|
||||
<TreeNode2Component key={node.label} className="dataResourceTree" node={node} treeNodeId={node.label} />
|
||||
))}
|
||||
</Tree>
|
||||
</FluentProvider>
|
||||
|
||||
@@ -17,6 +17,7 @@ import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
||||
import { mostRecentActivity } from "../MostRecentActivity/MostRecentActivity";
|
||||
import { useNotebook } from "../Notebook/useNotebook";
|
||||
import { useSelectedNode } from "../useSelectedNode";
|
||||
import { Platform, configContext } from "./../../ConfigContext";
|
||||
|
||||
export const buildCollectionNode = (
|
||||
database: ViewModels.Database,
|
||||
@@ -25,6 +26,53 @@ export const buildCollectionNode = (
|
||||
container: Explorer,
|
||||
refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void
|
||||
): TreeNode2 => {
|
||||
let children: TreeNode2[];
|
||||
|
||||
// Flat Tree for Fabric
|
||||
if (configContext.platform !== Platform.Fabric) {
|
||||
children = buildCollectionNodeChildren(database, collection, isNotebookEnabled, container, refreshActiveTab);
|
||||
}
|
||||
|
||||
return {
|
||||
label: collection.id(),
|
||||
iconSrc: CollectionIcon,
|
||||
children: children,
|
||||
className: "collectionHeader",
|
||||
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(container, collection),
|
||||
onClick: () => {
|
||||
useSelectedNode.getState().setSelectedNode(collection);
|
||||
collection.openTab();
|
||||
// push to most recent
|
||||
mostRecentActivity.collectionWasOpened(userContext.databaseAccount?.id, collection);
|
||||
},
|
||||
onExpanded: async () => {
|
||||
// Rewritten version of expandCollapseCollection
|
||||
useSelectedNode.getState().setSelectedNode(collection);
|
||||
useCommandBar.getState().setContextButtons([]);
|
||||
refreshActiveTab(
|
||||
(tab: TabsBase) =>
|
||||
tab.collection?.id() === collection.id() && tab.collection.databaseId === collection.databaseId
|
||||
);
|
||||
useDatabases.getState().updateDatabase(database);
|
||||
},
|
||||
isSelected: () => useSelectedNode.getState().isDataNodeSelected(collection.databaseId, collection.id()),
|
||||
onContextMenuOpen: () => useSelectedNode.getState().setSelectedNode(collection),
|
||||
onCollapsed: () => {
|
||||
collection.collapseCollection();
|
||||
// useCommandBar.getState().setContextButtons([]);
|
||||
useDatabases.getState().updateDatabase(database);
|
||||
},
|
||||
isExpanded: collection.isCollectionExpanded(),
|
||||
};
|
||||
};
|
||||
|
||||
const buildCollectionNodeChildren = (
|
||||
database: ViewModels.Database,
|
||||
collection: ViewModels.Collection,
|
||||
isNotebookEnabled: boolean,
|
||||
container: Explorer,
|
||||
refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void
|
||||
): TreeNode2[] => {
|
||||
const showScriptNodes = userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
||||
const children: TreeNode2[] = [];
|
||||
children.push({
|
||||
@@ -110,27 +158,7 @@ export const buildCollectionNode = (
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
label: collection.id(),
|
||||
iconSrc: CollectionIcon,
|
||||
children: children,
|
||||
className: "collectionHeader",
|
||||
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(container, collection),
|
||||
onClick: () => {
|
||||
useSelectedNode.getState().setSelectedNode(collection);
|
||||
},
|
||||
onExpanded: () => {
|
||||
// Rewritten version of expandCollapseCollection
|
||||
useSelectedNode.getState().setSelectedNode(collection);
|
||||
useCommandBar.getState().setContextButtons([]);
|
||||
refreshActiveTab(
|
||||
(tab: TabsBase) =>
|
||||
tab.collection?.id() === collection.id() && tab.collection.databaseId === collection.databaseId
|
||||
);
|
||||
},
|
||||
isSelected: () => useSelectedNode.getState().isDataNodeSelected(collection.databaseId, collection.id()),
|
||||
onContextMenuOpen: () => useSelectedNode.getState().setSelectedNode(collection),
|
||||
};
|
||||
return children;
|
||||
};
|
||||
|
||||
const buildStoredProcedureNode = (
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as ResourceTreeContextMenuButtonFactory from "../ContextMenuButtonFacto
|
||||
import Explorer from "../Explorer";
|
||||
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
||||
import { useSelectedNode } from "../useSelectedNode";
|
||||
import { Platform, configContext } from "./../../ConfigContext";
|
||||
|
||||
export const useDatabaseTreeNodes = (container: Explorer, isNotebookEnabled: boolean): TreeNode2[] => {
|
||||
const databases = useDatabases((state) => state.databases);
|
||||
@@ -24,18 +25,25 @@ export const useDatabaseTreeNodes = (container: Explorer, isNotebookEnabled: boo
|
||||
contextMenu: ResourceTreeContextMenuButtonFactory.createDatabaseContextMenu(container, database.id()),
|
||||
onExpanded: async () => {
|
||||
useSelectedNode.getState().setSelectedNode(database);
|
||||
if (databaseNode.children?.length === 0) {
|
||||
if (!databaseNode.children || databaseNode.children?.length === 0) {
|
||||
databaseNode.isLoading = true;
|
||||
}
|
||||
await database.expandDatabase();
|
||||
databaseNode.isLoading = false;
|
||||
useCommandBar.getState().setContextButtons([]);
|
||||
refreshActiveTab((tab: TabsBase) => tab.collection?.databaseId === database.id());
|
||||
useDatabases.getState().updateDatabase(database);
|
||||
},
|
||||
onContextMenuOpen: () => useSelectedNode.getState().setSelectedNode(database),
|
||||
isExpanded: database.isDatabaseExpanded(),
|
||||
onCollapsed: () => {
|
||||
database.collapseDatabase();
|
||||
// useCommandBar.getState().setContextButtons([]);
|
||||
useDatabases.getState().updateDatabase(database);
|
||||
},
|
||||
};
|
||||
|
||||
if (database.isDatabaseShared()) {
|
||||
if (database.isDatabaseShared() && configContext.platform !== Platform.Fabric) {
|
||||
databaseNode.children.push({
|
||||
id: database.isSampleDB ? "sampleScaleSettings" : "",
|
||||
label: "Scale",
|
||||
|
||||
23
src/Main.tsx
23
src/Main.tsx
@@ -1,5 +1,5 @@
|
||||
// CSS Dependencies
|
||||
import { initializeIcons } from "@fluentui/react";
|
||||
import { initializeIcons, loadTheme } from "@fluentui/react";
|
||||
import { QuickstartCarousel } from "Explorer/Quickstart/QuickstartCarousel";
|
||||
import { MongoQuickstartTutorial } from "Explorer/Quickstart/Tutorials/MongoQuickstartTutorial";
|
||||
import { SQLQuickstartTutorial } from "Explorer/Quickstart/Tutorials/SQLQuickstartTutorial";
|
||||
@@ -26,6 +26,8 @@ import "../less/TableStyles/CustomizeColumns.less";
|
||||
import "../less/TableStyles/EntityEditor.less";
|
||||
import "../less/TableStyles/fulldatatables.less";
|
||||
import "../less/TableStyles/queryBuilder.less";
|
||||
import * as StyleConstants from "./Common/StyleConstants";
|
||||
import { configContext, Platform } from "ConfigContext";
|
||||
import "../less/documentDB.less";
|
||||
import "../less/forms.less";
|
||||
import "../less/infobox.less";
|
||||
@@ -57,6 +59,7 @@ import "./Libs/jquery";
|
||||
import "./Shared/appInsights";
|
||||
import { useConfig } from "./hooks/useConfig";
|
||||
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
|
||||
import { appThemeFabric } from "./Platform/Fabric/FabricTheme";
|
||||
|
||||
initializeIcons();
|
||||
|
||||
@@ -67,6 +70,10 @@ const App: React.FunctionComponent = () => {
|
||||
const shouldShowModal = useQueryCopilot((state) => state.showFeedbackModal);
|
||||
|
||||
const config = useConfig();
|
||||
if (config?.platform === Platform.Fabric) {
|
||||
loadTheme(appThemeFabric);
|
||||
}
|
||||
StyleConstants.updateStyles();
|
||||
const explorer = useKnockoutExplorer(config?.platform);
|
||||
|
||||
const toggleLeftPaneExpanded = () => {
|
||||
@@ -84,6 +91,7 @@ const App: React.FunctionComponent = () => {
|
||||
|
||||
return (
|
||||
<div className="flexContainer" aria-hidden="false">
|
||||
<LoadFabricOverrides />
|
||||
<div id="divExplorer" className="flexContainer hideOverflows">
|
||||
<div id="freeTierTeachingBubble"> </div>
|
||||
{/* Main Command Bar - Start */}
|
||||
@@ -135,6 +143,19 @@ const App: React.FunctionComponent = () => {
|
||||
|
||||
ReactDOM.render(<App />, document.body);
|
||||
|
||||
function LoadFabricOverrides(): JSX.Element {
|
||||
if (configContext.platform === Platform.Fabric) {
|
||||
const FabricStyle = React.lazy(() => import("./Platform/Fabric/FabricPlatform"));
|
||||
return (
|
||||
<React.Suspense fallback={<div></div>}>
|
||||
<FabricStyle />
|
||||
</React.Suspense>
|
||||
);
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
}
|
||||
|
||||
function LoadingExplorer(): JSX.Element {
|
||||
return (
|
||||
<div className="splashLoaderContainer">
|
||||
|
||||
7
src/Platform/Fabric/FabricPlatform.tsx
Normal file
7
src/Platform/Fabric/FabricPlatform.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
import "../../../less/documentDBFabric.less";
|
||||
// This is a dummy export, allowing us to conditionally import documentDBFabric.less
|
||||
// by lazy-importing this in Main.tsx (see LoadFabricOverrides() there)
|
||||
export default function InitFabric() {
|
||||
return <></>;
|
||||
}
|
||||
208
src/Platform/Fabric/FabricTheme.tsx
Normal file
208
src/Platform/Fabric/FabricTheme.tsx
Normal file
@@ -0,0 +1,208 @@
|
||||
import { Theme, createTheme } from "@fluentui/react";
|
||||
|
||||
export const appThemeFabric: Theme = createTheme({
|
||||
palette: {
|
||||
/**
|
||||
* Color code for themeDarker.
|
||||
*/
|
||||
themeDarker: "#033f38",
|
||||
/**
|
||||
* Color code for themeDark.
|
||||
*/
|
||||
themeDark: "#0a5c50",
|
||||
/**
|
||||
* Color code for themeDarkAlt.
|
||||
*/
|
||||
themeDarkAlt: "#0c695a",
|
||||
/**
|
||||
* Color code for themePrimary.
|
||||
*/
|
||||
themePrimary: "#117865",
|
||||
/**
|
||||
* Color code for themeSecondary.
|
||||
*/
|
||||
themeSecondary: "#1f937e",
|
||||
/**
|
||||
* Color code for themeTertiary.
|
||||
*/
|
||||
themeTertiary: "#52c7aa",
|
||||
/**
|
||||
* Color code for themeLight.
|
||||
*/
|
||||
themeLight: "#9ee0cb",
|
||||
/**
|
||||
* Color code for themeLighter.
|
||||
*/
|
||||
themeLighter: "#c0ecdd",
|
||||
/**
|
||||
* Color code for themeLighterAlt.
|
||||
*/
|
||||
themeLighterAlt: "#e3f7ef",
|
||||
/**
|
||||
* Color code for the strongest color, which is black in the default theme.
|
||||
* This is a very light color in inverted themes.
|
||||
*/
|
||||
black: "#000000",
|
||||
/**
|
||||
* Color code for blackTranslucent40.
|
||||
*/
|
||||
blackTranslucent40: "rgba(0, 0, 0, 0.4)",
|
||||
/**
|
||||
* Color code for neutralDark.
|
||||
*/
|
||||
neutralDark: "#141414",
|
||||
/**
|
||||
* Color code for neutralPrimary.
|
||||
*/
|
||||
neutralPrimary: "#242424",
|
||||
/**
|
||||
* Color code for neutralPrimaryAlt.
|
||||
*/
|
||||
neutralPrimaryAlt: "#383838",
|
||||
/**
|
||||
* Color code for neutralSecondary.
|
||||
*/
|
||||
neutralSecondary: "#5c5c5c",
|
||||
/**
|
||||
* Color code for neutralSecondaryAlt.
|
||||
*/
|
||||
neutralSecondaryAlt: "#858585",
|
||||
/**
|
||||
* Color code for neutralTertiary.
|
||||
*/
|
||||
neutralTertiary: "#9e9e9e",
|
||||
/**
|
||||
* Color code for neutralTertiaryAlt.
|
||||
*/
|
||||
neutralTertiaryAlt: "#c7c7c7",
|
||||
/**
|
||||
* Color code for neutralQuaternary.
|
||||
*/
|
||||
neutralQuaternary: "#d1d1d1",
|
||||
/**
|
||||
* Color code for neutralQuaternaryAlt.
|
||||
*/
|
||||
neutralQuaternaryAlt: "#e0e0e0",
|
||||
/**
|
||||
* Color code for neutralLight.
|
||||
*/
|
||||
neutralLight: "#ebebeb",
|
||||
/**
|
||||
* Color code for neutralLighter.
|
||||
*/
|
||||
neutralLighter: "#f5f5f5",
|
||||
/**
|
||||
* Color code for neutralLighterAlt.
|
||||
*/
|
||||
neutralLighterAlt: "#fafafa",
|
||||
/**
|
||||
* Color code for the accent.
|
||||
*/
|
||||
accent: "#117865",
|
||||
/**
|
||||
* Color code for the softest color, which is white in the default theme. This is a very dark color in dark themes.
|
||||
* This is the page background.
|
||||
*/
|
||||
white: "#ffffff",
|
||||
/**
|
||||
* Color code for whiteTranslucent40
|
||||
*/
|
||||
whiteTranslucent40: "rgba(255, 255, 255, 0.4)",
|
||||
/**
|
||||
* Color code for yellowDark.
|
||||
*/
|
||||
yellowDark: "#d39300",
|
||||
/**
|
||||
* Color code for yellow.
|
||||
*/
|
||||
yellow: "#fde300",
|
||||
/**
|
||||
* Color code for yellowLight.
|
||||
*/
|
||||
yellowLight: "#fef7b2",
|
||||
/**
|
||||
* Color code for orange.
|
||||
*/
|
||||
orange: "#f7630c",
|
||||
/**
|
||||
* Color code for orangeLight.
|
||||
*/
|
||||
orangeLight: "#f98845",
|
||||
/**
|
||||
* Color code for orangeLighter.
|
||||
*/
|
||||
orangeLighter: "#fdcfb4",
|
||||
/**
|
||||
* Color code for redDark.
|
||||
*/
|
||||
redDark: "#750b1c",
|
||||
/**
|
||||
* Color code for red.
|
||||
*/
|
||||
red: "#d13438",
|
||||
/**
|
||||
* Color code for magentaDark.
|
||||
*/
|
||||
magentaDark: "#6b0043",
|
||||
/**
|
||||
* Color code for magenta.
|
||||
*/
|
||||
magenta: "#bf0077",
|
||||
/**
|
||||
* Color code for magentaLight.
|
||||
*/
|
||||
magentaLight: "#d957a8",
|
||||
/**
|
||||
* Color code for purpleDark.
|
||||
*/
|
||||
purpleDark: "#401b6c",
|
||||
/**
|
||||
* Color code for purple.
|
||||
*/
|
||||
purple: "#5c2e91",
|
||||
/**
|
||||
* Color code for purpleLight.
|
||||
*/
|
||||
purpleLight: "#c6b1de",
|
||||
/**
|
||||
* Color code for blueDark.
|
||||
*/
|
||||
blueDark: "#003966",
|
||||
/**
|
||||
* Color code for blueMid.
|
||||
*/
|
||||
blueMid: "#004e8c",
|
||||
/**
|
||||
* Color code for blue.
|
||||
*/
|
||||
blue: "#0078d4",
|
||||
/**
|
||||
* Color code for blueLight.
|
||||
*/
|
||||
blueLight: "#3a96dd",
|
||||
/**
|
||||
* Color code for tealDark.
|
||||
*/
|
||||
tealDark: "#006666",
|
||||
/**
|
||||
* Color code for teal.
|
||||
*/
|
||||
teal: "#038387",
|
||||
/**
|
||||
* Color code for tealLight.
|
||||
*/
|
||||
tealLight: "#00b7c3",
|
||||
/**
|
||||
* Color code for greenDark.
|
||||
*/
|
||||
greenDark: "#0b6a0b",
|
||||
/**
|
||||
* Color code for green.
|
||||
*/
|
||||
green: "#107c10",
|
||||
/**
|
||||
* Color code for greenLight.
|
||||
*/
|
||||
greenLight: "#13a10e",
|
||||
},
|
||||
});
|
||||
@@ -4,7 +4,7 @@
|
||||
import { DefaultButton, IButtonStyles, IContextualMenuItem } from "@fluentui/react";
|
||||
import * as React from "react";
|
||||
import { FunctionComponent, useEffect, useState } from "react";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
import { DatabaseAccount } from "../../../Contracts/DataModels";
|
||||
import { useDatabaseAccounts } from "../../../hooks/useDatabaseAccounts";
|
||||
import { useSubscriptions } from "../../../hooks/useSubscriptions";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useBoolean } from "@fluentui/react-hooks";
|
||||
import * as React from "react";
|
||||
import ErrorImage from "../../../../images/error.svg";
|
||||
import ConnectImage from "../../../../images/HdeConnectCosmosDB.svg";
|
||||
import ErrorImage from "../../../../images/error.svg";
|
||||
import { AuthType } from "../../../AuthType";
|
||||
import { HttpHeaders } from "../../../Common/Constants";
|
||||
import { configContext } from "../../../ConfigContext";
|
||||
@@ -16,6 +16,19 @@ interface Props {
|
||||
setAuthType: (authType: AuthType) => void;
|
||||
}
|
||||
|
||||
export const fetchEncryptedToken = async (connectionString: string): Promise<string> => {
|
||||
const headers = new Headers();
|
||||
headers.append(HttpHeaders.connectionString, connectionString);
|
||||
const url = configContext.BACKEND_ENDPOINT + "/api/guest/tokens/generateToken";
|
||||
const response = await fetch(url, { headers, method: "POST" });
|
||||
if (!response.ok) {
|
||||
throw response;
|
||||
}
|
||||
// This API has a quirk where it must be parsed twice
|
||||
const result: GenerateTokenResponse = JSON.parse(await response.json());
|
||||
return decodeURIComponent(result.readWrite || result.read);
|
||||
};
|
||||
|
||||
export const ConnectExplorer: React.FunctionComponent<Props> = ({
|
||||
setEncryptedToken,
|
||||
login,
|
||||
@@ -44,16 +57,8 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = new Headers();
|
||||
headers.append(HttpHeaders.connectionString, connectionString);
|
||||
const url = configContext.BACKEND_ENDPOINT + "/api/guest/tokens/generateToken";
|
||||
const response = await fetch(url, { headers, method: "POST" });
|
||||
if (!response.ok) {
|
||||
throw response;
|
||||
}
|
||||
// This API has a quirk where it must be parsed twice
|
||||
const result: GenerateTokenResponse = JSON.parse(await response.json());
|
||||
setEncryptedToken(decodeURIComponent(result.readWrite || result.read));
|
||||
const encryptedToken = await fetchEncryptedToken(connectionString);
|
||||
setEncryptedToken(encryptedToken);
|
||||
setAuthType(AuthType.ConnectionString);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -36,10 +36,10 @@ export type Features = {
|
||||
readonly enableLegacyMongoShellV2Debug: boolean;
|
||||
readonly loadLegacyMongoShellFromBE: boolean;
|
||||
readonly enableCopilot: boolean;
|
||||
readonly enablePriorityBasedThrottling: boolean;
|
||||
readonly copilotVersion?: string;
|
||||
readonly disableCopilotPhoenixGateaway: boolean;
|
||||
readonly enableCopilotFullSchema: boolean;
|
||||
readonly copilotChatFixedMonacoEditorHeight: boolean;
|
||||
|
||||
// can be set via both flight and feature flag
|
||||
autoscaleDefault: boolean;
|
||||
@@ -107,11 +107,11 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
||||
enableLegacyMongoShellV2: "true" === get("enablelegacymongoshellv2"),
|
||||
enableLegacyMongoShellV2Debug: "true" === get("enablelegacymongoshellv2debug"),
|
||||
loadLegacyMongoShellFromBE: "true" === get("loadlegacymongoshellfrombe"),
|
||||
enablePriorityBasedThrottling: "true" === get("enableprioritybasedthrottling"),
|
||||
enableCopilot: "true" === get("enablecopilot", "true"),
|
||||
copilotVersion: get("copilotversion") ?? "v1.0",
|
||||
disableCopilotPhoenixGateaway: "true" === get("disablecopilotphoenixgateaway"),
|
||||
enableCopilotFullSchema: "true" === get("enablecopilotfullschema", "true"),
|
||||
copilotChatFixedMonacoEditorHeight: "true" === get("copilotchatfixedmonacoeditorheight"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { IButtonStyles, ICommandBarStyles, ISeparatorStyles, IStackTokens } from "@fluentui/react";
|
||||
import { StyleConstants } from "../Common/Constants";
|
||||
import { StyleConstants } from "../Common/StyleConstants";
|
||||
|
||||
export const commandBarItemStyles: IButtonStyles = { root: { paddingLeft: 20 } };
|
||||
|
||||
|
||||
@@ -55,6 +55,17 @@ export const defaultAllowedBackendEndpoints: ReadonlyArray<string> = [
|
||||
"https://localhost:1234",
|
||||
];
|
||||
|
||||
export const PortalBackendIPs: { [key: string]: string[] } = {
|
||||
"https://main.documentdb.ext.azure.com": ["104.42.195.92", "40.76.54.131"],
|
||||
// DE doesn't talk to prod2 (main2) but it might be added
|
||||
//"https://main2.documentdb.ext.azure.com": ["104.42.196.69"],
|
||||
"https://main.documentdb.ext.azure.cn": ["139.217.8.252"],
|
||||
"https://main.documentdb.ext.azure.us": ["52.244.48.71"],
|
||||
// Add ussec and usnat when endpoint address is known:
|
||||
//ussec: ["29.26.26.67", "29.26.26.66"],
|
||||
//usnat: ["7.28.202.68"],
|
||||
};
|
||||
|
||||
export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
||||
"https://main.documentdb.ext.azure.com",
|
||||
"https://main.documentdb.ext.azure.cn",
|
||||
@@ -67,7 +78,7 @@ export const allowedEmulatorEndpoints: ReadonlyArray<string> = ["https://localho
|
||||
|
||||
export const allowedMongoBackendEndpoints: ReadonlyArray<string> = ["https://localhost:1234"];
|
||||
|
||||
export const allowedGraphEndpoints: ReadonlyArray<string> = ["https://graph.windows.net"];
|
||||
export const allowedGraphEndpoints: ReadonlyArray<string> = ["https://graph.microsoft.com"];
|
||||
|
||||
export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"];
|
||||
|
||||
|
||||
4
src/Utils/JestUtils.ts
Normal file
4
src/Utils/JestUtils.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function mockFunction<T extends (...args: any[]) => any>(fn: T): jest.MockedFunction<T> {
|
||||
return fn as jest.MockedFunction<T>;
|
||||
}
|
||||
106
src/Utils/NetworkUtility.test.ts
Normal file
106
src/Utils/NetworkUtility.test.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { resetConfigContext, updateConfigContext } from "ConfigContext";
|
||||
import { DatabaseAccount, IpRule } from "Contracts/DataModels";
|
||||
import { updateUserContext } from "UserContext";
|
||||
import { PortalBackendIPs } from "Utils/EndpointValidation";
|
||||
import { getNetworkSettingsWarningMessage } from "./NetworkUtility";
|
||||
|
||||
describe("NetworkUtility tests", () => {
|
||||
describe("getNetworkSettingsWarningMessage", () => {
|
||||
const publicAccessMessagePart = "Please enable public access to proceed";
|
||||
const accessMessagePart = "Please allow access from Azure Portal to proceed";
|
||||
// validEnpoints are a subset of those from Utils/EndpointValidation/PortalBackendIPs
|
||||
const validEndpoints = [
|
||||
"https://main.documentdb.ext.azure.com",
|
||||
"https://main.documentdb.ext.azure.cn",
|
||||
"https://main.documentdb.ext.azure.us",
|
||||
];
|
||||
|
||||
let warningMessageResult: string;
|
||||
const warningMessageFunc = (msg: string) => (warningMessageResult = msg);
|
||||
|
||||
beforeEach(() => {
|
||||
warningMessageResult = undefined;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetConfigContext();
|
||||
});
|
||||
|
||||
it("should return no message when publicNetworkAccess is enabled", async () => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
properties: {
|
||||
publicNetworkAccess: "Enabled",
|
||||
},
|
||||
} as DatabaseAccount,
|
||||
});
|
||||
|
||||
await getNetworkSettingsWarningMessage(warningMessageFunc);
|
||||
expect(warningMessageResult).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return publicAccessMessage when publicNetworkAccess is disabled", async () => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
properties: {
|
||||
publicNetworkAccess: "Disabled",
|
||||
},
|
||||
} as DatabaseAccount,
|
||||
});
|
||||
|
||||
await getNetworkSettingsWarningMessage(warningMessageFunc);
|
||||
expect(warningMessageResult).toContain(publicAccessMessagePart);
|
||||
});
|
||||
|
||||
it(`should return no message when the appropriate ip rules are added to mongo/cassandra account per endpoint`, () => {
|
||||
validEndpoints.forEach(async (endpoint) => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
kind: "MongoDB",
|
||||
properties: {
|
||||
ipRules: PortalBackendIPs[endpoint].map((ip: string) => ({ ipAddressOrRange: ip } as IpRule)),
|
||||
publicNetworkAccess: "Enabled",
|
||||
},
|
||||
} as DatabaseAccount,
|
||||
});
|
||||
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: endpoint,
|
||||
});
|
||||
|
||||
let asyncWarningMessageResult: string;
|
||||
const asyncWarningMessageFunc = (msg: string) => (asyncWarningMessageResult = msg);
|
||||
|
||||
await getNetworkSettingsWarningMessage(asyncWarningMessageFunc);
|
||||
expect(asyncWarningMessageResult).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should return accessMessage when incorrent ip rule is added to mongo/cassandra account per endpoint", () => {
|
||||
validEndpoints.forEach(async (endpoint) => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
kind: "MongoDB",
|
||||
properties: {
|
||||
ipRules: [{ ipAddressOrRange: "1.1.1.1" }],
|
||||
publicNetworkAccess: "Enabled",
|
||||
},
|
||||
} as DatabaseAccount,
|
||||
});
|
||||
|
||||
updateConfigContext({
|
||||
BACKEND_ENDPOINT: endpoint,
|
||||
});
|
||||
|
||||
let asyncWarningMessageResult: string;
|
||||
const asyncWarningMessageFunc = (msg: string) => (asyncWarningMessageResult = msg);
|
||||
|
||||
await getNetworkSettingsWarningMessage(asyncWarningMessageFunc);
|
||||
expect(asyncWarningMessageResult).toContain(accessMessagePart);
|
||||
});
|
||||
});
|
||||
|
||||
// Postgres and vcore mongo account checks basically pass through to CheckFirewallRules so those
|
||||
// tests are omitted here and included in CheckFirewallRules.test.ts
|
||||
});
|
||||
});
|
||||
@@ -1,15 +1,7 @@
|
||||
import { configContext } from "ConfigContext";
|
||||
import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules";
|
||||
import { userContext } from "UserContext";
|
||||
|
||||
const PortalIPs: { [key: string]: string[] } = {
|
||||
prod1: ["104.42.195.92", "40.76.54.131"],
|
||||
prod2: ["104.42.196.69"],
|
||||
mooncake: ["139.217.8.252"],
|
||||
blackforest: ["51.4.229.218"],
|
||||
fairfax: ["52.244.48.71"],
|
||||
ussec: ["29.26.26.67", "29.26.26.66"],
|
||||
usnat: ["7.28.202.68"],
|
||||
};
|
||||
import { PortalBackendIPs } from "Utils/EndpointValidation";
|
||||
|
||||
export const getNetworkSettingsWarningMessage = async (
|
||||
setStateFunc: (warningMessage: string) => void
|
||||
@@ -28,6 +20,7 @@ export const getNetworkSettingsWarningMessage = async (
|
||||
setStateFunc,
|
||||
accessMessage
|
||||
);
|
||||
return;
|
||||
} else if (userContext.apiType === "VCoreMongo") {
|
||||
checkFirewallRules(
|
||||
"2023-03-01-preview",
|
||||
@@ -38,6 +31,7 @@ export const getNetworkSettingsWarningMessage = async (
|
||||
setStateFunc,
|
||||
accessMessage
|
||||
);
|
||||
return;
|
||||
} else if (accountProperties) {
|
||||
// public network access is disabled
|
||||
if (
|
||||
@@ -45,13 +39,14 @@ export const getNetworkSettingsWarningMessage = async (
|
||||
accountProperties.publicNetworkAccess !== "SecuredByPerimeter"
|
||||
) {
|
||||
setStateFunc(publicAccessMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
const ipRules = accountProperties.ipRules;
|
||||
// public network access is NOT set to "All networks"
|
||||
if (ipRules.length > 0) {
|
||||
if (ipRules?.length > 0) {
|
||||
if (userContext.apiType === "Cassandra" || userContext.apiType === "Mongo") {
|
||||
const portalIPs = PortalIPs[userContext.portalEnv];
|
||||
const portalIPs = PortalBackendIPs[configContext.BACKEND_ENDPOINT];
|
||||
let numberOfMatches = 0;
|
||||
ipRules.forEach((ipRule) => {
|
||||
if (portalIPs.indexOf(ipRule.ipAddressOrRange) !== -1) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Platform, configContext } from "./../ConfigContext";
|
||||
|
||||
export const getDataExplorerWindow = (currentWindow: Window): Window | undefined => {
|
||||
// Data explorer is always loaded in an iframe, so traverse the parents until we hit the top and return the first child window.
|
||||
try {
|
||||
@@ -5,7 +7,11 @@ export const getDataExplorerWindow = (currentWindow: Window): Window | undefined
|
||||
if (currentWindow.parent === currentWindow) {
|
||||
return undefined;
|
||||
}
|
||||
if (currentWindow.parent === currentWindow.top) {
|
||||
if (configContext.platform === Platform.Fabric && currentWindow.parent.parent === currentWindow.top) {
|
||||
// in Fabric data explorer is inside an extension iframe, so we have two parent iframes
|
||||
return currentWindow;
|
||||
}
|
||||
if (configContext.platform !== Platform.Fabric && currentWindow.parent === currentWindow.top) {
|
||||
return currentWindow;
|
||||
}
|
||||
currentWindow = currentWindow.parent;
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Lists the Cassandra keyspaces under an existing Azure Cosmos DB database account. */
|
||||
export async function listCassandraKeyspaces(
|
||||
@@ -196,3 +196,100 @@ export async function migrateCassandraTableToManualThroughput(
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/tables/${tableName}/throughputSettings/default/migrateToManualThroughput`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
/* Lists the Cassandra materialized views under an existing Azure Cosmos DB database account. */
|
||||
export async function listCassandraViews(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string
|
||||
): Promise<Types.CassandraViewListResult> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Gets the Cassandra view under an existing Azure Cosmos DB database account. */
|
||||
export async function getCassandraView(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string,
|
||||
viewName: string
|
||||
): Promise<Types.CassandraViewGetResults> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views/${viewName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Create or update an Azure Cosmos DB Cassandra View */
|
||||
export async function createUpdateCassandraView(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string,
|
||||
viewName: string,
|
||||
body: Types.CassandraViewCreateUpdateParameters
|
||||
): Promise<Types.CassandraViewGetResults | void> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views/${viewName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Deletes an existing Azure Cosmos DB Cassandra view. */
|
||||
export async function deleteCassandraView(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string,
|
||||
viewName: string
|
||||
): Promise<void> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views/${viewName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
|
||||
}
|
||||
|
||||
/* Gets the RUs per second of the Cassandra view under an existing Azure Cosmos DB database account with the provided name. */
|
||||
export async function getCassandraViewThroughput(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string,
|
||||
viewName: string
|
||||
): Promise<Types.ThroughputSettingsGetResults> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views/${viewName}/throughputSettings/default`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Update RUs per second of an Azure Cosmos DB Cassandra view */
|
||||
export async function updateCassandraViewThroughput(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string,
|
||||
viewName: string,
|
||||
body: Types.ThroughputSettingsUpdateParameters
|
||||
): Promise<Types.ThroughputSettingsGetResults | void> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views/${viewName}/throughputSettings/default`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Migrate an Azure Cosmos DB Cassandra view from manual throughput to autoscale */
|
||||
export async function migrateCassandraViewToAutoscale(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string,
|
||||
viewName: string
|
||||
): Promise<Types.ThroughputSettingsGetResults | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views/${viewName}/throughputSettings/default/migrateToAutoscale`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
/* Migrate an Azure Cosmos DB Cassandra view from autoscale to manual throughput */
|
||||
export async function migrateCassandraViewToManualThroughput(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
keyspaceName: string,
|
||||
viewName: string
|
||||
): Promise<Types.ThroughputSettingsGetResults | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/cassandraKeyspaces/${keyspaceName}/views/${viewName}/throughputSettings/default/migrateToManualThroughput`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account and collection. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given collection, split by partition. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given collection and region, split by partition. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account, collection and region. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account and database. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account and region. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the properties of an existing Azure Cosmos DB database account. */
|
||||
export async function get(
|
||||
|
||||
56
src/Utils/arm/generatedClients/cosmos/graphResources.ts
Normal file
56
src/Utils/arm/generatedClients/cosmos/graphResources.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
AUTOGENERATED FILE
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Lists the graphs under an existing Azure Cosmos DB database account. */
|
||||
export async function listGraphs(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string
|
||||
): Promise<Types.GraphResourcesListResult> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/graphs`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Gets the Graph resource under an existing Azure Cosmos DB database account with the provided name. */
|
||||
export async function getGraph(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
graphName: string
|
||||
): Promise<Types.GraphResourceGetResults> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/graphs/${graphName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Create or update an Azure Cosmos DB Graph. */
|
||||
export async function createUpdateGraph(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
graphName: string,
|
||||
body: Types.GraphResourceCreateUpdateParameters
|
||||
): Promise<Types.GraphResourceGetResults | void> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/graphs/${graphName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Deletes an existing Azure Cosmos DB Graph Resource. */
|
||||
export async function deleteGraphResource(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
graphName: string
|
||||
): Promise<void> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/graphs/${graphName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
|
||||
}
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Lists the Gremlin databases under an existing Azure Cosmos DB database account. */
|
||||
export async function listGremlinDatabases(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* List Cosmos DB locations and their properties */
|
||||
export async function list(subscriptionId: string): Promise<Types.LocationListResult | Types.CloudError> {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Lists the MongoDB databases under an existing Azure Cosmos DB database account. */
|
||||
export async function listMongoDBDatabases(
|
||||
@@ -100,6 +100,56 @@ export async function migrateMongoDBDatabaseToManualThroughput(
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
/* Retrieve throughput distribution for an Azure Cosmos DB MongoDB database */
|
||||
export async function mongoDBDatabaseRetrieveThroughputDistribution(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
body: Types.RetrieveThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/mongodbDatabases/${databaseName}/throughputSettings/default/retrieveThroughputDistribution`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Redistribute throughput for an Azure Cosmos DB MongoDB database */
|
||||
export async function mongoDBDatabaseRedistributeThroughput(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
body: Types.RedistributeThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/mongodbDatabases/${databaseName}/throughputSettings/default/redistributeThroughput`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Retrieve throughput distribution for an Azure Cosmos DB MongoDB container */
|
||||
export async function mongoDBContainerRetrieveThroughputDistribution(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
collectionName: string,
|
||||
body: Types.RetrieveThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/mongodbDatabases/${databaseName}/collections/${collectionName}/throughputSettings/default/retrieveThroughputDistribution`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Redistribute throughput for an Azure Cosmos DB MongoDB container */
|
||||
export async function mongoDBContainerRedistributeThroughput(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
collectionName: string,
|
||||
body: Types.RedistributeThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/mongodbDatabases/${databaseName}/collections/${collectionName}/throughputSettings/default/redistributeThroughput`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Lists the MongoDB collection under an existing Azure Cosmos DB database account. */
|
||||
export async function listMongoDBCollections(
|
||||
subscriptionId: string,
|
||||
@@ -148,6 +198,31 @@ export async function deleteMongoDBCollection(
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
|
||||
}
|
||||
|
||||
/* Merges the partitions of a MongoDB database */
|
||||
export async function mongoDBDatabasePartitionMerge(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
body: Types.MergeParameters
|
||||
): Promise<Types.PhysicalPartitionStorageInfoCollection | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/mongodbDatabases/${databaseName}/partitionMerge`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Merges the partitions of a MongoDB Collection */
|
||||
export async function listMongoDBCollectionPartitionMerge(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
collectionName: string,
|
||||
body: Types.MergeParameters
|
||||
): Promise<Types.PhysicalPartitionStorageInfoCollection | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/mongodbDatabases/${databaseName}/collections/${collectionName}/partitionMerge`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Gets the RUs per second of the MongoDB collection under an existing Azure Cosmos DB database account with the provided name. */
|
||||
export async function getMongoDBCollectionThroughput(
|
||||
subscriptionId: string,
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Lists all of the available Cosmos DB Resource Provider operations. */
|
||||
export async function list(): Promise<Types.OperationListResult> {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given partition key range id. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given partition key range id and region. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account. This url is only for PBS and Replication Latency data */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given account, source and target region. This url is only for PBS and Replication Latency data */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given account target region. This url is only for PBS and Replication Latency data */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Lists the SQL databases under an existing Azure Cosmos DB database account. */
|
||||
export async function listSqlDatabases(
|
||||
@@ -100,6 +100,42 @@ export async function migrateSqlDatabaseToManualThroughput(
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
/* Lists the ClientEncryptionKeys under an existing Azure Cosmos DB SQL database. */
|
||||
export async function listClientEncryptionKeys(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string
|
||||
): Promise<Types.ClientEncryptionKeysListResult> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/clientEncryptionKeys`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Gets the ClientEncryptionKey under an existing Azure Cosmos DB SQL database. */
|
||||
export async function getClientEncryptionKey(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
clientEncryptionKeyName: string
|
||||
): Promise<Types.ClientEncryptionKeyGetResults> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/clientEncryptionKeys/${clientEncryptionKeyName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Create or update a ClientEncryptionKey. This API is meant to be invoked via tools such as the Azure Powershell (instead of directly). */
|
||||
export async function createUpdateClientEncryptionKey(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
clientEncryptionKeyName: string,
|
||||
body: Types.ClientEncryptionKeyCreateUpdateParameters
|
||||
): Promise<Types.ClientEncryptionKeyGetResults | void> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/clientEncryptionKeys/${clientEncryptionKeyName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Lists the SQL container under an existing Azure Cosmos DB database account. */
|
||||
export async function listSqlContainers(
|
||||
subscriptionId: string,
|
||||
@@ -148,6 +184,31 @@ export async function deleteSqlContainer(
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
|
||||
}
|
||||
|
||||
/* Merges the partitions of a SQL database */
|
||||
export async function sqlDatabasePartitionMerge(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
body: Types.MergeParameters
|
||||
): Promise<Types.PhysicalPartitionStorageInfoCollection | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/partitionMerge`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Merges the partitions of a SQL Container */
|
||||
export async function listSqlContainerPartitionMerge(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
containerName: string,
|
||||
body: Types.MergeParameters
|
||||
): Promise<Types.PhysicalPartitionStorageInfoCollection | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/containers/${containerName}/partitionMerge`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Gets the RUs per second of the SQL container under an existing Azure Cosmos DB database account. */
|
||||
export async function getSqlContainerThroughput(
|
||||
subscriptionId: string,
|
||||
@@ -197,40 +258,54 @@ export async function migrateSqlContainerToManualThroughput(
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
/* Lists the ClientEncryptionKeys under an existing Azure Cosmos DB SQL database. */
|
||||
export async function listClientEncryptionKeys(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string
|
||||
): Promise<Types.ClientEncryptionKeysListResult> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/clientEncryptionKeys`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Gets the ClientEncryptionKey under an existing Azure Cosmos DB SQL database. */
|
||||
export async function getClientEncryptionKey(
|
||||
/* Retrieve throughput distribution for an Azure Cosmos DB SQL database */
|
||||
export async function sqlDatabaseRetrieveThroughputDistribution(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
clientEncryptionKeyName: string
|
||||
): Promise<Types.ClientEncryptionKeyGetResults> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/clientEncryptionKeys/${clientEncryptionKeyName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
body: Types.RetrieveThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/throughputSettings/default/retrieveThroughputDistribution`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Create or update a ClientEncryptionKey. This API is meant to be invoked via tools such as the Azure Powershell (instead of directly). */
|
||||
export async function createUpdateClientEncryptionKey(
|
||||
/* Redistribute throughput for an Azure Cosmos DB SQL database */
|
||||
export async function sqlDatabaseRedistributeThroughput(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
clientEncryptionKeyName: string,
|
||||
body: Types.ClientEncryptionKeyCreateUpdateParameters
|
||||
): Promise<Types.ClientEncryptionKeyGetResults | void> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/clientEncryptionKeys/${clientEncryptionKeyName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
||||
body: Types.RedistributeThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/throughputSettings/default/redistributeThroughput`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Retrieve throughput distribution for an Azure Cosmos DB SQL container */
|
||||
export async function sqlContainerRetrieveThroughputDistribution(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
containerName: string,
|
||||
body: Types.RetrieveThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/containers/${containerName}/throughputSettings/default/retrieveThroughputDistribution`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Redistribute throughput for an Azure Cosmos DB SQL container */
|
||||
export async function sqlContainerRedistributeThroughput(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
databaseName: string,
|
||||
containerName: string,
|
||||
body: Types.RedistributeThroughputParameters
|
||||
): Promise<Types.PhysicalPartitionThroughputInfoResult | void | Types.CloudError> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/sqlDatabases/${databaseName}/containers/${containerName}/throughputSettings/default/redistributeThroughput`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Lists the SQL storedProcedure under an existing Azure Cosmos DB database account. */
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2023-04-15";
|
||||
const apiVersion = "2023-09-15-preview";
|
||||
|
||||
/* Lists the Tables under an existing Azure Cosmos DB database account. */
|
||||
export async function listTables(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2023-04-15/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2023-09-15-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
/* The List operation response, that contains the client encryption keys and their properties. */
|
||||
@@ -18,6 +18,12 @@ export interface DatabaseAccountsListResult {
|
||||
readonly value?: DatabaseAccountGetResults[];
|
||||
}
|
||||
|
||||
/* The List operation response, that contains the Graph resource and their properties. */
|
||||
export interface GraphResourcesListResult {
|
||||
/* List of Graph resource and their properties. */
|
||||
readonly value?: GraphResourceGetResults[];
|
||||
}
|
||||
|
||||
/* The List operation response, that contains the SQL databases and their properties. */
|
||||
export interface SqlDatabaseListResult {
|
||||
/* List of SQL databases and their properties. */
|
||||
@@ -90,6 +96,12 @@ export interface GremlinGraphListResult {
|
||||
readonly value?: GremlinGraphGetResults[];
|
||||
}
|
||||
|
||||
/* The List operation response, that contains the Cassandra views and their properties. */
|
||||
export interface CassandraViewListResult {
|
||||
/* List of Cassandra views and their properties. */
|
||||
readonly value?: CassandraViewGetResults[];
|
||||
}
|
||||
|
||||
/* Error Response. */
|
||||
export interface ErrorResponse {
|
||||
/* Error code. */
|
||||
@@ -155,6 +167,9 @@ export interface ARMResourceProperties {
|
||||
location?: string;
|
||||
/* undocumented */
|
||||
tags?: Tags;
|
||||
|
||||
/* undocumented */
|
||||
identity?: ManagedServiceIdentity;
|
||||
}
|
||||
|
||||
/* The resource model definition for a ARM proxy resource. It will have everything other than required location and tags */
|
||||
@@ -234,6 +249,20 @@ export type SqlDatabaseGetResults = ARMResourceProperties & {
|
||||
properties?: SqlDatabaseGetProperties;
|
||||
};
|
||||
|
||||
/* The properties of an Azure Cosmos DB SQL database */
|
||||
export interface GraphResourceGetProperties {
|
||||
/* undocumented */
|
||||
resource?: GraphResource;
|
||||
/* undocumented */
|
||||
options?: OptionsResource;
|
||||
}
|
||||
|
||||
/* An Azure Cosmos DB Graph resource. */
|
||||
export type GraphResourceGetResults = ARMResourceProperties & {
|
||||
/* The properties of an Azure Cosmos DB Graph resource. */
|
||||
properties?: GraphResourceGetProperties;
|
||||
};
|
||||
|
||||
/* The properties of an Azure Cosmos DB SQL database */
|
||||
export interface SqlDatabaseGetProperties {
|
||||
/* undocumented */
|
||||
@@ -390,6 +419,20 @@ export interface GremlinGraphGetProperties {
|
||||
options?: OptionsResource;
|
||||
}
|
||||
|
||||
/* An Azure Cosmos DB Cassandra view. */
|
||||
export type CassandraViewGetResults = ARMResourceProperties & {
|
||||
/* The properties of an Azure Cosmos DB Cassandra view */
|
||||
properties?: CassandraViewGetProperties;
|
||||
};
|
||||
|
||||
/* The properties of an Azure Cosmos DB Cassandra view */
|
||||
export interface CassandraViewGetProperties {
|
||||
/* undocumented */
|
||||
resource?: CassandraViewResource & ExtendedResourceProperties;
|
||||
/* undocumented */
|
||||
options?: OptionsResource;
|
||||
}
|
||||
|
||||
/* The consistency policy for the Cosmos DB database account. */
|
||||
export interface ConsistencyPolicy {
|
||||
/* The default consistency level and configuration settings of the Cosmos DB account. */
|
||||
@@ -502,18 +545,33 @@ export interface DatabaseAccountGetProperties {
|
||||
/* An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account. */
|
||||
networkAclBypassResourceIds?: unknown[];
|
||||
|
||||
/* The Object representing the different Diagnostic log settings for the Cosmos DB Account. */
|
||||
diagnosticLogSettings?: DiagnosticLogSettings;
|
||||
|
||||
/* Opt-out of local authentication and ensure only MSI and AAD can be used exclusively for authentication. */
|
||||
disableLocalAuth?: boolean;
|
||||
/* The object that represents all properties related to capacity enforcement on an account. */
|
||||
capacity?: Capacity;
|
||||
|
||||
/* Flag to indicate whether to enable MaterializedViews on the Cosmos DB account */
|
||||
enableMaterializedViews?: boolean;
|
||||
/* The object that represents the metadata for the Account Keys of the Cosmos DB account. */
|
||||
keysMetadata?: DatabaseAccountKeysMetadata;
|
||||
|
||||
/* Flag to indicate enabling/disabling of Partition Merge feature on the account */
|
||||
enablePartitionMerge?: boolean;
|
||||
/* Flag to indicate enabling/disabling of Burst Capacity Preview feature on the account */
|
||||
enableBurstCapacity?: boolean;
|
||||
/* Indicates the minimum allowed Tls version. The default is Tls 1.0, except for Cassandra and Mongo API's, which only work with Tls 1.2. */
|
||||
minimalTlsVersion?: MinimalTlsVersion;
|
||||
|
||||
/* Indicates the status of the Customer Managed Key feature on the account. In case there are errors, the property provides troubleshooting guidance. */
|
||||
customerManagedKeyStatus?: CustomerManagedKeyStatus;
|
||||
|
||||
/* Flag to indicate enabling/disabling of Priority Based Execution Preview feature on the account */
|
||||
enablePriorityBasedExecution?: boolean;
|
||||
/* Enum to indicate default Priority Level of request for Priority Based Execution. */
|
||||
defaultPriorityLevel?: DefaultPriorityLevel;
|
||||
}
|
||||
|
||||
/* Properties to create and update Azure Cosmos DB database accounts. */
|
||||
@@ -581,6 +639,9 @@ export interface DatabaseAccountCreateUpdateProperties {
|
||||
/* An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account. */
|
||||
networkAclBypassResourceIds?: unknown[];
|
||||
|
||||
/* The Object representing the different Diagnostic log settings for the Cosmos DB Account. */
|
||||
diagnosticLogSettings?: DiagnosticLogSettings;
|
||||
|
||||
/* Opt-out of local authentication and ensure only MSI and AAD can be used exclusively for authentication. */
|
||||
disableLocalAuth?: boolean;
|
||||
/* Parameters to indicate the information about the restore. */
|
||||
@@ -589,13 +650,25 @@ export interface DatabaseAccountCreateUpdateProperties {
|
||||
/* The object that represents all properties related to capacity enforcement on an account. */
|
||||
capacity?: Capacity;
|
||||
|
||||
/* Flag to indicate whether to enable MaterializedViews on the Cosmos DB account */
|
||||
enableMaterializedViews?: boolean;
|
||||
/* This property is ignored during the update/create operation, as the metadata is read-only. The object represents the metadata for the Account Keys of the Cosmos DB account. */
|
||||
keysMetadata?: DatabaseAccountKeysMetadata;
|
||||
|
||||
/* Flag to indicate enabling/disabling of Partition Merge feature on the account */
|
||||
enablePartitionMerge?: boolean;
|
||||
/* Flag to indicate enabling/disabling of Burst Capacity Preview feature on the account */
|
||||
enableBurstCapacity?: boolean;
|
||||
/* Indicates the minimum allowed Tls version. The default is Tls 1.0, except for Cassandra and Mongo API's, which only work with Tls 1.2. */
|
||||
minimalTlsVersion?: MinimalTlsVersion;
|
||||
|
||||
/* Indicates the status of the Customer Managed Key feature on the account. In case there are errors, the property provides troubleshooting guidance. */
|
||||
customerManagedKeyStatus?: CustomerManagedKeyStatus;
|
||||
|
||||
/* Flag to indicate enabling/disabling of Priority Based Execution Preview feature on the account */
|
||||
enablePriorityBasedExecution?: boolean;
|
||||
/* Enum to indicate default Priority Level of request for Priority Based Execution. */
|
||||
defaultPriorityLevel?: DefaultPriorityLevel;
|
||||
}
|
||||
|
||||
/* Parameters to create and update Cosmos DB database accounts. */
|
||||
@@ -669,18 +742,33 @@ export interface DatabaseAccountUpdateProperties {
|
||||
/* An array that contains the Resource Ids for Network Acl Bypass for the Cosmos DB account. */
|
||||
networkAclBypassResourceIds?: unknown[];
|
||||
|
||||
/* The Object representing the different Diagnostic log settings for the Cosmos DB Account. */
|
||||
diagnosticLogSettings?: DiagnosticLogSettings;
|
||||
|
||||
/* Opt-out of local authentication and ensure only MSI and AAD can be used exclusively for authentication. */
|
||||
disableLocalAuth?: boolean;
|
||||
/* The object that represents all properties related to capacity enforcement on an account. */
|
||||
capacity?: Capacity;
|
||||
|
||||
/* Flag to indicate whether to enable MaterializedViews on the Cosmos DB account */
|
||||
enableMaterializedViews?: boolean;
|
||||
/* This property is ignored during the update operation, as the metadata is read-only. The object represents the metadata for the Account Keys of the Cosmos DB account. */
|
||||
keysMetadata?: DatabaseAccountKeysMetadata;
|
||||
|
||||
/* Flag to indicate enabling/disabling of Partition Merge feature on the account */
|
||||
enablePartitionMerge?: boolean;
|
||||
/* Flag to indicate enabling/disabling of Burst Capacity Preview feature on the account */
|
||||
enableBurstCapacity?: boolean;
|
||||
/* Indicates the minimum allowed Tls version. The default is Tls 1.0, except for Cassandra and Mongo API's, which only work with Tls 1.2. */
|
||||
minimalTlsVersion?: MinimalTlsVersion;
|
||||
|
||||
/* Indicates the status of the Customer Managed Key feature on the account. In case there are errors, the property provides troubleshooting guidance. */
|
||||
customerManagedKeyStatus?: CustomerManagedKeyStatus;
|
||||
|
||||
/* Flag to indicate enabling/disabling of Priority Based Execution Preview feature on the account */
|
||||
enablePriorityBasedExecution?: boolean;
|
||||
/* Enum to indicate default Priority Level of request for Priority Based Execution. */
|
||||
defaultPriorityLevel?: DefaultPriorityLevel;
|
||||
}
|
||||
|
||||
/* Parameters for patching Azure Cosmos DB database account properties. */
|
||||
@@ -762,6 +850,27 @@ export interface ThroughputSettingsUpdateProperties {
|
||||
resource: ThroughputSettingsResource;
|
||||
}
|
||||
|
||||
/* Parameters to create and update Cosmos DB Graph resource. */
|
||||
export type GraphResourceCreateUpdateParameters = ARMResourceProperties & {
|
||||
/* Properties to create and update Azure Cosmos DB Graph resource. */
|
||||
properties: GraphResourceCreateUpdateProperties;
|
||||
};
|
||||
|
||||
/* Properties to create and update Azure Cosmos DB Graph resource. */
|
||||
export interface GraphResourceCreateUpdateProperties {
|
||||
/* The standard JSON format of a Graph resource */
|
||||
resource: GraphResource;
|
||||
|
||||
/* A key-value pair of options to be applied for the request. This corresponds to the headers sent with the request. */
|
||||
options?: CreateUpdateOptions;
|
||||
}
|
||||
|
||||
/* Cosmos DB Graph resource object */
|
||||
export interface GraphResource {
|
||||
/* Name of the Cosmos DB Graph */
|
||||
id: string;
|
||||
}
|
||||
|
||||
/* Parameters to create and update Cosmos DB SQL database. */
|
||||
export type SqlDatabaseCreateUpdateParameters = ARMResourceProperties & {
|
||||
/* Properties to create and update Azure Cosmos DB SQL database. */
|
||||
@@ -942,6 +1051,21 @@ export interface GremlinGraphCreateUpdateProperties {
|
||||
options?: CreateUpdateOptions;
|
||||
}
|
||||
|
||||
/* Parameters to create and update Cosmos DB Cassandra view. */
|
||||
export type CassandraViewCreateUpdateParameters = ARMResourceProperties & {
|
||||
/* Properties to create and update Azure Cosmos DB Cassandra view. */
|
||||
properties: CassandraViewCreateUpdateProperties;
|
||||
};
|
||||
|
||||
/* Properties to create and update Azure Cosmos DB Cassandra view. */
|
||||
export interface CassandraViewCreateUpdateProperties {
|
||||
/* The standard JSON format of a Cassandra view */
|
||||
resource: CassandraViewResource;
|
||||
|
||||
/* A key-value pair of options to be applied for the request. This corresponds to the headers sent with the request. */
|
||||
options?: CreateUpdateOptions;
|
||||
}
|
||||
|
||||
/* Cosmos DB resource throughput object. Either throughput is required or autoscaleSettings is required, but not both. */
|
||||
export interface ThroughputSettingsResource {
|
||||
/* Value of the Cosmos DB resource throughput. Either throughput is required or autoscaleSettings is required, but not both. */
|
||||
@@ -992,6 +1116,80 @@ export interface OptionsResource {
|
||||
autoscaleSettings?: AutoscaleSettings;
|
||||
}
|
||||
|
||||
/* Cosmos DB redistribute throughput parameters object */
|
||||
export type RedistributeThroughputParameters = ARMResourceProperties & {
|
||||
/* Properties to redistribute throughput parameters object */
|
||||
properties: RedistributeThroughputProperties;
|
||||
};
|
||||
|
||||
/* Properties to redistribute throughput for Azure Cosmos DB resource. */
|
||||
export interface RedistributeThroughputProperties {
|
||||
/* The standard JSON format of a resource throughput */
|
||||
resource: RedistributeThroughputPropertiesResource;
|
||||
}
|
||||
|
||||
/* Resource to redistribute throughput for Azure Cosmos DB resource */
|
||||
export interface RedistributeThroughputPropertiesResource {
|
||||
/* ThroughputPolicy to apply for throughput redistribution */
|
||||
throughputPolicy: "none" | "equal" | "custom";
|
||||
|
||||
/* Array of PhysicalPartitionThroughputInfoResource objects. */
|
||||
targetPhysicalPartitionThroughputInfo: PhysicalPartitionThroughputInfoResource[];
|
||||
|
||||
/* Array of PhysicalPartitionThroughputInfoResource objects. */
|
||||
sourcePhysicalPartitionThroughputInfo: PhysicalPartitionThroughputInfoResource[];
|
||||
}
|
||||
|
||||
/* Cosmos DB retrieve throughput parameters object */
|
||||
export type RetrieveThroughputParameters = ARMResourceProperties & {
|
||||
/* Properties to retrieve throughput parameters object */
|
||||
properties: RetrieveThroughputProperties;
|
||||
};
|
||||
|
||||
/* Properties to retrieve throughput for Azure Cosmos DB resource. */
|
||||
export interface RetrieveThroughputProperties {
|
||||
/* The standard JSON format of a resource throughput */
|
||||
resource: RetrieveThroughputPropertiesResource;
|
||||
}
|
||||
|
||||
/* Resource to retrieve throughput information for Cosmos DB resource */
|
||||
export interface RetrieveThroughputPropertiesResource {
|
||||
/* Array of PhysicalPartitionId objects. */
|
||||
physicalPartitionIds: PhysicalPartitionId[];
|
||||
}
|
||||
|
||||
/* PhysicalPartitionId object */
|
||||
export interface PhysicalPartitionId {
|
||||
/* Id of a physical partition */
|
||||
id: string;
|
||||
}
|
||||
|
||||
/* An Azure Cosmos DB PhysicalPartitionThroughputInfoResult object. */
|
||||
export type PhysicalPartitionThroughputInfoResult = ARMResourceProperties & {
|
||||
/* The properties of an Azure Cosmos DB PhysicalPartitionThroughputInfoResult object */
|
||||
properties?: PhysicalPartitionThroughputInfoResultProperties;
|
||||
};
|
||||
|
||||
/* The properties of an Azure Cosmos DB PhysicalPartitionThroughputInfoResult object */
|
||||
export interface PhysicalPartitionThroughputInfoResultProperties {
|
||||
/* properties of physical partition throughput info */
|
||||
resource?: PhysicalPartitionThroughputInfoProperties;
|
||||
}
|
||||
|
||||
/* The properties of an Azure Cosmos DB PhysicalPartitionThroughputInfoProperties object */
|
||||
export interface PhysicalPartitionThroughputInfoProperties {
|
||||
/* Array of physical partition throughput info objects */
|
||||
physicalPartitionThroughputInfo?: PhysicalPartitionThroughputInfoResource[];
|
||||
}
|
||||
|
||||
/* PhysicalPartitionThroughputInfo object */
|
||||
export interface PhysicalPartitionThroughputInfoResource {
|
||||
/* Id of a physical partition */
|
||||
id: string;
|
||||
/* Throughput of a physical partition */
|
||||
throughput?: number;
|
||||
}
|
||||
|
||||
/* Cosmos DB client encryption key resource object. */
|
||||
export interface ClientEncryptionKeyResource {
|
||||
/* Name of the ClientEncryptionKey */
|
||||
@@ -1020,6 +1218,11 @@ export interface KeyWrapMetadata {
|
||||
export interface SqlDatabaseResource {
|
||||
/* Name of the Cosmos DB SQL database */
|
||||
id: string;
|
||||
/* Parameters to indicate the information about the restore */
|
||||
restoreParameters?: ResourceRestoreParameters;
|
||||
|
||||
/* Enum to indicate the mode of resource creation. */
|
||||
createMode?: CreateMode;
|
||||
}
|
||||
|
||||
/* Cosmos DB SQL container resource object */
|
||||
@@ -1045,6 +1248,14 @@ export interface SqlContainerResource {
|
||||
|
||||
/* Analytical TTL. */
|
||||
analyticalStorageTtl?: number;
|
||||
/* Parameters to indicate the information about the restore */
|
||||
restoreParameters?: ResourceRestoreParameters;
|
||||
|
||||
/* Enum to indicate the mode of resource creation. */
|
||||
createMode?: CreateMode;
|
||||
|
||||
/* The configuration for defining Materialized Views. This must be specified only for creating a Materialized View container. */
|
||||
materializedViewDefinition?: MaterializedViewDefinition;
|
||||
}
|
||||
|
||||
/* Cosmos DB indexing policy */
|
||||
@@ -1175,6 +1386,16 @@ export interface ClientEncryptionIncludedPath {
|
||||
encryptionAlgorithm: string;
|
||||
}
|
||||
|
||||
/* Materialized View definition for the container. */
|
||||
export interface MaterializedViewDefinition {
|
||||
/* An unique identifier for the source collection. This is a system generated property. */
|
||||
readonly sourceCollectionRid?: string;
|
||||
/* The name of the source container on which the Materialized View will be created. */
|
||||
sourceCollectionId: string;
|
||||
/* The definition should be an SQL query which would be used to fetch data from the source container to populate into the Materialized View container. */
|
||||
definition: string;
|
||||
}
|
||||
|
||||
/* Cosmos DB SQL storedProcedure resource object */
|
||||
export interface SqlStoredProcedureResource {
|
||||
/* Name of the Cosmos DB SQL storedProcedure */
|
||||
@@ -1208,6 +1429,11 @@ export interface SqlTriggerResource {
|
||||
export interface MongoDBDatabaseResource {
|
||||
/* Name of the Cosmos DB MongoDB database */
|
||||
id: string;
|
||||
/* Parameters to indicate the information about the restore */
|
||||
restoreParameters?: ResourceRestoreParameters;
|
||||
|
||||
/* Enum to indicate the mode of resource creation. */
|
||||
createMode?: CreateMode;
|
||||
}
|
||||
|
||||
/* Cosmos DB MongoDB collection resource object */
|
||||
@@ -1222,6 +1448,11 @@ export interface MongoDBCollectionResource {
|
||||
|
||||
/* Analytical TTL. */
|
||||
analyticalStorageTtl?: number;
|
||||
/* Parameters to indicate the information about the restore */
|
||||
restoreParameters?: ResourceRestoreParameters;
|
||||
|
||||
/* Enum to indicate the mode of resource creation. */
|
||||
createMode?: CreateMode;
|
||||
}
|
||||
|
||||
/* The shard key and partition kind pair, only support "Hash" partition kind */
|
||||
@@ -1257,6 +1488,11 @@ export interface MongoIndexOptions {
|
||||
export interface TableResource {
|
||||
/* Name of the Cosmos DB table */
|
||||
id: string;
|
||||
/* Parameters to indicate the information about the restore */
|
||||
restoreParameters?: ResourceRestoreParameters;
|
||||
|
||||
/* Enum to indicate the mode of resource creation. */
|
||||
createMode?: CreateMode;
|
||||
}
|
||||
|
||||
/* Cosmos DB Cassandra keyspace resource object */
|
||||
@@ -1316,6 +1552,11 @@ export interface ClusterKey {
|
||||
export interface GremlinDatabaseResource {
|
||||
/* Name of the Cosmos DB Gremlin database */
|
||||
id: string;
|
||||
/* Parameters to indicate the information about the restore */
|
||||
restoreParameters?: ResourceRestoreParameters;
|
||||
|
||||
/* Enum to indicate the mode of resource creation. */
|
||||
createMode?: CreateMode;
|
||||
}
|
||||
|
||||
/* Cosmos DB Gremlin graph resource object */
|
||||
@@ -1338,13 +1579,26 @@ export interface GremlinGraphResource {
|
||||
|
||||
/* Analytical TTL. */
|
||||
analyticalStorageTtl?: number;
|
||||
/* Parameters to indicate the information about the restore */
|
||||
restoreParameters?: ResourceRestoreParameters;
|
||||
|
||||
/* Enum to indicate the mode of resource creation. */
|
||||
createMode?: CreateMode;
|
||||
}
|
||||
|
||||
/* Cosmos DB Cassandra view resource object */
|
||||
export interface CassandraViewResource {
|
||||
/* Name of the Cosmos DB Cassandra view */
|
||||
id: string;
|
||||
/* View Definition of the Cosmos DB Cassandra view */
|
||||
viewDefinition: string;
|
||||
}
|
||||
|
||||
/* CreateUpdateOptions are a list of key-value pairs that describe the resource. Supported keys are "If-Match", "If-None-Match", "Session-Token" and "Throughput" */
|
||||
export interface CreateUpdateOptions {
|
||||
/* Request Units per second. For example, "throughput": 10000. */
|
||||
throughput?: number;
|
||||
/* Specifies the Autoscale settings. */
|
||||
/* Specifies the Autoscale settings. Note: Either throughput or autoscaleSettings is required, but not both. */
|
||||
autoscaleSettings?: AutoscaleSettings;
|
||||
}
|
||||
|
||||
@@ -1426,6 +1680,12 @@ export interface DatabaseAccountKeysMetadata {
|
||||
readonly secondaryReadonlyMasterKey?: AccountKeyMetadata;
|
||||
}
|
||||
|
||||
/* Indicates what diagnostic log settings are to be enabled. */
|
||||
export interface DiagnosticLogSettings {
|
||||
/* Describe the level of detail with which queries are to be logged. */
|
||||
enableFullTextQuery?: "None" | "True" | "False";
|
||||
}
|
||||
|
||||
/* REST API operation */
|
||||
export interface Operation {
|
||||
/* Operation name: {provider}/{resource}/{operation} */
|
||||
@@ -1642,7 +1902,7 @@ export type AnalyticalStorageSchemaType = "WellDefined" | "FullFidelity";
|
||||
export type CreateMode = "Default" | "Restore";
|
||||
|
||||
/* Parameters to indicate the information about the restore. */
|
||||
export interface RestoreParameters {
|
||||
export type RestoreParameters = RestoreParametersBase & {
|
||||
/* Describes the mode of the restore. */
|
||||
restoreMode?: "PointInTime";
|
||||
|
||||
@@ -1658,8 +1918,22 @@ export interface RestoreParameters {
|
||||
|
||||
/* List of specific tables available for restore. */
|
||||
tablesToRestore?: TableName[];
|
||||
|
||||
/* The source backup location for restore. */
|
||||
sourceBackupLocation?: string;
|
||||
};
|
||||
|
||||
/* Parameters to indicate the information about the restore. */
|
||||
export interface RestoreParametersBase {
|
||||
/* The id of the restorable database account from which the restore has to be initiated. For example: /subscriptions/{subscriptionId}/providers/Microsoft.DocumentDB/locations/{location}/restorableDatabaseAccounts/{restorableDatabaseAccountName} */
|
||||
restoreSource?: string;
|
||||
/* Time to which the account has to be restored (ISO-8601 format). */
|
||||
restoreTimestampInUtc?: string;
|
||||
}
|
||||
|
||||
/* Parameters to indicate the information about the restore. */
|
||||
export type ResourceRestoreParameters = RestoreParametersBase;
|
||||
|
||||
/* Specific Databases to restore. */
|
||||
export interface DatabaseRestoreResource {
|
||||
/* The name of the database available for restore. */
|
||||
@@ -1736,10 +2010,30 @@ export interface PeriodicModeProperties {
|
||||
|
||||
/* Configuration values for periodic mode backup */
|
||||
export interface ContinuousModeProperties {
|
||||
/* Enum to indicate type of Continuous backup mode */
|
||||
/* Enum to indicate type of Continuos backup mode */
|
||||
tier?: ContinuousTier;
|
||||
}
|
||||
|
||||
/* The properties of an Azure Cosmos DB merge operations */
|
||||
export interface MergeParameters {
|
||||
/* Specifies whether the operation is a real merge operation or a simulation. */
|
||||
isDryRun?: boolean;
|
||||
}
|
||||
|
||||
/* List of physical partitions and their properties returned by a merge operation. */
|
||||
export interface PhysicalPartitionStorageInfoCollection {
|
||||
/* List of physical partitions and their properties. */
|
||||
readonly physicalPartitionStorageInfoCollection?: physicalPartitionStorageInfo[];
|
||||
}
|
||||
|
||||
/* The storage of a physical partition */
|
||||
export interface physicalPartitionStorageInfo {
|
||||
/* The unique identifier of the partition. */
|
||||
readonly id?: string;
|
||||
/* The storage in KB for the physical partition. */
|
||||
readonly storageInKB?: number;
|
||||
}
|
||||
|
||||
/* The List operation response, that contains Cosmos DB locations and their properties. */
|
||||
export interface LocationListResult {
|
||||
/* List of Cosmos DB locations and their properties. */
|
||||
@@ -1777,3 +2071,20 @@ export type ContinuousTier = "Continuous7Days" | "Continuous30Days";
|
||||
|
||||
/* Indicates the minimum allowed Tls version. The default is Tls 1.0, except for Cassandra and Mongo API's, which only work with Tls 1.2. */
|
||||
export type MinimalTlsVersion = "Tls" | "Tls11" | "Tls12";
|
||||
|
||||
/* Indicates the status of the Customer Managed Key feature on the account. In case there are errors, the property provides troubleshooting guidance. */
|
||||
export type CustomerManagedKeyStatus =
|
||||
| "Access to your account is currently revoked because the Azure Cosmos DB service is unable to obtain the AAD authentication token for the account's default identity; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#azure-active-directory-token-acquisition-error (4000)."
|
||||
| "Access to your account is currently revoked because the Azure Cosmos DB account's key vault key URI does not follow the expected format; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#improper-syntax-detected-on-the-key-vault-uri-property (4006)."
|
||||
| "Access to your account is currently revoked because the current default identity no longer has permission to the associated Key Vault key; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#default-identity-is-unauthorized-to-access-the-azure-key-vault-key (4002)."
|
||||
| "Access to your account is currently revoked because the Azure Key Vault DNS name specified by the account's keyvaultkeyuri property could not be resolved; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#unable-to-resolve-the-key-vaults-dns (4009)."
|
||||
| "Access to your account is currently revoked because the correspondent key is not found on the specified Key Vault; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#azure-key-vault-resource-not-found (4003)."
|
||||
| "Access to your account is currently revoked because the Azure Cosmos DB service is unable to wrap or unwrap the key; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#internal-unwrapping-procedure-error (4005)."
|
||||
| "Access to your account is currently revoked because the Azure Cosmos DB account has an undefined default identity; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#invalid-azure-cosmos-db-default-identity (4015)."
|
||||
| "Access to your account is currently revoked because the access rules are blocking outbound requests to the Azure Key Vault service; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide (4016)."
|
||||
| "Access to your account is currently revoked because the correspondent Azure Key Vault was not found; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide#azure-key-vault-resource-not-found (4017)."
|
||||
| "Access to your account is currently revoked; for more details about this error and how to restore access to your account please visit https://learn.microsoft.com/en-us/azure/cosmos-db/cmk-troubleshooting-guide"
|
||||
| "Access to the configured customer managed key confirmed.";
|
||||
|
||||
/* Enum to indicate default priorityLevel of requests */
|
||||
export type DefaultPriorityLevel = "High" | "Low";
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { createUri } from "Common/UrlUtility";
|
||||
import { FabricMessage } from "Contracts/FabricContract";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { useSelectedNode } from "Explorer/useSelectedNode";
|
||||
import { fetchEncryptedToken } from "Platform/Hosted/Components/ConnectExplorer";
|
||||
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
|
||||
import { fetchAccessData } from "hooks/usePortalAccessToken";
|
||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||
import { useEffect, useState } from "react";
|
||||
import { AuthType } from "../AuthType";
|
||||
@@ -8,7 +12,7 @@ import { AccountKind, Flights } from "../Common/Constants";
|
||||
import { normalizeArmEndpoint } from "../Common/EnvironmentUtility";
|
||||
import { sendMessage, sendReadyMessage } from "../Common/MessageHandler";
|
||||
import { Platform, configContext, updateConfigContext } from "../ConfigContext";
|
||||
import { ActionType, DataExplorerAction } from "../Contracts/ActionContracts";
|
||||
import { ActionType, DataExplorerAction, TabKind } from "../Contracts/ActionContracts";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { DataExplorerInputsFrame } from "../Contracts/ViewModels";
|
||||
import { handleOpenAction } from "../Explorer/OpenActions/OpenActions";
|
||||
@@ -60,6 +64,9 @@ export function useKnockoutExplorer(platform: Platform): Explorer {
|
||||
} else if (platform === Platform.Portal) {
|
||||
const explorer = await configurePortal();
|
||||
setExplorer(explorer);
|
||||
} else if (platform === Platform.Fabric) {
|
||||
const explorer = await configureFabric();
|
||||
setExplorer(explorer);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -78,11 +85,104 @@ export function useKnockoutExplorer(platform: Platform): Explorer {
|
||||
return explorer;
|
||||
}
|
||||
|
||||
async function configureFabric(): Promise<Explorer> {
|
||||
let explorer: Explorer;
|
||||
return new Promise<Explorer>((resolve) => {
|
||||
window.addEventListener(
|
||||
"message",
|
||||
async (event) => {
|
||||
if (isInvalidParentFrameOrigin(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldProcessMessage(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data: FabricMessage = event.data?.data;
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case "initialize": {
|
||||
// TODO For now, retrieve info from session storage. Replace with info injected into Data Explorer
|
||||
const connectionString = data.connectionString ?? sessionStorage.getItem("connectionString");
|
||||
if (!connectionString) {
|
||||
console.error("No connection string found in session storage");
|
||||
return undefined;
|
||||
}
|
||||
const encryptedToken = await fetchEncryptedToken(connectionString);
|
||||
// TODO Duplicated from useTokenMetadata
|
||||
const encryptedTokenMetadata = await fetchAccessData(encryptedToken);
|
||||
|
||||
const hostedConfig: EncryptedToken = {
|
||||
authType: AuthType.EncryptedToken,
|
||||
encryptedToken,
|
||||
encryptedTokenMetadata,
|
||||
};
|
||||
|
||||
explorer = await configureWithEncryptedToken(hostedConfig);
|
||||
resolve(explorer);
|
||||
break;
|
||||
}
|
||||
case "newContainer":
|
||||
explorer.onNewCollectionClicked();
|
||||
break;
|
||||
case "openTab": {
|
||||
// Expand database first
|
||||
const databaseName = sessionStorage.getItem("openDatabaseName") ?? data.databaseName;
|
||||
const database = useDatabases.getState().databases.find((db) => db.id() === databaseName);
|
||||
if (database) {
|
||||
await database.expandDatabase();
|
||||
useDatabases.getState().updateDatabase(database);
|
||||
useSelectedNode.getState().setSelectedNode(database);
|
||||
|
||||
let collectionResourceId = data.collectionName;
|
||||
if (collectionResourceId === undefined) {
|
||||
// Pick first collection if collectionName not specified in message
|
||||
collectionResourceId = database.collections()[0]?.id();
|
||||
}
|
||||
|
||||
if (collectionResourceId !== undefined) {
|
||||
// Expand collection
|
||||
const collection = database.collections().find((coll) => coll.id() === collectionResourceId);
|
||||
collection.expandCollection();
|
||||
useSelectedNode.getState().setSelectedNode(collection);
|
||||
|
||||
handleOpenAction(
|
||||
{
|
||||
actionType: ActionType.OpenCollectionTab,
|
||||
databaseResourceId: databaseName,
|
||||
collectionResourceId: data.collectionName,
|
||||
tabKind: TabKind.SQLDocuments,
|
||||
} as DataExplorerAction,
|
||||
useDatabases.getState().databases,
|
||||
explorer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.error(`Unknown Fabric message type: ${JSON.stringify(data)}`);
|
||||
break;
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
sendReadyMessage();
|
||||
});
|
||||
}
|
||||
|
||||
async function configureHosted(): Promise<Explorer> {
|
||||
const win = (window as unknown) as HostedExplorerChildFrame;
|
||||
let explorer: Explorer;
|
||||
if (win.hostedConfig.authType === AuthType.EncryptedToken) {
|
||||
explorer = configureHostedWithEncryptedToken(win.hostedConfig);
|
||||
explorer = configureWithEncryptedToken(win.hostedConfig);
|
||||
} else if (win.hostedConfig.authType === AuthType.ResourceToken) {
|
||||
explorer = configureHostedWithResourceToken(win.hostedConfig);
|
||||
} else if (win.hostedConfig.authType === AuthType.ConnectionString) {
|
||||
@@ -215,7 +315,7 @@ function configureHostedWithResourceToken(config: ResourceToken): Explorer {
|
||||
return explorer;
|
||||
}
|
||||
|
||||
function configureHostedWithEncryptedToken(config: EncryptedToken): Explorer {
|
||||
function configureWithEncryptedToken(config: EncryptedToken): Explorer {
|
||||
const apiExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(config.encryptedTokenMetadata.apiKind);
|
||||
updateUserContext({
|
||||
authType: AuthType.EncryptedToken,
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { CollectionTabKind } from "../Contracts/ViewModels";
|
||||
import NotebookTabV2 from "../Explorer/Tabs/NotebookV2Tab";
|
||||
import TabsBase from "../Explorer/Tabs/TabsBase";
|
||||
import { Platform, configContext } from "./../ConfigContext";
|
||||
|
||||
interface TabsState {
|
||||
openedTabs: TabsBase[];
|
||||
@@ -37,11 +38,22 @@ export enum ReactTabKind {
|
||||
QueryCopilot,
|
||||
}
|
||||
|
||||
// HACK: using this const when the configuration context is not initialized yet.
|
||||
// Since Fabric is always setting the url param, use that instead of the regular config.
|
||||
const isPlatformFabric = (() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (params.has("platform")) {
|
||||
const platform = params.get("platform");
|
||||
return platform === Platform.Fabric;
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
|
||||
export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
openedTabs: [],
|
||||
openedReactTabs: [ReactTabKind.Home],
|
||||
openedReactTabs: !isPlatformFabric ? [ReactTabKind.Home] : [],
|
||||
activeTab: undefined,
|
||||
activeReactTab: ReactTabKind.Home,
|
||||
activeReactTab: !isPlatformFabric ? ReactTabKind.Home : undefined,
|
||||
networkSettingsWarning: "",
|
||||
queryCopilotTabInitialInput: "",
|
||||
isTabExecuting: false,
|
||||
@@ -92,7 +104,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (updatedTabs.length === 0) {
|
||||
if (updatedTabs.length === 0 && configContext.platform !== Platform.Fabric) {
|
||||
set({ activeTab: undefined, activeReactTab: ReactTabKind.Home });
|
||||
}
|
||||
|
||||
@@ -130,7 +142,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
}
|
||||
});
|
||||
|
||||
if (get().openedTabs.length === 0) {
|
||||
if (get().openedTabs.length === 0 && configContext.platform !== Platform.Fabric) {
|
||||
set({ activeTab: undefined, activeReactTab: ReactTabKind.Home });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +57,22 @@ describe("shouldShowQueryPageOptions()", () => {
|
||||
});
|
||||
expect(userContext.apiType).toBe("Mongo");
|
||||
});
|
||||
|
||||
it("should be 'Postgres' for Postgres API", () => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
kind: "Postgres",
|
||||
} as DatabaseAccount,
|
||||
});
|
||||
expect(userContext.apiType).toBe("Postgres");
|
||||
});
|
||||
|
||||
it("should be 'VCoreMongo' for vCore Mongo", () => {
|
||||
updateUserContext({
|
||||
databaseAccount: {
|
||||
kind: "VCoreMongo",
|
||||
} as DatabaseAccount,
|
||||
});
|
||||
expect(userContext.apiType).toBe("VCoreMongo");
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user