Compare commits

..

1 Commits

Author SHA1 Message Date
vaidankarswapnil
877813b7f9 Fix a11y database Id radiobutton issue 2021-09-20 19:13:29 +05:30
119 changed files with 1692 additions and 2173 deletions

View File

@@ -6,7 +6,7 @@ src/Api/Apis.ts
src/AuthType.ts
src/Bindings/BindingHandlersRegisterer.ts
src/Bindings/ReactBindingHandler.ts
src/Common/Constants/index.ts
src/Common/Constants.ts
src/Common/CosmosClient.test.ts
src/Common/CosmosClient.ts
src/Common/DataAccessUtilityBase.test.ts
@@ -81,13 +81,17 @@ src/Explorer/Tables/DataTable/DataTableBindingManager.ts
src/Explorer/Tables/DataTable/DataTableBuilder.ts
src/Explorer/Tables/DataTable/DataTableContextMenu.ts
src/Explorer/Tables/DataTable/DataTableOperationManager.ts
# src/Explorer/Tables/DataTable/DataTableOperations.ts
src/Explorer/Tables/DataTable/DataTableOperations.ts
src/Explorer/Tables/DataTable/DataTableViewModel.ts
# src/Explorer/Tables/DataTable/TableCommands.ts
# src/Explorer/Tables/DataTable/TableEntityCache.ts
src/Explorer/Tables/DataTable/TableCommands.ts
src/Explorer/Tables/DataTable/TableEntityCache.ts
src/Explorer/Tables/DataTable/TableEntityListViewModel.ts
# src/Explorer/Tables/Entities.ts
src/Explorer/Tables/Entities.ts
src/Explorer/Tables/QueryBuilder/ClauseGroup.ts
src/Explorer/Tables/QueryBuilder/ClauseGroupViewModel.ts
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
src/Explorer/Tables/QueryBuilder/QueryBuilderViewModel.ts
src/Explorer/Tables/QueryBuilder/QueryClauseViewModel.ts
src/Explorer/Tables/TableDataClient.ts
src/Explorer/Tables/TableEntityProcessor.ts
src/Explorer/Tables/Utilities.ts
@@ -111,10 +115,15 @@ src/Explorer/Tree/ObjectId.ts
src/Explorer/Tree/ResourceTokenCollection.ts
src/Explorer/Tree/StoredProcedure.ts
src/Explorer/Tree/TreeComponents.ts
src/Explorer/Tree/Trigger.ts
src/Explorer/WaitsForTemplateViewModel.ts
src/GitHub/GitHubClient.test.ts
src/GitHub/GitHubClient.ts
src/GitHub/GitHubConnector.ts
src/GitHub/GitHubOAuthService.ts
src/Index.ts
src/Juno/JunoClient.test.ts
src/Juno/JunoClient.ts
src/Platform/Hosted/Authorization.ts
src/ReactDevTools.ts
src/Shared/Constants.ts
@@ -134,7 +143,7 @@ src/Explorer/Controls/Notebook/NotebookTerminalComponent.tsx
src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx
src/Explorer/Controls/TreeComponent/TreeComponent.tsx
src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx
; src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx
src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx
src/Explorer/Graph/GraphExplorerComponent/GraphVizComponent.tsx
src/Explorer/Graph/GraphExplorerComponent/LeftPaneComponent.tsx
src/Explorer/Graph/GraphExplorerComponent/MiddlePaneComponent.tsx
@@ -144,10 +153,10 @@ src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.test.t
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
; src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
src/Explorer/Notebook/NotebookComponent/VirtualCommandBarComponent.tsx
src/Explorer/Notebook/NotebookComponent/contents/index.tsx
; src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx
src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx
src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx
src/Explorer/Notebook/NotebookRenderer/decorators/draggable/index.tsx
src/Explorer/Notebook/NotebookRenderer/decorators/hijack-scroll/index.tsx

View File

@@ -39,6 +39,7 @@ module.exports = {
"@typescript-eslint/switch-exhaustiveness-check": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-extraneous-class": "error",
"no-null/no-null": "error",
"@typescript-eslint/no-explicit-any": "error",
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
eqeqeq: "error",

View File

@@ -22,6 +22,5 @@
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"typescript.preferences.importModuleSpecifier": "non-relative"
}
}

View File

@@ -1,8 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<path
d="M14,2.691l-5.301,5.309l5.301,5.309l-0.691,0.691l-5.309,-5.301l-5.309,5.301l-0.691,-0.691l5.301,-5.309l-5.301,-5.309l0.691,-0.691l5.309,5.301l5.309,-5.301l0.691,0.691Z"
transform="scale(0.5)" fill="#000" stroke="#000">
<path
d="M14,2.691l-5.301,5.309l5.301,5.309l-0.691,0.691l-5.309,-5.301l-5.309,5.301l-0.691,-0.691l5.301,-5.309l-5.301,-5.309l0.691,-0.691l5.309,5.301l5.309,-5.301l0.691,0.691Z"
transform="scale(0.5)"
fill="#000"
stroke="#CCC"
>
</path>
</svg>

Before

Width:  |  Height:  |  Size: 449 B

After

Width:  |  Height:  |  Size: 503 B

View File

@@ -37,8 +37,8 @@ module.exports = {
global: {
branches: 25,
functions: 25,
lines: 29,
statements: 29,
lines: 29.5,
statements: 29.5,
},
},
@@ -129,8 +129,6 @@ module.exports = {
// The test environment that will be used for testing
// testEnvironment: "jest-environment-jsdom",
modulePaths: ["node_modules", "<rootDir>/src"],
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},

View File

@@ -2357,8 +2357,6 @@ a:link {
height: 100%;
flex-grow: 1;
overflow: hidden;
min-height: 300px;
overflow-y: scroll;
}
.tabs {
@@ -2834,8 +2832,6 @@ a:link {
#explorerNotificationConsole {
z-index: 1000;
overflow-y: auto;
overflow-x: clip;
}
.uniqueIndexesContainer {

384
src/Common/Constants.ts Normal file
View File

@@ -0,0 +1,384 @@
export class CodeOfConductEndpoints {
public static privacyStatement: string = "https://aka.ms/ms-privacy-policy";
public static codeOfConduct: string = "https://aka.ms/cosmos-code-of-conduct";
public static termsOfUse: string = "https://aka.ms/ms-terms-of-use";
}
export class EndpointsRegex {
public static readonly cassandra = [
"AccountEndpoint=(.*).cassandra.cosmosdb.azure.com",
"HostName=(.*).cassandra.cosmos.azure.com",
];
public static readonly mongo = "mongodb://.*:(.*)@(.*).documents.azure.com";
public static readonly mongoCompute = "mongodb://.*:(.*)@(.*).mongo.cosmos.azure.com";
public static readonly sql = "AccountEndpoint=https://(.*).documents.azure.com";
public static readonly table = "TableEndpoint=https://(.*).table.cosmosdb.azure.com";
}
export class ApiEndpoints {
public static runtimeProxy: string = "/api/RuntimeProxy";
public static guestRuntimeProxy: string = "/api/guest/RuntimeProxy";
}
export class ServerIds {
public static localhost: string = "localhost";
public static blackforest: string = "blackforest";
public static fairfax: string = "fairfax";
public static mooncake: string = "mooncake";
public static productionPortal: string = "prod";
public static dev: string = "dev";
}
export class ArmApiVersions {
public static readonly documentDB: string = "2015-11-06";
public static readonly arcadia: string = "2019-06-01-preview";
public static readonly arcadiaLivy: string = "2019-11-01-preview";
public static readonly arm: string = "2015-11-01";
public static readonly armFeatures: string = "2014-08-01-preview";
public static readonly publicVersion = "2020-04-01";
}
export class ArmResourceTypes {
public static readonly notebookWorkspaces = "Microsoft.DocumentDB/databaseAccounts/notebookWorkspaces";
public static readonly synapseWorkspaces = "Microsoft.Synapse/workspaces";
}
export class BackendDefaults {
public static partitionKeyKind = "Hash";
public static singlePartitionStorageInGb: string = "10";
public static multiPartitionStorageInGb: string = "100";
public static maxChangeFeedRetentionDuration: number = 10;
public static partitionKeyVersion = 2;
}
export class ClientDefaults {
public static requestTimeoutMs: number = 60000;
public static portalCacheTimeoutMs: number = 10000;
public static errorNotificationTimeoutMs: number = 5000;
public static copyHelperTimeoutMs: number = 2000;
public static waitForDOMElementMs: number = 500;
public static cacheBustingTimeoutMs: number =
10 /** minutes **/ * 60 /** to seconds **/ * 1000 /** to milliseconds **/;
public static databaseThroughputIncreaseFactor: number = 100;
public static readonly arcadiaTokenRefreshInterval: number =
20 /** minutes **/ * 60 /** to seconds **/ * 1000 /** to milliseconds **/;
public static readonly arcadiaTokenRefreshIntervalPaddingMs: number = 2000;
}
export enum AccountKind {
DocumentDB = "DocumentDB",
MongoDB = "MongoDB",
Parse = "Parse",
GlobalDocumentDB = "GlobalDocumentDB",
Default = "DocumentDB",
}
export class CorrelationBackend {
public static Url: string = "https://aka.ms/cosmosdbanalytics";
}
export class CapabilityNames {
public static EnableTable: string = "EnableTable";
public static EnableGremlin: string = "EnableGremlin";
public static EnableCassandra: string = "EnableCassandra";
public static EnableAutoScale: string = "EnableAutoScale";
public static readonly EnableNotebooks: string = "EnableNotebooks";
public static readonly EnableStorageAnalytics: string = "EnableStorageAnalytics";
public static readonly EnableMongo: string = "EnableMongo";
public static readonly EnableServerless: string = "EnableServerless";
}
// flight names returned from the portal are always lowercase
export class Flights {
public static readonly SettingsV2 = "settingsv2";
public static readonly MongoIndexEditor = "mongoindexeditor";
public static readonly MongoIndexing = "mongoindexing";
public static readonly AutoscaleTest = "autoscaletest";
public static readonly PartitionKeyTest = "partitionkeytest";
public static readonly PKPartitionKeyTest = "pkpartitionkeytest";
public static readonly Phoenix = "phoenix";
}
export class AfecFeatures {
public static readonly Spark = "spark-public-preview";
public static readonly Notebooks = "sparknotebooks-public-preview";
public static readonly StorageAnalytics = "storageanalytics-public-preview";
}
export class TagNames {
public static defaultExperience: string = "defaultExperience";
}
export class MongoDBAccounts {
public static protocol: string = "https";
public static defaultPort: string = "10255";
}
export enum MongoBackendEndpointType {
local,
remote,
}
// TODO: 435619 Add default endpoints per cloud and use regional only when available
export class CassandraBackend {
public static readonly createOrDeleteApi: string = "api/cassandra/createordelete";
public static readonly guestCreateOrDeleteApi: string = "api/guest/cassandra/createordelete";
public static readonly queryApi: string = "api/cassandra";
public static readonly guestQueryApi: string = "api/guest/cassandra";
public static readonly keysApi: string = "api/cassandra/keys";
public static readonly guestKeysApi: string = "api/guest/cassandra/keys";
public static readonly schemaApi: string = "api/cassandra/schema";
public static readonly guestSchemaApi: string = "api/guest/cassandra/schema";
}
export class Queries {
public static CustomPageOption: string = "custom";
public static UnlimitedPageOption: string = "unlimited";
public static itemsPerPage: number = 100;
public static unlimitedItemsPerPage: number = 100; // TODO: Figure out appropriate value so it works for accounts with a large number of partitions
public static QueryEditorMinHeightRatio: number = 0.1;
public static QueryEditorMaxHeightRatio: number = 0.4;
public static readonly DefaultMaxDegreeOfParallelism = 6;
}
export class SavedQueries {
public static readonly CollectionName: string = "___Query";
public static readonly DatabaseName: string = "___Cosmos";
public static readonly OfferThroughput: number = 400;
public static readonly PartitionKeyProperty: string = "id";
}
export class DocumentsGridMetrics {
public static DocumentsPerPage: number = 100;
public static IndividualRowHeight: number = 34;
public static BufferHeight: number = 28;
public static SplitterMinWidth: number = 200;
public static SplitterMaxWidth: number = 360;
public static DocumentEditorMinWidthRatio: number = 0.2;
public static DocumentEditorMaxWidthRatio: number = 0.4;
}
export class Areas {
public static ResourceTree: string = "Resource Tree";
public static ContextualPane: string = "Contextual Pane";
public static Tab: string = "Tab";
public static ShareDialog: string = "Share Access Dialog";
public static Notebook: string = "Notebook";
}
export class HttpHeaders {
public static activityId: string = "x-ms-activity-id";
public static apiType: string = "x-ms-cosmos-apitype";
public static authorization: string = "authorization";
public static collectionIndexTransformationProgress: string =
"x-ms-documentdb-collection-index-transformation-progress";
public static continuation: string = "x-ms-continuation";
public static correlationRequestId: string = "x-ms-correlation-request-id";
public static enableScriptLogging: string = "x-ms-documentdb-script-enable-logging";
public static guestAccessToken: string = "x-ms-encrypted-auth-token";
public static getReadOnlyKey: string = "x-ms-get-read-only-key";
public static connectionString: string = "x-ms-connection-string";
public static msDate: string = "x-ms-date";
public static location: string = "Location";
public static contentType: string = "Content-Type";
public static offerReplacePending: string = "x-ms-offer-replace-pending";
public static user: string = "x-ms-user";
public static populatePartitionStatistics: string = "x-ms-documentdb-populatepartitionstatistics";
public static queryMetrics: string = "x-ms-documentdb-query-metrics";
public static requestCharge: string = "x-ms-request-charge";
public static resourceQuota: string = "x-ms-resource-quota";
public static resourceUsage: string = "x-ms-resource-usage";
public static retryAfterMs: string = "x-ms-retry-after-ms";
public static scriptLogResults: string = "x-ms-documentdb-script-log-results";
public static populateCollectionThroughputInfo = "x-ms-documentdb-populatecollectionthroughputinfo";
public static supportSpatialLegacyCoordinates = "x-ms-documentdb-supportspatiallegacycoordinates";
public static usePolygonsSmallerThanAHemisphere = "x-ms-documentdb-usepolygonssmallerthanahemisphere";
public static autoPilotThroughput = "autoscaleSettings";
public static autoPilotThroughputSDK = "x-ms-cosmos-offer-autopilot-settings";
public static partitionKey: string = "x-ms-documentdb-partitionkey";
public static migrateOfferToManualThroughput: string = "x-ms-cosmos-migrate-offer-to-manual-throughput";
public static migrateOfferToAutopilot: string = "x-ms-cosmos-migrate-offer-to-autopilot";
}
export class ApiType {
// Mapped to hexadecimal values in the backend
public static readonly MongoDB: number = 1;
public static readonly Gremlin: number = 2;
public static readonly Cassandra: number = 4;
public static readonly Table: number = 8;
public static readonly SQL: number = 16;
}
export class HttpStatusCodes {
public static readonly OK: number = 200;
public static readonly Created: number = 201;
public static readonly Accepted: number = 202;
public static readonly NoContent: number = 204;
public static readonly NotModified: number = 304;
public static readonly Unauthorized: number = 401;
public static readonly Forbidden: number = 403;
public static readonly NotFound: number = 404;
public static readonly TooManyRequests: number = 429;
public static readonly Conflict: number = 409;
public static readonly InternalServerError: number = 500;
public static readonly BadGateway: number = 502;
public static readonly ServiceUnavailable: number = 503;
public static readonly GatewayTimeout: number = 504;
public static readonly RetryableStatusCodes: number[] = [
HttpStatusCodes.TooManyRequests,
HttpStatusCodes.InternalServerError, // TODO: Handle all 500s on Portal backend and remove from retries list
HttpStatusCodes.BadGateway,
HttpStatusCodes.ServiceUnavailable,
HttpStatusCodes.GatewayTimeout,
];
}
export class Urls {
public static feedbackEmail = "https://aka.ms/cosmosdbfeedback?subject=Cosmos%20DB%20Data%20Explorer%20Feedback";
public static autoscaleMigration = "https://aka.ms/cosmos-autoscale-migration";
public static freeTierInformation = "https://aka.ms/cosmos-free-tier";
public static cosmosPricing = "https://aka.ms/azure-cosmos-db-pricing";
}
export class HashRoutePrefixes {
public static databases: string = "/dbs/{db_id}";
public static collections: string = "/dbs/{db_id}/colls/{coll_id}";
public static sprocHash: string = "/sprocs/";
public static sprocs: string = HashRoutePrefixes.collections + HashRoutePrefixes.sprocHash + "{sproc_id}";
public static docs: string = HashRoutePrefixes.collections + "/docs/{doc_id}/";
public static conflicts: string = HashRoutePrefixes.collections + "/conflicts";
public static databasesWithId(databaseId: string): string {
return this.databases.replace("{db_id}", databaseId).replace("/", ""); // strip the first slash since hasher adds it
}
public static collectionsWithIds(databaseId: string, collectionId: string): string {
const transformedDatabasePrefix: string = this.collections.replace("{db_id}", databaseId);
return transformedDatabasePrefix.replace("{coll_id}", collectionId).replace("/", ""); // strip the first slash since hasher adds it
}
public static sprocWithIds(
databaseId: string,
collectionId: string,
sprocId: string,
stripFirstSlash: boolean = true
): string {
const transformedDatabasePrefix: string = this.sprocs.replace("{db_id}", databaseId);
const transformedSprocRoute: string = transformedDatabasePrefix
.replace("{coll_id}", collectionId)
.replace("{sproc_id}", sprocId);
if (!!stripFirstSlash) {
return transformedSprocRoute.replace("/", ""); // strip the first slash since hasher adds it
}
return transformedSprocRoute;
}
public static conflictsWithIds(databaseId: string, collectionId: string) {
const transformedDatabasePrefix: string = this.conflicts.replace("{db_id}", databaseId);
return transformedDatabasePrefix.replace("{coll_id}", collectionId).replace("/", ""); // strip the first slash since hasher adds it;
}
public static docsWithIds(databaseId: string, collectionId: string, docId: string) {
const transformedDatabasePrefix: string = this.docs.replace("{db_id}", databaseId);
return transformedDatabasePrefix.replace("{coll_id}", collectionId).replace("{doc_id}", docId).replace("/", ""); // strip the first slash since hasher adds it
}
}
export class ConfigurationOverridesValues {
public static IsBsonSchemaV2: string = "true";
}
export class KeyCodes {
public static Space: number = 32;
public static Enter: number = 13;
public static Escape: number = 27;
public static UpArrow: number = 38;
public static DownArrow: number = 40;
public static LeftArrow: number = 37;
public static RightArrow: number = 39;
public static Tab: number = 9;
}
// Normalized per: https://www.w3.org/TR/uievents-key/#named-key-attribute-values
export class NormalizedEventKey {
public static readonly Space = " ";
public static readonly Enter = "Enter";
public static readonly Escape = "Escape";
public static readonly UpArrow = "ArrowUp";
public static readonly DownArrow = "ArrowDown";
public static readonly LeftArrow = "ArrowLeft";
public static readonly RightArrow = "ArrowRight";
}
export class TryCosmosExperience {
public static extendUrl: string = "https://trycosmosdb.azure.com/api/resource/extendportal?userId={0}";
public static deleteUrl: string = "https://trycosmosdb.azure.com/api/resource/deleteportal?userId={0}";
public static collectionsPerAccount: number = 3;
public static maxRU: number = 5000;
public static defaultRU: number = 3000;
}
export class OfferVersions {
public static V1: string = "V1";
public static V2: string = "V2";
}
export enum ConflictOperationType {
Replace = "replace",
Create = "create",
Delete = "delete",
}
export enum ConnectionStatusType {
Connecting = "Connecting",
Connected = "Connected",
Failed = "Connection Failed",
}
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 = 5000;
public static readonly kernelRestartInitialDelayMs = 1000;
public static readonly kernelRestartMaxDelayMs = 20000;
public static readonly autoSaveIntervalMs = 120000;
public static readonly temporarilyDownMsg = "Notebooks is currently not available. We are working on it.";
public static readonly mongoShellTemporarilyDownMsg =
"We have identified an issue with the Mongo Shell and it is unavailable right now. We are actively working on the mitigation.";
public static readonly cassandraShellTemporarilyDownMsg =
"We have identified an issue with the Cassandra Shell and it is unavailable right now. We are actively working on the mitigation.";
}
export class SparkLibrary {
public static readonly nameMinLength = 3;
public static readonly nameMaxLength = 63;
}
export class AnalyticalStorageTtl {
public static readonly Days90: number = 7776000;
public static readonly Infinite: number = -1;
public static readonly Disabled: number = 0;
}
export class TerminalQueryParams {
public static readonly Terminal = "terminal";
public static readonly Server = "server";
public static readonly Token = "token";
public static readonly SubscriptionId = "subscriptionId";
public static readonly TerminalEndpoint = "terminalEndpoint";
}

View File

@@ -1,3 +0,0 @@
export const Spark = "spark-public-preview";
export const Notebooks = "sparknotebooks-public-preview";
export const StorageAnalytics = "storageanalytics-public-preview";

View File

@@ -1,3 +0,0 @@
export const Days90 = 7776000;
export const Infinite = -1;
export const Disabled = 0;

View File

@@ -1,2 +0,0 @@
export const runtimeProxy = "/api/RuntimeProxy";
export const guestRuntimeProxy = "/api/guest/RuntimeProxy";

View File

@@ -1,6 +0,0 @@
// Mapped to hexadecimal values in the backend
export const MongoDB = 1;
export const Gremlin = 2;
export const Cassandra = 4;
export const Table = 8;
export const SQL = 16;

View File

@@ -1,5 +0,0 @@
export const ResourceTree = "Resource Tree";
export const ContextualPane = "Contextual Pane";
export const Tab = "Tab";
export const ShareDialog = "Share Access Dialog";
export const Notebook = "Notebook";

View File

@@ -1,6 +0,0 @@
export const documentDB = "2015-11-06";
export const arcadia = "2019-06-01-preview";
export const arcadiaLivy = "2019-11-01-preview";
export const arm = "2015-11-01";
export const armFeatures = "2014-08-01-preview";
export const publicVersion = "2020-04-01";

View File

@@ -1,2 +0,0 @@
export const notebookWorkspaces = "Microsoft.DocumentDB/databaseAccounts/notebookWorkspaces";
export const synapseWorkspaces = "Microsoft.Synapse/workspaces";

View File

@@ -1,5 +0,0 @@
export const partitionKeyKind = "Hash";
export const singlePartitionStorageInGb = "10";
export const multiPartitionStorageInGb = "100";
export const maxChangeFeedRetentionDuration = 10;
export const partitionKeyVersion = 2;

View File

@@ -1,8 +0,0 @@
export const EnableTable = "EnableTable";
export const EnableGremlin = "EnableGremlin";
export const EnableCassandra = "EnableCassandra";
export const EnableAutoScale = "EnableAutoScale";
export const EnableNotebooks = "EnableNotebooks";
export const EnableStorageAnalytics = "EnableStorageAnalytics";
export const EnableMongo = "EnableMongo";
export const EnableServerless = "EnableServerless";

View File

@@ -1,9 +0,0 @@
// TODO: 435619 Add default endpoints per cloud and use regional only when available
export const createOrDeleteApi = "api/cassandra/createordelete";
export const guestCreateOrDeleteApi = "api/guest/cassandra/createordelete";
export const queryApi = "api/cassandra";
export const guestQueryApi = "api/guest/cassandra";
export const keysApi = "api/cassandra/keys";
export const guestKeysApi = "api/guest/cassandra/keys";
export const schemaApi = "api/cassandra/schema";
export const guestSchemaApi = "api/guest/cassandra/schema";

View File

@@ -1,9 +0,0 @@
export const requestTimeoutMs = 60000;
export const portalCacheTimeoutMs = 10000;
export const errorNotificationTimeoutMs = 5000;
export const copyHelperTimeoutMs = 2000;
export const waitForDOMElementMs = 500;
export const cacheBustingTimeoutMs = 10 /** minutes **/ * 60 /** to seconds **/ * 1000; /** to milliseconds **/
export const databaseThroughputIncreaseFactor = 100;
export const arcadiaTokenRefreshInterval = 20 /** minutes **/ * 60 /** to seconds **/ * 1000; /** to milliseconds **/
export const arcadiaTokenRefreshIntervalPaddingMs = 2000;

View File

@@ -1,3 +0,0 @@
export const privacyStatement = "https://aka.ms/ms-privacy-policy";
export const codeOfConduct = "https://aka.ms/cosmos-code-of-conduct";
export const termsOfUse = "https://aka.ms/ms-terms-of-use";

View File

@@ -1 +0,0 @@
export const IsBsonSchemaV2 = "true";

View File

@@ -1 +0,0 @@
export const Url = "https://aka.ms/cosmosdbanalytics";

View File

@@ -1,8 +0,0 @@
export const DocumentsPerPage = 100;
export const IndividualRowHeight = 34;
export const BufferHeight = 28;
export const SplitterMinWidth = 200;
export const SplitterMaxWidth = 360;
export const DocumentEditorMinWidthRatio = 0.2;
export const DocumentEditorMaxWidthRatio = 0.4;

View File

@@ -1,8 +0,0 @@
export const cassandra = [
"AccountEndpoint=(.*).cassandra.cosmosdb.azure.com",
"HostName=(.*).cassandra.cosmos.azure.com",
];
export const mongo = "mongodb://.*:(.*)@(.*).documents.azure.com";
export const mongoCompute = "mongodb://.*:(.*)@(.*).mongo.cosmos.azure.com";
export const sql = "AccountEndpoint=https://(.*).documents.azure.com";
export const table = "TableEndpoint=https://(.*).table.cosmosdb.azure.com";

View File

@@ -1,8 +0,0 @@
// flight names returned from the portal are always lowercase
export const SettingsV2 = "settingsv2";
export const MongoIndexEditor = "mongoindexeditor";
export const MongoIndexing = "mongoindexing";
export const AutoscaleTest = "autoscaletest";
export const PartitionKeyTest = "partitionkeytest";
export const PKPartitionKeyTest = "pkpartitionkeytest";
export const Phoenix = "phoenix";

View File

@@ -1,40 +0,0 @@
export const databases = "/dbs/{db_id}";
export const collections = "/dbs/{db_id}/colls/{coll_id}";
export const sprocHash = "/sprocs/";
export const sprocs = collections + sprocHash + "{sproc_id}";
export const docs = collections + "/docs/{doc_id}/";
export const conflicts = collections + "/conflicts";
export const databasesWithId = (databaseId: string) => {
return databases.replace("{db_id}", databaseId).replace("/", ""); // strip the first slash since hasher adds it
};
export const collectionsWithIds = (databaseId: string, collectionId: string) => {
const transformedDatabasePrefix = collections.replace("{db_id}", databaseId);
return transformedDatabasePrefix.replace("{coll_id}", collectionId).replace("/", ""); // strip the first slash since hasher adds it
};
export const sprocWithIds = (databaseId: string, collectionId: string, sprocId: string, stripFirstSlash = true) => {
const transformedDatabasePrefix = sprocs.replace("{db_id}", databaseId);
const transformedSprocRoute = transformedDatabasePrefix
.replace("{coll_id}", collectionId)
.replace("{sproc_id}", sprocId);
if (stripFirstSlash) {
return transformedSprocRoute.replace("/", ""); // strip the first slash since hasher adds it
}
return transformedSprocRoute;
};
export const conflictsWithIds = (databaseId: string, collectionId: string) => {
const transformedDatabasePrefix = conflicts.replace("{db_id}", databaseId);
return transformedDatabasePrefix.replace("{coll_id}", collectionId).replace("/", ""); // strip the first slash since hasher adds it;
};
export const docsWithIds = (databaseId: string, collectionId: string, docId: string): string => {
const transformedDatabasePrefix = docs.replace("{db_id}", databaseId);
return transformedDatabasePrefix.replace("{coll_id}", collectionId).replace("{doc_id}", docId).replace("/", ""); // strip the first slash since hasher adds it
};

View File

@@ -1,30 +0,0 @@
export const activityId = "x-ms-activity-id";
export const apiType = "x-ms-cosmos-apitype";
export const authorization = "authorization";
export const collectionIndexTransformationProgress = "x-ms-documentdb-collection-index-transformation-progress";
export const continuation = "x-ms-continuation";
export const correlationRequestId = "x-ms-correlation-request-id";
export const enableScriptLogging = "x-ms-documentdb-script-enable-logging";
export const guestAccessToken = "x-ms-encrypted-auth-token";
export const getReadOnlyKey = "x-ms-get-read-only-key";
export const connectionString = "x-ms-connection-string";
export const msDate = "x-ms-date";
export const location = "Location";
export const contentType = "Content-Type";
export const offerReplacePending = "x-ms-offer-replace-pending";
export const user = "x-ms-user";
export const populatePartitionStatistics = "x-ms-documentdb-populatepartitionstatistics";
export const queryMetrics = "x-ms-documentdb-query-metrics";
export const requestCharge = "x-ms-request-charge";
export const resourceQuota = "x-ms-resource-quota";
export const resourceUsage = "x-ms-resource-usage";
export const retryAfterMs = "x-ms-retry-after-ms";
export const scriptLogResults = "x-ms-documentdb-script-log-results";
export const populateCollectionThroughputInfo = "x-ms-documentdb-populatecollectionthroughputinfo";
export const supportSpatialLegacyCoordinates = "x-ms-documentdb-supportspatiallegacycoordinates";
export const usePolygonsSmallerThanAHemisphere = "x-ms-documentdb-usepolygonssmallerthanahemisphere";
export const autoPilotThroughput = "autoscaleSettings";
export const autoPilotThroughputSDK = "x-ms-cosmos-offer-autopilot-settings";
export const partitionKey = "x-ms-documentdb-partitionkey";
export const migrateOfferToManualThroughput = "x-ms-cosmos-migrate-offer-to-manual-throughput";
export const migrateOfferToAutopilot = "x-ms-cosmos-migrate-offer-to-autopilot";

View File

@@ -1,23 +0,0 @@
export const OK = 200;
export const Created = 201;
export const Accepted = 202;
export const NoContent = 204;
export const NotModified = 304;
export const Unauthorized = 401;
export const Forbidden = 403;
export const NotFound = 404;
export const TooManyRequests = 429;
export const Conflict = 409;
export const InternalServerError = 500;
export const BadGateway = 502;
export const ServiceUnavailable = 503;
export const GatewayTimeout = 504;
export const RetryableStatusCodes: number[] = [
TooManyRequests,
InternalServerError, // TODO: Handle all 500s on Portal backend and remove from retries list
BadGateway,
ServiceUnavailable,
GatewayTimeout,
];

View File

@@ -1,8 +0,0 @@
export const Space = 32;
export const Enter = 13;
export const Escape = 27;
export const UpArrow = 38;
export const DownArrow = 40;
export const LeftArrow = 37;
export const RightArrow = 39;
export const Tab = 9;

View File

@@ -1,2 +0,0 @@
export const protocol = "https";
export const defaultPort = "10255";

View File

@@ -1,8 +0,0 @@
// Normalized per: https://www.w3.org/TR/uievents-key/#named-key-attribute-values
export const Space = " ";
export const Enter = "Enter";
export const Escape = "Escape";
export const UpArrow = "ArrowUp";
export const DownArrow = "ArrowDown";
export const LeftArrow = "ArrowLeft";
export const RightArrow = "ArrowRight";

View File

@@ -1,27 +0,0 @@
export const defaultBasePath = "./notebooks";
export const heartbeatDelayMs = 60000;
export const kernelRestartInitialDelayMs = 1000;
export const kernelRestartMaxDelayMs = 20000;
export const autoSaveIntervalMs = 120000;
export const memoryGuageToGB = 1048576;
export const temporarilyDownMsg = "Notebooks is currently not available. We are working on it.";
export const mongoShellTemporarilyDownMsg =
"We have identified an issue with the Mongo Shell and it is unavailable right now. We are actively working on the mitigation.";
export const cassandraShellTemporarilyDownMsg =
"We have identified an issue with the Cassandra Shell and it is unavailable right now. We are actively working on the mitigation.";
export const saveNotebookModalTitle = "Save Notebook in temporary workspace";
export const saveNotebookModalContent =
"This notebook will be saved in the temporary workspace and will be removed when the session expires. To save your work permanently, save your notebooks to a GitHub repository or download the notebooks to your local machine before the session ends.";
export const newNotebookModalTitle = "Create Notebook in temporary workspace";
export const newNotebookUploadModalTitle = "Upload Notebook in temporary workspace";
export const newNotebookModalContent1 =
"A temporary workspace will be created to enable you to work with notebooks. When the session expires, any notebooks in the workspace will be removed.";
export const newNotebookModalContent2 =
"To save your work permanently, save your notebooks to a GitHub repository or download the notebooks to your local machine before the session ends. ";
export const galleryNotebookDownloadContent1 =
"To download, run, and make changes to this sample notebook, a temporary workspace will be created. When the session expires, any notebooks in the workspace will be removed.";
export const galleryNotebookDownloadContent2 =
"To save your work permanently, save your notebooks to a GitHub repository or download the Notebooks to your local machine before the session ends. ";
export const cosmosNotebookHomePageUrl = "https://aka.ms/cosmos-notebooks-limits";
export const cosmosNotebookGitDocumentationUrl = "https://aka.ms/cosmos-notebooks-github";
export const learnMore = "Learn more.";

View File

@@ -1,2 +0,0 @@
export const V1 = "V1";
export const V2 = "V2";

View File

@@ -1,8 +0,0 @@
export const CustomPageOption = "custom";
export const UnlimitedPageOption = "unlimited";
export const itemsPerPage = 100;
export const unlimitedItemsPerPage = 100; // TODO: Figure out appropriate value so it works for accounts with a large number of partitions
export const QueryEditorMinHeightRatio = 0.1;
export const QueryEditorMaxHeightRatio = 0.4;
export const DefaultMaxDegreeOfParallelism = 6;

View File

@@ -1,4 +0,0 @@
export const CollectionName = "___Query";
export const DatabaseName = "___Cosmos";
export const OfferThroughput = 400;
export const PartitionKeyProperty = "id";

View File

@@ -1,6 +0,0 @@
export const localhost = "localhost";
export const blackforest = "blackforest";
export const fairfax = "fairfax";
export const mooncake = "mooncake";
export const productionPortal = "prod";
export const dev = "dev";

View File

@@ -1,2 +0,0 @@
export const nameMinLength = 3;
export const nameMaxLength = 63;

View File

@@ -1 +0,0 @@
export const defaultExperience = "defaultExperience";

View File

@@ -1,5 +0,0 @@
export const Terminal = "terminal";
export const Server = "server";
export const Token = "token";
export const SubscriptionId = "subscriptionId";
export const TerminalEndpoint = "terminalEndpoint";

View File

@@ -1,5 +0,0 @@
export const extendUrl = "https://trycosmosdb.azure.com/api/resource/extendportal?userId={0}";
export const deleteUrl = "https://trycosmosdb.azure.com/api/resource/deleteportal?userId={0}";
export const collectionsPerAccount = 3;
export const maxRU = 5000;
export const defaultRU = 3000;

View File

@@ -1,4 +0,0 @@
export const feedbackEmail = "https://aka.ms/cosmosdbfeedback?subject=Cosmos%20DB%20Data%20Explorer%20Feedback";
export const autoscaleMigration = "https://aka.ms/cosmos-autoscale-migration";
export const freeTierInformation = "https://aka.ms/cosmos-free-tier";
export const cosmosPricing = "https://aka.ms/azure-cosmos-db-pricing";

View File

@@ -1,105 +0,0 @@
import * as AfecFeatures from "./AfecFeatures";
import * as AnalyticalStorageTtl from "./AnalyticalStorageTtl";
import * as ApiEndpoints from "./ApiEndpoints";
import * as ApiType from "./ApiType";
import * as Areas from "./Areas";
import * as ArmApiVersions from "./ArmApiVersions";
import * as ArmResourceTypes from "./ArmResourceTypes";
import * as BackendDefaults from "./BackendDefaults";
import * as CapabilityNames from "./CapabilityNames";
import * as CassandraBackend from "./CassandraBackend";
import * as ClientDefaults from "./ClientDefaults";
import * as CodeOfConductEndpoints from "./CodeOfConductEndpoints";
import * as ConfigurationOverridesValues from "./ConfigurationOverridesValues";
import * as CorrelationBackend from "./CorrelationBackend";
import * as DocumentsGridMetrics from "./DocumentsGridMetrics";
import * as EndpointsRegex from "./EndpointsRegex";
import * as Flights from "./Flights";
import * as HashRoutePrefixes from "./HashRoutePrefixes";
import * as HttpHeaders from "./HttpHeaders";
import * as HttpStatusCodes from "./HttpStatusCodes";
import * as KeyCodes from "./KeyCodes";
import * as MongoDBAccounts from "./MongoDBAccounts";
import * as NormalizedEventKey from "./NormalizedEventKey";
import * as Notebook from "./Notebook";
import * as OfferVersions from "./OfferVersions";
import * as Queries from "./Queries";
import * as SavedQueries from "./SavedQueries";
import * as ServerIds from "./ServerIds";
import * as SparkLibrary from "./SparkLibrary";
import * as TagNames from "./TagNames";
import * as TerminalQueryParams from "./TerminalQueryParams";
import * as TryCosmosExperience from "./TryCosmosExperience";
import * as Urls from "./Urls";
const StyleConstants = require("less-vars-loader!../../../less/Common/Constants.less");
export {
StyleConstants,
SparkLibrary,
ConfigurationOverridesValues,
OfferVersions,
AnalyticalStorageTtl,
Notebook,
TryCosmosExperience,
NormalizedEventKey,
KeyCodes,
HashRoutePrefixes,
Urls,
HttpStatusCodes,
ApiType,
HttpHeaders,
Areas,
DocumentsGridMetrics,
SavedQueries,
Queries,
CassandraBackend,
MongoDBAccounts,
TagNames,
AfecFeatures,
Flights,
CorrelationBackend,
CapabilityNames,
ClientDefaults,
BackendDefaults,
ArmResourceTypes,
ArmApiVersions,
TerminalQueryParams,
CodeOfConductEndpoints,
ApiEndpoints,
EndpointsRegex,
ServerIds,
};
export enum ConnectionStatusType {
Connect = "Connect",
Connecting = "Connecting",
Connected = "Connected",
Failed = "Connection Failed",
ReConnect = "Reconnect",
}
export enum ConflictOperationType {
Replace = "replace",
Create = "create",
Delete = "delete",
}
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 enum AccountKind {
DocumentDB = "DocumentDB",
MongoDB = "MongoDB",
Parse = "Parse",
GlobalDocumentDB = "GlobalDocumentDB",
Default = "DocumentDB",
}
export enum MongoBackendEndpointType {
local,
remote,
}

View File

@@ -80,7 +80,8 @@ export function queryDocuments(
};
const endpoint = getFeatureEndpointOrDefault("resourcelist") || "";
const headers: HeadersInit = {
const headers = {
...defaultHeaders,
...authHeaders(),
[CosmosSDKConstants.HttpHeaders.IsQuery]: "true",

View File

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

View File

@@ -8,9 +8,6 @@
.input-type-head-text-field {
width: 100%;
}
.input-query-form {
width: 100%;
}
textarea {
width: 100%;
line-height: 1;

View File

@@ -160,21 +160,18 @@ export class InputTypeaheadComponent extends React.Component<
return (
<div className="input-typeahead-container">
<Stack horizontal>
<form aria-labelledby="input" className="input-query-form">
<TextField
multiline={useTextarea}
rows={1}
id="input"
defaultValue={defaultValue}
ariaLabel="Input query"
placeholder={placeholder}
className="input-type-head-text-field"
value={defaultValue}
onKeyDown={this.onSubmit}
onFocus={() => this.setState({ isSuggestionVisible: true })}
onChange={(_event, newValue?: string) => this.handleChange(newValue)}
/>
</form>
<TextField
multiline={useTextarea}
rows={1}
defaultValue={defaultValue}
ariaLabel="Input query"
placeholder={placeholder}
className="input-type-head-text-field"
value={defaultValue}
onKeyDown={this.onSubmit}
onFocus={() => this.setState({ isSuggestionVisible: true })}
onChange={(_event, newValue?: string) => this.handleChange(newValue)}
/>
{this.props.showCancelButton && (
<IconButton
styles={iconButtonStyles}

View File

@@ -7,22 +7,16 @@ exports[`inputTypeahead renders <input /> 1`] = `
<Stack
horizontal={true}
>
<form
aria-labelledby="input"
className="input-query-form"
>
<StyledTextFieldBase
ariaLabel="Input query"
className="input-type-head-text-field"
id="input"
multiline={false}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder="placeholder"
rows={1}
/>
</form>
<StyledTextFieldBase
ariaLabel="Input query"
className="input-type-head-text-field"
multiline={false}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder="placeholder"
rows={1}
/>
</Stack>
</div>
`;
@@ -34,22 +28,16 @@ exports[`inputTypeahead renders <textarea /> 1`] = `
<Stack
horizontal={true}
>
<form
aria-labelledby="input"
className="input-query-form"
>
<StyledTextFieldBase
ariaLabel="Input query"
className="input-type-head-text-field"
id="input"
multiline={true}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder="placeholder"
rows={1}
/>
</form>
<StyledTextFieldBase
ariaLabel="Input query"
className="input-type-head-text-field"
multiline={true}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder="placeholder"
rows={1}
/>
</Stack>
</div>
`;

View File

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

View File

@@ -65,7 +65,7 @@ export interface PriceBreakdown {
currencySign: string;
}
export const infoAndToolTipTextStyle: ITextStyles = { root: { fontSize: 14, color: "windowtext" } };
export const infoAndToolTipTextStyle: ITextStyles = { root: { fontSize: 14 } };
export const noLeftPaddingCheckBoxStyle: ICheckboxStyles = {
label: {
@@ -272,7 +272,7 @@ export const manualToAutoscaleDisclaimerElement: JSX.Element = (
<Text styles={infoAndToolTipTextStyle} id="manualToAutoscaleDisclaimerElement">
The starting autoscale max RU/s will be determined by the system, based on the current manual throughput settings
and storage of your resource. After autoscale has been enabled, you can change the max RU/s.{" "}
<Link href={Urls.autoscaleMigration}>Learn more</Link>
<a href={Urls.autoscaleMigration}>Learn more</a>
</Text>
);

View File

@@ -8,7 +8,6 @@ exports[`IndexingPolicyRefreshComponent renders 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}

View File

@@ -20,7 +20,6 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -40,7 +39,6 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -75,7 +73,6 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -83,11 +80,11 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
>
The starting autoscale max RU/s will be determined by the system, based on the current manual throughput settings and storage of your resource. After autoscale has been enabled, you can change the max RU/s.
<StyledLinkBase
<a
href="https://aka.ms/cosmos-autoscale-migration"
>
Learn more
</StyledLinkBase>
</a>
</Text>
</StyledMessageBar>
<StyledChoiceGroup
@@ -189,7 +186,6 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -464,7 +460,6 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}

View File

@@ -16,7 +16,6 @@ exports[`ScaleComponent renders with correct initial notification 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}

View File

@@ -136,7 +136,6 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -413,7 +412,6 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -954,7 +952,6 @@ exports[`SubSettingsComponent renders 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -1231,7 +1228,6 @@ exports[`SubSettingsComponent timeToLiveSeconds hidden 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}

View File

@@ -159,7 +159,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -167,17 +166,16 @@ exports[`SettingsUtils functions render 1`] = `
>
The starting autoscale max RU/s will be determined by the system, based on the current manual throughput settings and storage of your resource. After autoscale has been enabled, you can change the max RU/s.
<StyledLinkBase
<a
href="https://aka.ms/cosmos-autoscale-migration"
>
Learn more
</StyledLinkBase>
</a>
</Text>
<Text
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -197,7 +195,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -210,7 +207,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -223,7 +219,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -235,7 +230,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -255,7 +249,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -271,7 +264,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -286,7 +278,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -300,7 +291,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -312,7 +302,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -332,7 +321,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -375,7 +363,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -391,7 +378,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}
@@ -408,7 +394,6 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"color": "windowtext",
"fontSize": 14,
},
}

View File

@@ -1,6 +1,7 @@
@import "../../../../less/Common/Constants";
.tabComponentContainer {
overflow: hidden;
height: 100%;
.flex-display();
.flex-direction();

View File

@@ -243,7 +243,6 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
<div ref={this.contextMenuRef} onContextMenu={this.onRightClick} onKeyPress={this.onMoreButtonKeyPress}>
<IconButton
name="More"
title="More"
className="treeMenuEllipsis"
ariaLabel={menuItemLabel}
menuIconProps={{

View File

@@ -211,7 +211,6 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
},
}
}
title="More"
/>
</div>
</div>
@@ -424,7 +423,6 @@ exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents
},
}
}
title="More"
/>
</div>
</div>

View File

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

View File

@@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { FeedOptions, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
import * as Q from "q";
import * as React from "react";
@@ -296,6 +294,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
this.setGremlinParams();
}
const selectedNode = this.state.highlightedNode;
props.onGraphAccessorCreated({
applyFilter: this.submitQuery.bind(this),
addVertex: this.addVertex.bind(this),
@@ -303,7 +303,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
});
} // constructor
public shareIGraphConfig(igraphConfig: IGraphConfig): void {
public shareIGraphConfig(igraphConfig: IGraphConfig) {
this.setState({
igraphConfig: { ...igraphConfig },
});
@@ -330,10 +330,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
const partitionKeyProperty = this.props.collectionPartitionKeyProperty;
// aggregate all the properties, remove dropped ones
const finalProperties = editedProperties.existingProperties.concat(editedProperties.addedProperties);
let finalProperties = editedProperties.existingProperties.concat(editedProperties.addedProperties);
// Compose the query
const pkId = editedProperties.pkId;
let pkId = editedProperties.pkId;
let updateQueryFragment = "";
finalProperties.forEach((p) => {
@@ -422,7 +422,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
* Called from ko binding
* @param id
*/
public selectNode(id: string): void {
public selectNode(id: string) {
if (!this.d3ForceGraph) {
console.warn("Attempting to select node, but d3ForceGraph not initialized, yet.");
return;
@@ -431,7 +431,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
this.d3ForceGraph.selectNode(id);
}
public deleteHighlightedNode(): void {
public deleteHighlightedNode() {
if (!this.state.highlightedNode) {
GraphExplorer.reportToConsole(ConsoleDataType.Error, "No highlighted node to remove.");
return;
@@ -467,23 +467,23 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
* Is of type: {e: GremlinEdge, v: GremlinVertex}[]
* @param data
*/
public static isEdgeVertexPairArray(data: any): boolean {
public static isEdgeVertexPairArray(data: any) {
if (!(data instanceof Array)) {
GraphExplorer.reportToConsole(ConsoleDataType.Info, "Query result not an array", data);
return false;
}
const pairs: any[] = data;
let pairs: any[] = data;
for (let i = 0; i < pairs.length; i++) {
const item = pairs[i];
if (
!Object.prototype.hasOwnProperty.call(item, "e") ||
!Object.prototype.hasOwnProperty.call(item, "v") ||
!Object.prototype.hasOwnProperty.call(item["e"], "id") ||
!Object.prototype.hasOwnProperty.call(item["e"], "type") ||
!item.hasOwnProperty("e") ||
!item.hasOwnProperty("v") ||
!item["e"].hasOwnProperty("id") ||
!item["e"].hasOwnProperty("type") ||
item["e"].type !== "edge" ||
!Object.prototype.hasOwnProperty.call(item["v"], "id") ||
!Object.prototype.hasOwnProperty.call(item["e"], "type") ||
!item["v"].hasOwnProperty("id") ||
!item["v"].hasOwnProperty("type") ||
item["v"].type !== "vertex"
) {
return false;
@@ -514,7 +514,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
// Try hitting cache first
const cache = outE ? this.outECache : this.inECache;
const pairs = cache.retrieve(vertex.id, startIndex, pageSize);
if (pairs !== null && pairs.length === pageSize) {
if (pairs != null && pairs.length === pageSize) {
const msg = `Retrieved ${pairs.length} ${outE ? "outE" : "inE"} edges from cache for vertex id: ${vertex.id}`;
GraphExplorer.reportToConsole(ConsoleDataType.Info, msg);
return Q.resolve(pairs);
@@ -588,6 +588,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
vertex._outEAllLoaded &&
vertex._inEAllLoaded
) {
console.info("No more edges to load for vertex " + vertex.id);
updateGraphData();
return Q.resolve(graphData);
}
@@ -667,7 +668,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
}
);
return promise.then(() => {
return promise.then((nbPairsFetched: number) => {
if (offsetIndex >= GraphExplorer.LOAD_PAGE_SIZE || !vertex._outEAllLoaded || !vertex._inEAllLoaded) {
vertex._pagination = {
total:
@@ -753,7 +754,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
* Create a new edge in docdb and update graph
* @param e
*/
public createNewEdge(e: GraphNewEdgeData): Q.Promise<unknown> {
public createNewEdge(e: GraphNewEdgeData): Q.Promise<any> {
const q = `g.V('${GraphUtil.escapeSingleQuotes(e.inputOutV)}').addE('${GraphUtil.escapeSingleQuotes(
e.label
)}').To(g.V('${GraphUtil.escapeSingleQuotes(e.inputInV)}'))`;
@@ -771,8 +772,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
return;
}
const edge = edges[0];
const graphData = this.originalGraphData;
let edge = edges[0];
let graphData = this.originalGraphData;
graphData.addEdge(edge);
// Allow loadNeighbors to load list new edge
@@ -799,10 +800,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
* Manually update in-memory graph.
* @param edgeId
*/
public removeEdge(edgeId: string): Q.Promise<unknown> {
public removeEdge(edgeId: string): Q.Promise<any> {
return this.submitToBackend(`g.E('${GraphUtil.escapeSingleQuotes(edgeId)}').drop()`).then(
() => {
const graphData = this.originalGraphData;
let graphData = this.originalGraphData;
graphData.removeEdge(edgeId, false);
this.updateGraphData(graphData, this.state.igraphConfig);
},
@@ -825,14 +826,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
return false;
}
const vertices: any[] = data;
let vertices: any[] = data;
if (vertices.length > 0) {
const v0 = vertices[0];
if (
!Object.prototype.hasOwnProperty.call(v0, "id") ||
!Object.prototype.hasOwnProperty.call(v0, "type") ||
v0.type !== "vertex"
) {
let v0 = vertices[0];
if (!v0.hasOwnProperty("id") || !v0.hasOwnProperty("type") || v0.type !== "vertex") {
return false;
}
}
@@ -840,7 +837,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
}
public processGremlinQueryResults(result: GremlinClient.GremlinRequestResult): void {
const data = result.data as GraphData.GremlinVertex[];
const data = result.data as any;
this.setFilterQueryStatus(FilterQueryStatus.GraphEmptyResult);
if (data === null) {
@@ -930,13 +927,13 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
throw { title: err };
}
if (vertices === null || vertices.length < 1) {
if (vertices == null || vertices.length < 1) {
const err = "Failed to create vertex (no vertex in response)";
GraphExplorer.reportToConsole(ConsoleDataType.Error, err, vertices);
throw { title: err };
}
const vertex = vertices[0];
let vertex = vertices[0];
const graphData = this.originalGraphData;
graphData.addVertex(vertex);
this.updateGraphData(graphData, this.state.igraphConfig);
@@ -1025,7 +1022,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
this.gremlinClient.destroy();
}
public componentDidMount(): void {
if (this.props.onLoadStartKey !== null && this.props.onLoadStartKey !== undefined) {
if (this.props.onLoadStartKey != null && this.props.onLoadStartKey != undefined) {
TelemetryProcessor.traceSuccess(
Action.Tab,
{
@@ -1085,7 +1082,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
public static reportToConsole(type: ConsoleDataType.Info, msg: string, ...errorData: any[]): void;
public static reportToConsole(type: ConsoleDataType.Error, msg: string, ...errorData: any[]): void;
public static reportToConsole(type: ConsoleDataType, msg: string, ...errorData: any[]): void | (() => void) {
let errorDataStr = "";
let errorDataStr: string = "";
if (errorData && errorData.length > 0) {
console.error(msg, errorData);
errorDataStr = ": " + JSON.stringify(errorData);
@@ -1164,15 +1161,12 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
)}"`
).then(
(documents: DataModels.DocumentId[]) => {
$.each(
documents,
(index: number, doc: { _graph_icon_property_value: string; icon: string; format: string }) => {
newIconsMap[doc["_graph_icon_property_value"]] = {
data: doc["icon"],
format: doc["format"],
};
}
);
$.each(documents, (index: number, doc: any) => {
newIconsMap[doc["_graph_icon_property_value"]] = {
data: doc["icon"],
format: doc["format"],
};
});
// Update graph configuration
this.setState({
@@ -1229,8 +1223,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
const key = this.state.igraphConfig.nodeCaption;
return $.map(
this.state.rootMap,
(value: any): LeftPane.CaptionId => {
const result = GraphData.GraphData.getNodePropValue(value, key);
(value: any, index: number): LeftPane.CaptionId => {
let result = GraphData.GraphData.getNodePropValue(value, key);
return {
caption: result !== undefined ? result : value.id,
id: value.id,
@@ -1243,7 +1237,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
* Selecting a root node means
* @param node
*/
private selectRootNode(id: string): Q.Promise<unknown> {
private selectRootNode(id: string): Q.Promise<any> {
if (!this.d3ForceGraph) {
console.warn("Attempting to reset zoom, but d3ForceGraph not initialized, yet.");
} else {
@@ -1288,7 +1282,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
this.collectNodeProperties(this.originalGraphData.vertices);
this.updatePropertiesPane(id);
},
(reason: string) => {
(reason: any) => {
GraphExplorer.reportToConsole(ConsoleDataType.Error, `Failed to select root node. Reason:${reason}`);
}
);
@@ -1355,10 +1349,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
private getPkIdFromVertex(v: GraphData.GremlinVertex): string {
if (
this.props.collectionPartitionKeyProperty &&
Object.prototype.hasOwnProperty.call(v, "properties") &&
Object.prototype.hasOwnProperty.call(v.properties, this.props.collectionPartitionKeyProperty) &&
v.hasOwnProperty("properties") &&
v.properties.hasOwnProperty(this.props.collectionPartitionKeyProperty) &&
v.properties[this.props.collectionPartitionKeyProperty].length > 0 &&
Object.prototype.hasOwnProperty.call(v.properties[this.props.collectionPartitionKeyProperty][0], "value")
v.properties[this.props.collectionPartitionKeyProperty][0].hasOwnProperty("value")
) {
const pk = v.properties[this.props.collectionPartitionKeyProperty][0].value;
return GraphExplorer.generatePkIdPair(pk, v.id);
@@ -1376,8 +1370,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
private getPkIdFromNodeData(v: GraphHighlightedNodeData): string {
if (
this.props.collectionPartitionKeyProperty &&
Object.prototype.hasOwnProperty.call(v, "properties") &&
Object.prototype.hasOwnProperty.call(v.properties, this.props.collectionPartitionKeyProperty)
v.hasOwnProperty("properties") &&
v.properties.hasOwnProperty(this.props.collectionPartitionKeyProperty)
) {
const pk = v.properties[this.props.collectionPartitionKeyProperty];
return GraphExplorer.generatePkIdPair(pk[0] as PartitionKeyValueType, v.id);
@@ -1394,14 +1388,14 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
* @return id
*/
public static getPkIdFromDocumentId(d: DataModels.DocumentId, collectionPartitionKeyProperty: string): string {
const { id } = d;
let { id } = d;
if (typeof id !== "string") {
const error = `Vertex id is not a string: ${JSON.stringify(id)}.`;
logConsoleError(error);
throw new Error(error);
}
if (collectionPartitionKeyProperty && Object.prototype.hasOwnProperty.call(d, collectionPartitionKeyProperty)) {
if (collectionPartitionKeyProperty && d.hasOwnProperty(collectionPartitionKeyProperty)) {
let pk = (d as any)[collectionPartitionKeyProperty];
if (typeof pk !== "string" && typeof pk !== "number" && typeof pk !== "boolean") {
if (Array.isArray(pk) && pk.length > 0) {
@@ -1431,7 +1425,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
}"] AS p FROM c WHERE NOT IS_DEFINED(c._isEdge)`;
return this.executeNonPagedDocDbQuery(q).then(
(documents: DataModels.DocumentId[]) => {
const possibleVertices = [] as PossibleVertex[];
let possibleVertices = [] as PossibleVertex[];
$.each(documents, (index: number, item: any) => {
if (highlightedNodeId && item.id === highlightedNodeId) {
// Exclude highlighed node in the list
@@ -1445,7 +1439,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
caption: item.p,
});
} else {
if (Object.prototype.hasOwnProperty.call(item, "p")) {
if (item.hasOwnProperty("p")) {
possibleVertices.push({
value: item.id,
caption: item.p[0]["_value"],
@@ -1468,17 +1462,17 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
* @param addedEdges
* @return promise when done
*/
private editGraphEdges(editedEdges: EditedEdges): Q.Promise<unknown> {
const promises = [];
private editGraphEdges(editedEdges: EditedEdges): Q.Promise<any> {
let promises = [];
// Drop edges
for (let i = 0; i < editedEdges.droppedIds.length; i++) {
const id = editedEdges.droppedIds[i];
let id = editedEdges.droppedIds[i];
promises.push(this.removeEdge(id));
}
// Add edges
for (let i = 0; i < editedEdges.addedEdges.length; i++) {
const e = editedEdges.addedEdges[i];
let e = editedEdges.addedEdges[i];
promises.push(
this.createNewEdge(e).then(() => {
// Reload neighbors in case we linked to a vertex that isn't loaded in the graph
@@ -1531,9 +1525,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
/**
* For unit testing purposes
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public onGraphUpdated(_timestamp: number): void {}
public onGraphUpdated(timestamp: number): void {}
/**
* Get node properties for styling purposes. Result is the union of all properties of all nodes.
@@ -1541,17 +1533,17 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
private collectNodeProperties(vertices: GraphData.GremlinVertex[]) {
const props = {} as any; // Hashset
$.each(vertices, (index: number, item: GraphData.GremlinVertex) => {
for (const p in item) {
for (var p in item) {
// DocDB: Exclude type because it's always 'vertex'
if (p !== "type" && typeof (item as any)[p] === "string") {
props[p] = true;
}
}
// Inspect properties
if (Object.prototype.hasOwnProperty.call(item, "properties")) {
if (item.hasOwnProperty("properties")) {
// TODO This is DocDB-graph specific
// Assume each property value is [{value:... }]
for (const f in item.properties) {
for (var f in item.properties) {
props[f] = true;
}
}
@@ -1578,21 +1570,21 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
return;
}
const data = this.originalGraphData.getVertexById(id);
let data = this.originalGraphData.getVertexById(id);
// A bit of translation to make it easier to display
const props: { [id: string]: ViewModels.GremlinPropertyValueType[] } = {};
for (const p in data.properties) {
let props: { [id: string]: ViewModels.GremlinPropertyValueType[] } = {};
for (let p in data.properties) {
props[p] = data.properties[p].map((gremlinProperty) => gremlinProperty.value);
}
// update neighbors
const sources: NeighborVertexBasicInfo[] = [];
const targets: NeighborVertexBasicInfo[] = [];
let sources: NeighborVertexBasicInfo[] = [];
let targets: NeighborVertexBasicInfo[] = [];
this.props.onResetDefaultGraphConfigValues();
const nodeCaption = this.state.igraphConfigUiData.nodeCaptionChoice;
let nodeCaption = this.state.igraphConfigUiData.nodeCaptionChoice;
this.updateSelectedNodeNeighbors(data.id, nodeCaption, sources, targets);
const sData: GraphHighlightedNodeData = {
let sData: GraphHighlightedNodeData = {
id: data.id,
label: data.label,
properties: props,
@@ -1619,16 +1611,16 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
targets: NeighborVertexBasicInfo[]
): void {
// update neighbors
const gd = this.originalGraphData;
const v = gd.getVertexById(id);
let gd = this.originalGraphData;
let v = gd.getVertexById(id);
// Clear the array while keeping the references
sources.length = 0;
targets.length = 0;
const possibleEdgeLabels = {} as any; // Collect all edge labels in a hashset
let possibleEdgeLabels = {} as any; // Collect all edge labels in a hashset
for (const p in v.inE) {
for (let p in v.inE) {
possibleEdgeLabels[p] = true;
const edges = v.inE[p];
$.each(edges, (index: number, edge: GraphData.GremlinShortInEdge) => {
@@ -1637,7 +1629,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
// If id not known, it must be an edge node whose neighbor hasn't been loaded into the graph, yet
return;
}
const caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
sources.push({
name: caption,
id: neighborId,
@@ -1647,7 +1639,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
});
}
for (const p in v.outE) {
for (let p in v.outE) {
possibleEdgeLabels[p] = true;
const edges = v.outE[p];
$.each(edges, (index: number, edge: GraphData.GremlinShortOutEdge) => {
@@ -1656,7 +1648,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
// If id not known, it must be an edge node whose neighbor hasn't been loaded into the graph, yet
return;
}
const caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
targets.push({
name: caption,
id: neighborId,
@@ -1668,7 +1660,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
this.setState({
possibleEdgeLabels: Object.keys(possibleEdgeLabels).map(
(value: string): InputTypeaheadComponent.Item => {
(value: string, index: number, array: string[]): InputTypeaheadComponent.Item => {
return { caption: value, value: value };
}
),
@@ -1689,20 +1681,20 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
return;
}
const updatedVertex = vertices[0];
let updatedVertex = vertices[0];
if (this.originalGraphData.hasVertexId(updatedVertex.id)) {
const currentVertex = this.originalGraphData.getVertexById(updatedVertex.id);
let currentVertex = this.originalGraphData.getVertexById(updatedVertex.id);
// Copy updated properties
if (Object.prototype.hasOwnProperty.call(currentVertex, "properties")) {
if (currentVertex.hasOwnProperty("properties")) {
delete currentVertex["properties"];
}
for (const p in updatedVertex) {
for (var p in updatedVertex) {
(currentVertex as any)[p] = updatedVertex[p];
}
}
// TODO This kind of assumes saveVertexProperty is done from property panes.
const hn = this.state.highlightedNode;
let hn = this.state.highlightedNode;
if (hn && hn.id === updatedVertex.id) {
this.updatePropertiesPane(hn.id);
}
@@ -1716,7 +1708,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
igraphConfig?: IGraphConfig
) {
this.originalGraphData = graphData;
const gd = JSON.parse(JSON.stringify(this.originalGraphData));
let gd = JSON.parse(JSON.stringify(this.originalGraphData));
if (!this.d3ForceGraph) {
console.warn("Attempting to update graph, but d3ForceGraph not initialized, yet.");
return;
@@ -1881,7 +1873,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
promise
.then((result: GremlinClient.GremlinRequestResult) => this.processGremlinQueryResults(result))
.catch((error: Error) => {
.catch((error: any) => {
const errorMsg = `Failed to process query result: ${getErrorMessage(error)}`;
GraphExplorer.reportToConsole(ConsoleDataType.Error, errorMsg);
this.setState({

View File

@@ -1,8 +1,8 @@
import * as React from "react";
import { GraphVizComponent, GraphVizComponentProps } from "./GraphVizComponent";
import CollapseArrowIcon from "../../../../images/Collapse_arrow_14x14.svg";
import ExpandIcon from "../../../../images/Expand_14x14.svg";
import LoadingIndicatorIcon from "../../../../images/LoadingIndicator_3Squares.gif";
import { GraphVizComponent, GraphVizComponentProps } from "./GraphVizComponent";
interface MiddlePaneComponentProps {
isTabsContentExpanded: boolean;
@@ -17,14 +17,7 @@ export class MiddlePaneComponent extends React.Component<MiddlePaneComponentProp
<div className="middlePane">
<div className="graphTitle">
<span className="paneTitle">Graph</span>
<span
className="graphExpandCollapseBtn pull-right"
onClick={this.props.toggleExpandGraph}
role="button"
aria-expanded={this.props.isTabsContentExpanded}
aria-name="View graph in full screen"
tabIndex={0}
>
<span className="graphExpandCollapseBtn pull-right" onClick={this.props.toggleExpandGraph}>
<img
src={this.props.isTabsContentExpanded ? CollapseArrowIcon : ExpandIcon}
alt={this.props.isTabsContentExpanded ? "collapse graph content" : "expand graph content"}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -307,18 +307,11 @@ function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonCo
function createNewDatabase(container: Explorer): CommandButtonComponentProps {
const label = "New " + getDatabaseName();
const newDatabaseButton = document.activeElement as HTMLElement;
return {
iconSrc: AddDatabaseIcon,
iconAlt: label,
onCommandClick: () =>
useSidePanel
.getState()
.openSidePanel(
"New " + getDatabaseName(),
<AddDatabasePanel explorer={container} buttonElement={newDatabaseButton} />
),
useSidePanel.getState().openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={container} />),
commandButtonLabel: label,
ariaLabel: label,
hasPopup: true,
@@ -603,7 +596,7 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
return {
iconSrc: GitHubIcon,
iconAlt: label,
onCommandClick: () => {
onCommandClick: () =>
useSidePanel
.getState()
.openSidePanel(
@@ -613,8 +606,7 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
gitHubClientProp={container.notebookManager.gitHubClient}
junoClientProp={junoClient}
/>
);
},
),
commandButtonLabel: label,
hasPopup: false,
disabled: false,

View File

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

View File

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

View File

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

View File

@@ -129,7 +129,7 @@ export class NotificationConsoleComponent extends React.Component<
className="expandCollapseButton"
role="button"
tabIndex={0}
aria-label={"console button" + (this.props.isConsoleExpanded ? " expanded" : " collapsed")}
aria-label={"console button" + (this.props.isConsoleExpanded ? " collapsed" : " expanded")}
aria-expanded={!this.props.isConsoleExpanded}
>
<img
@@ -205,9 +205,7 @@ export class NotificationConsoleComponent extends React.Component<
{item.type === ConsoleDataType.Error && <img className="errorIcon" src={ErrorRedIcon} alt="error" />}
{item.type === ConsoleDataType.InProgress && <img className="loaderIcon" src={LoaderIcon} alt="in progress" />}
<span className="date">{item.date}</span>
<span className="message" role="alert" aria-live="assertive">
{item.message}
</span>
<span className="message">{item.message}</span>
</div>
));
}

View File

@@ -70,7 +70,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
</div>
<div
aria-expanded={true}
aria-label="console button collapsed"
aria-label="console button expanded"
className="expandCollapseButton"
role="button"
tabIndex={0}
@@ -236,7 +236,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
</div>
<div
aria-expanded={true}
aria-label="console button collapsed"
aria-label="console button expanded"
className="expandCollapseButton"
role="button"
tabIndex={0}
@@ -340,9 +340,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
date
</span>
<span
aria-live="assertive"
className="message"
role="alert"
>
message
</span>

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CellId, CellType, ImmutableNotebook } from "@nteract/commutable";
// Vendor modules
import {
@@ -31,19 +30,6 @@ export interface NotebookComponentBootstrapperOptions {
contentRef: ContentRef;
}
interface IWrapModel {
name: string;
path: string;
last_modified: Date;
created: string;
content: unknown;
format: string;
mimetype: unknown;
size: number;
writeable: boolean;
type: string;
}
export class NotebookComponentBootstrapper {
public contentRef: ContentRef;
protected renderExtraComponent: () => JSX.Element;
@@ -55,7 +41,7 @@ export class NotebookComponentBootstrapper {
this.contentRef = options.contentRef;
}
protected static wrapModelIntoContent(name: string, path: string, content: unknown): IWrapModel {
protected static wrapModelIntoContent(name: string, path: string, content: any) {
return {
name,
path,
@@ -63,7 +49,7 @@ export class NotebookComponentBootstrapper {
created: "",
content,
format: "json",
mimetype: undefined,
mimetype: null as any,
size: 0,
writeable: false,
type: "notebook",
@@ -99,7 +85,7 @@ export class NotebookComponentBootstrapper {
};
}
public setContent(name: string, content: unknown): void {
public setContent(name: string, content: any): void {
this.getStore().dispatch(
actions.fetchContentFulfilled({
filepath: undefined,
@@ -284,6 +270,7 @@ export class NotebookComponentBootstrapper {
public isContentDirty(): boolean {
const content = selectors.content(this.getStore().getState(), { contentRef: this.contentRef });
if (!content) {
console.log("No error");
return false;
}

View File

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

View File

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

View File

@@ -16,10 +16,9 @@ import "./NotebookReadOnlyRenderer.less";
import SandboxOutputs from "./outputs/SandboxOutputs";
export interface NotebookRendererProps {
contentRef: ContentRef;
contentRef: any;
hideInputs?: boolean;
hidePrompts?: boolean;
addTransform: (component: React.ComponentType & { MIMETYPE: string }) => void;
}
/**
@@ -28,7 +27,7 @@ export interface NotebookRendererProps {
class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
componentDidMount() {
if (!userContext.features.sandboxNotebookOutputs) {
loadTransform(this.props as NotebookRendererProps);
loadTransform(this.props as any);
}
}
@@ -60,7 +59,7 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
<div className="NotebookReadOnlyRender">
<Cells contentRef={this.props.contentRef}>
{{
code: ({ id, contentRef }: { id: string; contentRef: ContentRef }) => (
code: ({ id, contentRef }: { id: any; contentRef: ContentRef }) => (
<CodeCell id={id} contentRef={contentRef}>
{{
prompt: (props: { id: string; contentRef: string }) => this.renderPrompt(props.id, props.contentRef),
@@ -74,14 +73,14 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
}}
</CodeCell>
),
markdown: ({ id, contentRef }: { id: string; contentRef: ContentRef }) => (
markdown: ({ id, contentRef }: { id: any; contentRef: ContentRef }) => (
<MarkdownCell id={id} contentRef={contentRef} cell_type="markdown">
{{
editor: {},
}}
</MarkdownCell>
),
raw: ({ id, contentRef }: { id: string; contentRef: ContentRef }) => (
raw: ({ id, contentRef }: { id: any; contentRef: ContentRef }) => (
<RawCell id={id} contentRef={contentRef} cell_type="raw">
{{
editor: {
@@ -99,7 +98,6 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const makeMapDispatchToProps = (initialDispatch: Dispatch, initialProps: NotebookRendererProps) => {
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
@@ -116,4 +114,4 @@ const makeMapDispatchToProps = (initialDispatch: Dispatch, initialProps: Noteboo
return mapDispatchToProps;
};
export default connect(undefined, makeMapDispatchToProps)(NotebookReadOnlyRenderer);
export default connect(null, makeMapDispatchToProps)(NotebookReadOnlyRenderer);

View File

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

View File

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

View File

@@ -1,9 +1,11 @@
import {
ActionButton,
Checkbox,
ChoiceGroup,
DefaultButton,
DirectionalHint,
Dropdown,
IChoiceGroupOption,
Icon,
IconButton,
IDropdownOption,
@@ -13,21 +15,21 @@ import {
Text,
TooltipHost,
} from "@fluentui/react";
import * as Constants from "Common/Constants";
import { createCollection } from "Common/dataAccess/createCollection";
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import { configContext, Platform } from "ConfigContext";
import * as DataModels from "Contracts/DataModels";
import { SubscriptionType } from "Contracts/SubscriptionType";
import { useSidePanel } from "hooks/useSidePanel";
import React from "react";
import { CollectionCreation } from "Shared/Constants";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
import { getCollectionName } from "Utils/APITypeUtils";
import { isCapabilityEnabled, isServerlessAccount } from "Utils/CapabilityUtils";
import { getUpsellMessage } from "Utils/PricingUtils";
import * as Constants from "../../Common/Constants";
import { createCollection } from "../../Common/dataAccess/createCollection";
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
import { configContext, Platform } from "../../ConfigContext";
import * as DataModels from "../../Contracts/DataModels";
import { SubscriptionType } from "../../Contracts/SubscriptionType";
import { useSidePanel } from "../../hooks/useSidePanel";
import { CollectionCreation } from "../../Shared/Constants";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import { getCollectionName } from "../../Utils/APITypeUtils";
import { isCapabilityEnabled, isServerlessAccount } from "../../Utils/CapabilityUtils";
import { getUpsellMessage } from "../../Utils/PricingUtils";
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
import Explorer from "../Explorer";
@@ -125,6 +127,26 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
};
}
choiceButtonStyles = {
flexContainer: [
{
selectors: {
".ms-ChoiceField-wrapper label": {
fontSize: 12,
paddingTop: 0,
},
".ms-ChoiceField": {
marginTop: 0,
},
},
},
],
};
collectionOptions: IChoiceGroupOption[] = [
{ key: "create", text: "Create new database" },
{ key: "existing", text: "Use existing database" },
];
render(): JSX.Element {
const isFirstResourceCreated = useDatabases.getState().isFirstResourceCreated();
@@ -152,7 +174,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
<Stack hidden={userContext.apiType === "Tables"}>
<Stack horizontal>
<span className="mandatoryStar">*&nbsp;</span>
<Text className="panelTextBold" variant="small">
<Text id="databaseId" className="panelTextBold" variant="small">
Database {userContext.apiType === "Mongo" ? "name" : "id"}
</Text>
<TooltipHost
@@ -166,32 +188,15 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
</Stack>
<Stack horizontal verticalAlign="center">
<input
className="panelRadioBtn"
checked={this.state.createNewDatabase}
aria-label="Create new database"
aria-checked={this.state.createNewDatabase}
name="databaseType"
type="radio"
role="radio"
id="databaseCreateNew"
tabIndex={0}
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
<ChoiceGroup
aria-labelledby="databaseId"
styles={this.choiceButtonStyles}
options={this.collectionOptions}
defaultSelectedKey={this.collectionOptions[0].key}
onChange={(_: React.ChangeEvent<HTMLInputElement>, options: IChoiceGroupOption) =>
this.handleOnChangeMode(_, options.key.toString())
}
/>
<span className="panelRadioBtnLabel">Create new</span>
<input
className="panelRadioBtn"
checked={!this.state.createNewDatabase}
aria-label="Use existing database"
aria-checked={!this.state.createNewDatabase}
name="databaseType"
type="radio"
role="radio"
tabIndex={0}
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
/>
<span className="panelRadioBtnLabel">Use existing</span>
</Stack>
{this.state.createNewDatabase && (
@@ -209,7 +214,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
size={40}
className="panelTextField"
aria-label="New database id"
autoFocus
tabIndex={0}
value={this.state.newDatabaseId}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
@@ -707,6 +711,14 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
}
}
private handleOnChangeMode = (event: React.ChangeEvent<HTMLInputElement>, mode: string): void => {
if (mode === "create") {
this.onCreateNewDatabaseRadioBtnChange(event);
} else {
this.onUseExistingDatabaseRadioBtnChange(event);
}
};
private onCreateNewDatabaseRadioBtnChange(event: React.ChangeEvent<HTMLInputElement>): void {
if (event.target.checked && !this.state.createNewDatabase) {
this.setState({
@@ -999,7 +1011,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
const collectionId: string = this.state.collectionId.trim();
let databaseId = this.state.createNewDatabase ? this.state.newDatabaseId.trim() : this.state.selectedDatabaseId;
let partitionKeyString = this.state.isSharded ? this.state.partitionKey.trim() : undefined;
let partitionKeyString = this.state.partitionKey.trim();
if (userContext.apiType === "Tables") {
// Table require fixed Database: TablesDB, and fixed Partition Key: /'$pk'

View File

@@ -23,12 +23,10 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
export interface AddDatabasePaneProps {
explorer: Explorer;
buttonElement?: HTMLElement;
}
export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
explorer: container,
buttonElement,
}: AddDatabasePaneProps) => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
let throughput: number;
@@ -79,7 +77,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
dataExplorerArea: Constants.Areas.ContextualPane,
};
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
buttonElement.focus();
}, []);
const onSubmit = () => {

View File

@@ -1,14 +1,14 @@
import { Checkbox, Dropdown, IDropdownOption, Link, Stack, Text, TextField } from "@fluentui/react";
import * as Constants from "Common/Constants";
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
import { useSidePanel } from "hooks/useSidePanel";
import React, { FunctionComponent, useState } from "react";
import * as SharedConstants from "Shared/Constants";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
import { isServerlessAccount } from "Utils/CapabilityUtils";
import * as Constants from "../../../Common/Constants";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
import { useSidePanel } from "../../../hooks/useSidePanel";
import * as SharedConstants from "../../../Shared/Constants";
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext";
import { isServerlessAccount } from "../../../Utils/CapabilityUtils";
import { ThroughputInput } from "../../Controls/ThroughputInput/ThroughputInput";
import Explorer from "../../Explorer";
import { CassandraAPIDataClient } from "../../Tables/TableDataClient";
@@ -198,7 +198,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
<Stack className="panelGroupSpacing">
<TextField
aria-required="true"
required={true}
autoComplete="off"
styles={getTextFieldStyles()}
pattern="[^/?#\\]*[^/?# \\]"
@@ -286,7 +285,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
underlined
styles={getTextFieldStyles({ fontSize: 12, width: 150 })}
aria-required="true"
required={true}
ariaLabel="addCollection-tableId"
autoComplete="off"
pattern="[^/?#\\]*[^/?# \\]"

View File

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

View File

@@ -1,18 +1,18 @@
import { Text, TextField } from "@fluentui/react";
import { Areas } from "Common/Constants";
import { deleteCollection } from "Common/dataAccess/deleteCollection";
import DeleteFeedback from "Common/DeleteFeedback";
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import { Collection } from "Contracts/ViewModels";
import { useSidePanel } from "hooks/useSidePanel";
import { useTabs } from "hooks/useTabs";
import React, { FunctionComponent, useState } from "react";
import { DefaultExperienceUtility } from "Shared/DefaultExperienceUtility";
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
import { getCollectionName } from "Utils/APITypeUtils";
import * as NotificationConsoleUtils from "Utils/NotificationConsoleUtils";
import { Areas } from "../../../Common/Constants";
import { deleteCollection } from "../../../Common/dataAccess/deleteCollection";
import DeleteFeedback from "../../../Common/DeleteFeedback";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import { Collection } from "../../../Contracts/ViewModels";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { useTabs } from "../../../hooks/useTabs";
import { DefaultExperienceUtility } from "../../../Shared/DefaultExperienceUtility";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext";
import { getCollectionName } from "../../../Utils/APITypeUtils";
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
import { useDatabases } from "../../useDatabases";
import { useSelectedNode } from "../../useSelectedNode";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";

View File

@@ -1,18 +1,18 @@
import { Text, TextField } from "@fluentui/react";
import { useBoolean } from "@fluentui/react-hooks";
import { Areas } from "Common/Constants";
import { deleteDatabase } from "Common/dataAccess/deleteDatabase";
import DeleteFeedback from "Common/DeleteFeedback";
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import { Collection, Database } from "Contracts/ViewModels";
import { useSidePanel } from "hooks/useSidePanel";
import { useTabs } from "hooks/useTabs";
import React, { FunctionComponent, useState } from "react";
import { DefaultExperienceUtility } from "Shared/DefaultExperienceUtility";
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
import { logConsoleError } from "Utils/NotificationConsoleUtils";
import { Areas } from "../../Common/Constants";
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
import DeleteFeedback from "../../Common/DeleteFeedback";
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
import { Collection, Database } from "../../Contracts/ViewModels";
import { useSidePanel } from "../../hooks/useSidePanel";
import { useTabs } from "../../hooks/useTabs";
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import { logConsoleError } from "../../Utils/NotificationConsoleUtils";
import { useDatabases } from "../useDatabases";
import { useSelectedNode } from "../useSelectedNode";
import { PanelInfoErrorComponent, PanelInfoErrorProps } from "./PanelInfoErrorComponent";

View File

@@ -9,7 +9,6 @@
flex-grow: 1;
padding: 0 34px;
margin: 20px 0;
overflow-x: hidden;
& > :not(.collapsibleSection) {
margin-bottom: @DefaultSpace;

View File

@@ -33,13 +33,7 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
<Stack className="panelInfoErrorContainer" horizontal verticalAlign="center">
{icon}
<span className="panelWarningErrorDetailsLinkContainer">
<Text
role="alert"
aria-live="assertive"
aria-label={message}
className="panelWarningErrorMessage"
variant="small"
>
<Text className="panelWarningErrorMessage" variant="small" aria-label="message">
{message}
{link && linkText && (
<Link target="_blank" href={link}>

View File

@@ -34,6 +34,6 @@ describe("Right Pane Form", () => {
it("should render error in header", () => {
render(<RightPaneForm {...props} formError="file already Exist" />);
expect(screen.getByLabelText("error")).toBeDefined();
expect(screen.getByRole("alert").innerHTML).toEqual("file already Exist");
expect(screen.getByLabelText("message").innerHTML).toEqual("file already Exist");
});
});

View File

@@ -1,13 +1,13 @@
import { Checkbox, ChoiceGroup, IChoiceGroupOption, SpinButton } from "@fluentui/react";
import * as Constants from "Common/Constants";
import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
import { configContext } from "ConfigContext";
import { useSidePanel } from "hooks/useSidePanel";
import React, { FunctionComponent, MouseEvent, useState } from "react";
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
import * as StringUtility from "Shared/StringUtility";
import { userContext } from "UserContext";
import { logConsoleInfo } from "Utils/NotificationConsoleUtils";
import * as Constants from "../../../Common/Constants";
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
import { configContext } from "../../../ConfigContext";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { LocalStorageUtility, StorageKey } from "../../../Shared/StorageUtility";
import * as StringUtility from "../../../Shared/StringUtility";
import { userContext } from "../../../UserContext";
import { logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
export const SettingsPane: FunctionComponent = () => {

View File

@@ -1,8 +1,8 @@
import { TextField } from "@fluentui/react";
import * as ViewModels from "Contracts/ViewModels";
import { useTabs } from "hooks/useTabs";
import React, { FormEvent, FunctionComponent, useState } from "react";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "Utils/NotificationConsoleUtils";
import * as ViewModels from "../../../Contracts/ViewModels";
import { useTabs } from "../../../hooks/useTabs";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
import * as FileSystemUtil from "../../Notebook/FileSystemUtil";
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
import NotebookV2Tab from "../../Tabs/NotebookV2Tab";

View File

@@ -29,7 +29,6 @@ describe("Table query select Panel", () => {
it("Should checked availableCheckbox by default", () => {
const wrapper = mount(<TableQuerySelectPanel {...props} />);
expect(wrapper.find("#availableCheckbox").first().props()).toEqual({
ariaPositionInSet: 0,
id: "availableCheckbox",
label: "Available Columns",
checked: true,

View File

@@ -128,9 +128,8 @@ export const TableQuerySelectPanel: FunctionComponent<TableQuerySelectPanelProps
label="Available Columns"
checked={isAvailableColumnChecked}
onChange={availableColumnsCheckboxClick}
ariaPositionInSet={0}
/>
{columnOptions.map((column, index) => {
{columnOptions.map((column) => {
return (
<Checkbox
label={column.columnName}
@@ -138,7 +137,6 @@ export const TableQuerySelectPanel: FunctionComponent<TableQuerySelectPanelProps
key={column.columnName}
checked={column.selected}
disabled={!column.editable}
ariaPositionInSet={index + 1}
/>
);
})}

View File

@@ -37,14 +37,12 @@ exports[`Table query select Panel should render Default properly 1`] = `
className="column-select-view"
>
<StyledCheckboxBase
ariaPositionInSet={0}
checked={true}
id="availableCheckbox"
label="Available Columns"
onChange={[Function]}
>
<CheckboxBase
ariaPositionInSet={0}
checked={true}
id="availableCheckbox"
label="Available Columns"
@@ -330,7 +328,6 @@ exports[`Table query select Panel should render Default properly 1`] = `
<input
aria-checked="true"
aria-label="Available Columns"
aria-posinset={0}
checked={true}
className="input-55"
data-ktp-execute-target={true}
@@ -649,7 +646,6 @@ exports[`Table query select Panel should render Default properly 1`] = `
</CheckboxBase>
</StyledCheckboxBase>
<StyledCheckboxBase
ariaPositionInSet={1}
checked={true}
disabled={false}
key=""
@@ -657,7 +653,6 @@ exports[`Table query select Panel should render Default properly 1`] = `
onChange={[Function]}
>
<CheckboxBase
ariaPositionInSet={1}
checked={true}
disabled={false}
label=""
@@ -944,7 +939,6 @@ exports[`Table query select Panel should render Default properly 1`] = `
aria-checked="true"
aria-disabled={false}
aria-label=""
aria-posinset={1}
checked={true}
className="input-55"
data-ktp-execute-target={true}

View File

@@ -1,7 +1,7 @@
import { Upload } from "Common/Upload/Upload";
import { useSidePanel } from "hooks/useSidePanel";
import React, { ChangeEvent, FunctionComponent, useState } from "react";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "Utils/NotificationConsoleUtils";
import { Upload } from "../../../Common/Upload/Upload";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";

View File

@@ -1,8 +1,8 @@
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } 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 { Upload } from "../../../Common/Upload/Upload";
import { UploadDetailsRecord } from "../../../Contracts/ViewModels";
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
import { getErrorMessage } from "../../Tables/Utilities";
import { useSelectedNode } from "../../useSelectedNode";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";

View File

@@ -327,17 +327,13 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
key=".0:$.1"
>
<Text
aria-label="Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources."
aria-live="assertive"
aria-label="message"
className="panelWarningErrorMessage"
role="alert"
variant="small"
>
<span
aria-label="Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources."
aria-live="assertive"
aria-label="message"
className="panelWarningErrorMessage css-56"
role="alert"
>
Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources.
</span>

View File

@@ -307,23 +307,16 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
iconSrc: AddDatabaseIcon,
title: "New " + getDatabaseName(),
description: undefined,
onClick: () => this.openAddDatabasePanel(),
onClick: () =>
useSidePanel
.getState()
.openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={this.container} />),
});
}
return items;
}
private openAddDatabasePanel() {
const newDatabaseButton = document.activeElement as HTMLElement;
useSidePanel
.getState()
.openSidePanel(
"New " + getDatabaseName(),
<AddDatabasePanel explorer={this.container} buttonElement={newDatabaseButton} />
);
}
private decorateOpenCollectionActivity({ databaseId, collectionId }: MostRecentActivity.OpenCollectionItem) {
return {
iconSrc: NotebookIcon,

View File

@@ -1,11 +1,12 @@
import Q from "q";
import _ from "underscore";
import * as QueryBuilderConstants from "../Constants";
import Q from "q";
import * as Entities from "../Entities";
import * as QueryBuilderConstants from "../Constants";
import * as Utilities from "../Utilities";
export function getRowSelector(selectorSchema: Entities.IProperty[]): string {
let selector = "";
var selector: string = "";
selectorSchema &&
selectorSchema.forEach((p: Entities.IProperty) => {
selector += "[" + p.key + '="' + Utilities.jQuerySelectorEscape(p.value) + '"]';
@@ -14,10 +15,10 @@ export function getRowSelector(selectorSchema: Entities.IProperty[]): string {
}
export function isRowVisible(dataTableScrollBodyQuery: JQuery, element: HTMLElement): boolean {
let isVisible = false;
var isVisible = false;
if (dataTableScrollBodyQuery.length && element) {
const elementRect: ClientRect = element.getBoundingClientRect(),
var elementRect: ClientRect = element.getBoundingClientRect(),
dataTableScrollBodyRect: ClientRect = dataTableScrollBodyQuery.get(0).getBoundingClientRect();
isVisible = elementRect.bottom <= dataTableScrollBodyRect.bottom && dataTableScrollBodyRect.top <= elementRect.top;
@@ -28,17 +29,17 @@ export function isRowVisible(dataTableScrollBodyQuery: JQuery, element: HTMLElem
export function scrollToRowIfNeeded(dataTableRows: JQuery, currentIndex: number, isScrollUp: boolean): void {
if (dataTableRows.length) {
const dataTableScrollBodyQuery: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableScrollBodySelector),
var dataTableScrollBodyQuery: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableScrollBodySelector),
selectedRowElement: HTMLElement = dataTableRows.get(currentIndex);
if (dataTableScrollBodyQuery.length && selectedRowElement) {
const isVisible: boolean = isRowVisible(dataTableScrollBodyQuery, selectedRowElement);
var isVisible: boolean = isRowVisible(dataTableScrollBodyQuery, selectedRowElement);
if (!isVisible) {
const selectedRowQuery: JQuery = $(selectedRowElement),
var selectedRowQuery: JQuery = $(selectedRowElement),
scrollPosition: number = dataTableScrollBodyQuery.scrollTop(),
selectedElementPosition: number = selectedRowQuery.position().top;
let newScrollPosition = 0;
selectedElementPosition: number = selectedRowQuery.position().top,
newScrollPosition: number = 0;
if (isScrollUp) {
newScrollPosition = scrollPosition + selectedElementPosition;
@@ -54,7 +55,7 @@ export function scrollToRowIfNeeded(dataTableRows: JQuery, currentIndex: number,
}
export function scrollToTopIfNeeded(): void {
const $dataTableRows: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableAllRowsSelector),
var $dataTableRows: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableAllRowsSelector),
$dataTableScrollBody: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableScrollBodySelector);
if ($dataTableRows.length && $dataTableScrollBody.length) {
@@ -87,14 +88,13 @@ export function reorderColumns(
table: DataTables.DataTable,
targetOrder: number[],
currentOrder?: number[]
//eslint-disable-next-line
): Q.Promise<any> {
const columnsCount: number = targetOrder.length;
const isCurrentOrderPassedIn = !!currentOrder;
var columnsCount: number = targetOrder.length;
var isCurrentOrderPassedIn: boolean = !!currentOrder;
if (!isCurrentOrderPassedIn) {
currentOrder = getInitialOrder(columnsCount);
}
const isSameOrder: boolean = Utilities.isEqual(currentOrder, targetOrder);
var isSameOrder: boolean = Utilities.isEqual(currentOrder, targetOrder);
// if the targetOrder is the same as current order, do nothing.
if (!isSameOrder) {
@@ -104,7 +104,7 @@ export function reorderColumns(
// Then the transformation order will be the same as target order.
// If current order is specified, then a transformation order is calculated.
// Refer to calculateTransformationOrder for details about transformation order.
const transformationOrder: number[] = isCurrentOrderPassedIn
var transformationOrder: number[] = isCurrentOrderPassedIn
? calculateTransformationOrder(currentOrder, targetOrder)
: targetOrder;
try {
@@ -143,7 +143,7 @@ export function getCurrentOrder(table: DataTables.DataTable): number[] {
* Result: [0, 1, 2, 5, 6, 7, 3, 4, 8]
*/
export function invertIndexValues(inputArray: number[]): number[] {
const invertedArray: number[] = [];
var invertedArray: number[] = [];
if (inputArray) {
inputArray.forEach((value: number, index: number) => {
invertedArray[inputArray[index]] = index;
@@ -170,21 +170,20 @@ export function invertIndexValues(inputArray: number[]): number[] {
* transformation order: Trans = [0, 1, 2, 7, 3, 4, 8, 5, 6]
*/
export function calculateTransformationOrder(currentOrder: number[], targetOrder: number[]): number[] {
let transformationOrder: number[] = [];
var transformationOrder: number[] = [];
if (currentOrder && targetOrder && currentOrder.length === targetOrder.length) {
const invertedCurrentOrder: number[] = invertIndexValues(currentOrder);
var invertedCurrentOrder: number[] = invertIndexValues(currentOrder);
transformationOrder = targetOrder.map((value: number) => invertedCurrentOrder[value]);
}
return transformationOrder;
}
export function getDataTableHeaders(table: DataTables.DataTable): string[] {
const columns: DataTables.ColumnsMethods = table.columns();
let headers: string[] = [];
var columns: DataTables.ColumnsMethods = table.columns();
var headers: string[] = [];
if (columns) {
// table.columns() return ColumnsMethods which is an array of arrays
//eslint-disable-next-line
const columnIndexes: number[] = (<any>columns)[0];
var columnIndexes: number[] = (<any>columns)[0];
if (columnIndexes) {
headers = columnIndexes.map((value: number) => $(table.columns(value).header()).html());
}

View File

@@ -8,11 +8,11 @@ import TableEntityListViewModel from "./TableEntityListViewModel";
export default class TableCommands {
// Command Ids
public static editEntityCommand = "edit";
public static deleteEntitiesCommand = "delete";
public static reorderColumnsCommand = "reorder";
public static resetColumnsCommand = "reset";
public static customizeColumnsCommand = "customizeColumns";
public static editEntityCommand: string = "edit";
public static deleteEntitiesCommand: string = "delete";
public static reorderColumnsCommand: string = "reorder";
public static resetColumnsCommand: string = "reset";
public static customizeColumnsCommand: string = "customizeColumns";
private _container: Explorer;
@@ -21,8 +21,8 @@ export default class TableCommands {
}
public isEnabled(commandName: string, selectedEntites: Entities.ITableEntity[]): boolean {
const singleItemSelected = DataTableUtilities.containSingleItem(selectedEntites);
const atLeastOneItemSelected = DataTableUtilities.containItems(selectedEntites);
var singleItemSelected: boolean = DataTableUtilities.containSingleItem(selectedEntites);
var atLeastOneItemSelected: boolean = DataTableUtilities.containItems(selectedEntites);
switch (commandName) {
case TableCommands.editEntityCommand:
return singleItemSelected;
@@ -47,7 +47,6 @@ export default class TableCommands {
/**
* Edit entity
*/
//eslint-disable-next-line
public editEntityCommand(viewModel: TableEntityListViewModel): Q.Promise<any> {
if (!viewModel) {
return null; // Error
@@ -57,9 +56,12 @@ export default class TableCommands {
return null; // Erorr
}
var entityToUpdate: Entities.ITableEntity = viewModel.selected()[0];
var originalNumberOfProperties = entityToUpdate ? 0 : Object.keys(entityToUpdate).length - 1; // .metadata is always a property for etag
return null;
}
//eslint-disable-next-line
public deleteEntitiesCommand(viewModel: TableEntityListViewModel): Q.Promise<any> {
if (!viewModel) {
return null; // Error
@@ -67,7 +69,7 @@ export default class TableCommands {
if (!DataTableUtilities.containItems(viewModel.selected())) {
return null; // Error
}
const entitiesToDelete: Entities.ITableEntity[] = viewModel.selected();
var entitiesToDelete: Entities.ITableEntity[] = viewModel.selected();
const deleteMessage: string =
userContext.apiType === "Cassandra"
? "Are you sure you want to delete the selected rows?"
@@ -80,7 +82,7 @@ export default class TableCommands {
() => {
viewModel.queryTablesTab.container.tableDataClient
.deleteDocuments(viewModel.queryTablesTab.collection, entitiesToDelete)
.then(() => {
.then((results: any) => {
return viewModel.removeEntitiesFromCache(entitiesToDelete).then(() => {
viewModel.redrawTableThrottled();
});

View File

@@ -1,5 +1,5 @@
import * as Entities from "../Entities";
import * as Utilities from "../Utilities";
import * as Entities from "../Entities";
import CacheBase from "./CacheBase";
export default class TableEntityCache extends CacheBase<Entities.ITableEntity> {
@@ -21,7 +21,7 @@ export default class TableEntityCache extends CacheBase<Entities.ITableEntity> {
this._tableQuery = Utilities.copyTableQuery(tableQuery);
}
public preClear(): void {
public preClear() {
this.tableQuery = null;
}
}

View File

@@ -1,4 +1,4 @@
import { ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
import { QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
export interface ITableEntity {
[property: string]: ITableEntityAttribute;
@@ -17,7 +17,6 @@ export interface ITableEntityAttribute {
export interface IListTableEntitiesResult {
Results: ITableEntity[];
//eslint-disable-next-line
ContinuationToken: any;
iterator?: QueryIterator<ItemDefinition & Resource>;
}

View File

@@ -1,9 +1,8 @@
import * as Utilities from "../Utilities";
import QueryClauseViewModel from "./QueryClauseViewModel";
import * as Utilities from "../Utilities";
export default class ClauseGroup {
public isRootGroup: boolean;
//eslint-disable-next-line
public children = new Array();
public parentGroup: ClauseGroup;
private _id: string;
@@ -18,7 +17,7 @@ export default class ClauseGroup {
* Flattens the clause tree into an array, depth-first, left to right.
*/
public flattenClauses(targetArray: ko.ObservableArray<QueryClauseViewModel>): void {
const tempArray = new Array<QueryClauseViewModel>();
var tempArray = new Array<QueryClauseViewModel>();
this.flattenClausesImpl(this, tempArray);
targetArray.removeAll();
@@ -32,10 +31,10 @@ export default class ClauseGroup {
newClause.clauseGroup = this;
this.children.push(newClause);
} else {
const targetGroup = insertBefore.clauseGroup;
var targetGroup = insertBefore.clauseGroup;
if (targetGroup) {
const insertBeforeIndex = targetGroup.children.indexOf(insertBefore);
var insertBeforeIndex = targetGroup.children.indexOf(insertBefore);
newClause.clauseGroup = targetGroup;
targetGroup.children.splice(insertBeforeIndex, 0, newClause);
}
@@ -43,19 +42,19 @@ export default class ClauseGroup {
}
public deleteClause(clause: QueryClauseViewModel): void {
const targetGroup = clause.clauseGroup;
var targetGroup = clause.clauseGroup;
if (targetGroup) {
const index = targetGroup.children.indexOf(clause);
var index = targetGroup.children.indexOf(clause);
targetGroup.children.splice(index, 1);
clause.dispose();
if (targetGroup.children.length <= 1 && !targetGroup.isRootGroup) {
const parent = targetGroup.parentGroup;
const targetGroupIndex = parent.children.indexOf(targetGroup);
var parent = targetGroup.parentGroup;
var targetGroupIndex = parent.children.indexOf(targetGroup);
if (targetGroup.children.length === 1) {
const orphan = targetGroup.children.shift();
var orphan = targetGroup.children.shift();
if (orphan instanceof QueryClauseViewModel) {
(<QueryClauseViewModel>orphan).clauseGroup = parent;
@@ -72,14 +71,14 @@ export default class ClauseGroup {
}
public removeAll(): void {
const allClauses: QueryClauseViewModel[] = new Array<QueryClauseViewModel>();
var allClauses: QueryClauseViewModel[] = new Array<QueryClauseViewModel>();
this.flattenClausesImpl(this, allClauses);
while (allClauses.length > 0) {
allClauses.shift().dispose();
}
//eslint-disable-next-line
this.children = new Array<any>();
}
@@ -88,12 +87,12 @@ export default class ClauseGroup {
*/
public groupSelectedItems(): boolean {
// Find the selection start & end, also check for gaps between selected items (if found, cannot proceed).
const selection = this.getCheckedItemsInfo();
var selection = this.getCheckedItemsInfo();
if (selection.canGroup) {
const newGroup = new ClauseGroup(false, this);
var newGroup = new ClauseGroup(false, this);
// Replace the selected items with the new group, and then move the selected items into the new group.
const groupedItems = this.children.splice(selection.begin, selection.end - selection.begin + 1, newGroup);
var groupedItems = this.children.splice(selection.begin, selection.end - selection.begin + 1, newGroup);
groupedItems &&
groupedItems.forEach((element) => {
@@ -119,13 +118,13 @@ export default class ClauseGroup {
return;
}
const parentGroup = this.parentGroup;
let index = parentGroup.children.indexOf(this);
var parentGroup = this.parentGroup;
var index = parentGroup.children.indexOf(this);
if (index >= 0) {
parentGroup.children.splice(index, 1);
const toPromote = this.children.splice(0, this.children.length);
var toPromote = this.children.splice(0, this.children.length);
// Move all children one level up.
toPromote &&
@@ -147,16 +146,16 @@ export default class ClauseGroup {
}
public findDeepestGroupInChildren(skipIndex?: number): ClauseGroup {
let deepest = <ClauseGroup>this;
let level = 0;
const func = (currentGroup: ClauseGroup): void => {
var deepest: ClauseGroup = this;
var level: number = 0;
var func = (currentGroup: ClauseGroup): void => {
level++;
if (currentGroup.getCurrentGroupDepth() > deepest.getCurrentGroupDepth()) {
deepest = currentGroup;
}
for (let i = 0; i < currentGroup.children.length; i++) {
const currentItem = currentGroup.children[i];
for (var i = 0; i < currentGroup.children.length; i++) {
var currentItem = currentGroup.children[i];
if ((i !== skipIndex || level > 1) && currentItem instanceof ClauseGroup) {
func(currentItem);
@@ -171,16 +170,16 @@ export default class ClauseGroup {
}
private getCheckedItemsInfo(): { canGroup: boolean; begin: number; end: number } {
let beginIndex = -1;
let endIndex = -1;
var beginIndex = -1;
var endIndex = -1;
// In order to perform group, all selected items must be next to each other.
// If one or more items are not selected between the first and the last selected item, the gapFlag will be set to True, meaning cannot perform group.
let gapFlag = false;
let count = 0;
var gapFlag = false;
var count = 0;
for (let i = 0; i < this.children.length; i++) {
const currentItem = this.children[i];
let subGroupSelectionState: { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean };
for (var i = 0; i < this.children.length; i++) {
var currentItem = this.children[i];
var subGroupSelectionState: { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean };
if (currentItem instanceof ClauseGroup) {
subGroupSelectionState = (<ClauseGroup>currentItem).getSelectionState();
@@ -236,10 +235,10 @@ export default class ClauseGroup {
}
private getSelectionState(): { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean } {
let selectedCount = 0;
var selectedCount = 0;
for (let i = 0; i < this.children.length; i++) {
const currentItem = this.children[i];
for (var i = 0; i < this.children.length; i++) {
var currentItem = this.children[i];
if (currentItem instanceof ClauseGroup && (<ClauseGroup>currentItem).getSelectionState().allSelected) {
selectedCount++;
@@ -261,8 +260,8 @@ export default class ClauseGroup {
}
private unselectAll(): void {
for (let i = 0; i < this.children.length; i++) {
const currentItem = this.children[i];
for (var i = 0; i < this.children.length; i++) {
var currentItem = this.children[i];
if (currentItem instanceof ClauseGroup) {
(<ClauseGroup>currentItem).unselectAll();
@@ -279,8 +278,8 @@ export default class ClauseGroup {
targetArray.splice(0, targetArray.length);
}
for (let i = 0; i < queryGroup.children.length; i++) {
const currentItem = queryGroup.children[i];
for (var i = 0; i < queryGroup.children.length; i++) {
var currentItem = queryGroup.children[i];
if (currentItem instanceof ClauseGroup) {
this.flattenClausesImpl(currentItem, targetArray);
@@ -293,13 +292,13 @@ export default class ClauseGroup {
}
public getTreeDepth(): number {
let currentDepth = this.getCurrentGroupDepth();
var currentDepth = this.getCurrentGroupDepth();
for (let i = 0; i < this.children.length; i++) {
const currentItem = this.children[i];
for (var i = 0; i < this.children.length; i++) {
var currentItem = this.children[i];
if (currentItem instanceof ClauseGroup) {
const newDepth = (<ClauseGroup>currentItem).getTreeDepth();
var newDepth = (<ClauseGroup>currentItem).getTreeDepth();
if (newDepth > currentDepth) {
currentDepth = newDepth;
@@ -311,8 +310,8 @@ export default class ClauseGroup {
}
public getCurrentGroupDepth(): number {
let group = <ClauseGroup>this;
let depth = 0;
var group = <ClauseGroup>this;
var depth = 0;
while (!group.isRootGroup) {
depth++;

View File

@@ -1,7 +1,7 @@
import * as ko from "knockout";
import * as Constants from "../Constants";
import ClauseGroup from "./ClauseGroup";
import QueryBuilderViewModel from "./QueryBuilderViewModel";
import * as Constants from "../Constants";
/**
* View model for showing group indicators on UI, contains information such as group color and border styles.
@@ -38,7 +38,7 @@ export default class ClauseGroupViewModel {
};
private getGroupBackgroundColor(group: ClauseGroup): string {
const colorCount = Constants.clauseGroupColors.length;
var colorCount = Constants.clauseGroupColors.length;
if (group.isRootGroup) {
return Constants.transparentColor;

View File

@@ -29,7 +29,7 @@ export default class QueryBuilderViewModel {
public removeThisFilterLine = "Remove this filter line"; // localize
public groupSelectedClauses = "Group selected clauses"; // localize
public clauseArray = ko.observableArray<QueryClauseViewModel>(); // This is for storing the clauses in flattened form queryClauses for easier UI data binding.
public queryClauses = new ClauseGroup(true, undefined); // The actual data structure containing the clause information.
public queryClauses = new ClauseGroup(true, null); // The actual data structure containing the clause information.
public columnOptions: ko.ObservableArray<string>;
public canGroupClauses = ko.observable<boolean>(false);
@@ -107,7 +107,7 @@ export default class QueryBuilderViewModel {
}
public setExample() {
const example1 = new QueryClauseViewModel(
var example1 = new QueryClauseViewModel(
this,
"",
"PartitionKey",
@@ -121,7 +121,7 @@ export default class QueryBuilderViewModel {
//null,
true
);
const example2 = new QueryClauseViewModel(
var example2 = new QueryClauseViewModel(
this,
"And",
"RowKey",
@@ -140,13 +140,13 @@ export default class QueryBuilderViewModel {
}
public getODataFilterFromClauses = (): string => {
let filterString = "";
const treeTraversal = (group: ClauseGroup): void => {
for (let i = 0; i < group.children.length; i++) {
const currentItem = group.children[i];
var filterString: string = "";
var treeTraversal = (group: ClauseGroup): void => {
for (var i = 0; i < group.children.length; i++) {
var currentItem = group.children[i];
if (currentItem instanceof QueryClauseViewModel) {
const clause = <QueryClauseViewModel>currentItem;
var clause = <QueryClauseViewModel>currentItem;
this.timestampToValue(clause);
filterString = filterString.concat(
this.constructODataClause(
@@ -173,7 +173,7 @@ export default class QueryBuilderViewModel {
};
public getSqlFilterFromClauses = (): string => {
let filterString = "SELECT * FROM c";
var filterString: string = "SELECT * FROM c";
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
filterString = "SELECT";
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
@@ -199,15 +199,15 @@ export default class QueryBuilderViewModel {
return filterString;
}
filterString = filterString.concat(" WHERE");
let first = true;
const treeTraversal = (group: ClauseGroup): void => {
for (let i = 0; i < group.children.length; i++) {
const currentItem = group.children[i];
var first = true;
var treeTraversal = (group: ClauseGroup): void => {
for (var i = 0; i < group.children.length; i++) {
var currentItem = group.children[i];
if (currentItem instanceof QueryClauseViewModel) {
const clause = <QueryClauseViewModel>currentItem;
const timeStampValue: string = this.timestampToSqlValue(clause);
let value = clause.value();
var clause = <QueryClauseViewModel>currentItem;
let timeStampValue: string = this.timestampToSqlValue(clause);
var value = clause.value();
if (!clause.isValue()) {
value = timeStampValue;
}
@@ -240,7 +240,7 @@ export default class QueryBuilderViewModel {
const databaseId = this._queryViewModel.queryTablesTab.collection.databaseId;
const collectionId = this._queryViewModel.queryTablesTab.collection.id();
const tableToQuery = `${getQuotedCqlIdentifier(databaseId)}.${getQuotedCqlIdentifier(collectionId)}`;
let filterString = `SELECT * FROM ${tableToQuery}`;
var filterString: string = `SELECT * FROM ${tableToQuery}`;
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
filterString = "SELECT";
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
@@ -255,15 +255,15 @@ export default class QueryBuilderViewModel {
return filterString;
}
filterString = filterString.concat(" WHERE");
let first = true;
const treeTraversal = (group: ClauseGroup): void => {
for (let i = 0; i < group.children.length; i++) {
const currentItem = group.children[i];
var first = true;
var treeTraversal = (group: ClauseGroup): void => {
for (var i = 0; i < group.children.length; i++) {
var currentItem = group.children[i];
if (currentItem instanceof QueryClauseViewModel) {
const clause = <QueryClauseViewModel>currentItem;
const timeStampValue = this.timestampToSqlValue(clause);
let value = clause.value();
var clause = <QueryClauseViewModel>currentItem;
let timeStampValue: string = this.timestampToSqlValue(clause);
var value = clause.value();
if (!clause.isValue()) {
value = timeStampValue;
}
@@ -293,13 +293,13 @@ export default class QueryBuilderViewModel {
};
public updateColumnOptions = (): void => {
// let originalHeaders = this.columnOptions();
const newHeaders = this.tableEntityListViewModel.headers;
let originalHeaders = this.columnOptions();
let newHeaders = this.tableEntityListViewModel.headers;
this.columnOptions(newHeaders.sort(DataTableUtilities.compareTableColumns));
};
private generateLeftParentheses(clause: QueryClauseViewModel): string {
let result = "";
var result = "";
if (clause.clauseGroup.isRootGroup || clause.clauseGroup.children.indexOf(clause) !== 0) {
return result;
@@ -307,7 +307,7 @@ export default class QueryBuilderViewModel {
result = result.concat("(");
}
let currentGroup: ClauseGroup = clause.clauseGroup;
var currentGroup: ClauseGroup = clause.clauseGroup;
while (
!currentGroup.isRootGroup &&
@@ -322,7 +322,7 @@ export default class QueryBuilderViewModel {
}
private generateRightParentheses(clause: QueryClauseViewModel): string {
let result = "";
var result = "";
if (
clause.clauseGroup.isRootGroup ||
@@ -333,7 +333,7 @@ export default class QueryBuilderViewModel {
result = result.concat(")");
}
let currentGroup: ClauseGroup = clause.clauseGroup;
var currentGroup: ClauseGroup = clause.clauseGroup;
while (
!currentGroup.isRootGroup &&
@@ -364,17 +364,14 @@ export default class QueryBuilderViewModel {
case Constants.TableType.String:
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
operator
// eslint-disable-next-line no-useless-escape
)} \'${value}\'${rightParentheses}`;
case Constants.TableType.Guid:
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
operator
// eslint-disable-next-line no-useless-escape
)} guid\'${value}\'${rightParentheses}`;
case Constants.TableType.Binary:
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
operator
// eslint-disable-next-line no-useless-escape
)} binary\'${value}\'${rightParentheses}`;
default:
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
@@ -394,11 +391,9 @@ export default class QueryBuilderViewModel {
): string => {
if (propertyName === Constants.EntityKeyNames.PartitionKey) {
propertyName = TableEntityProcessor.keyProperties.PartitionKey;
// eslint-disable-next-line no-useless-escape
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c["${propertyName}"] ${operator} \'${value}\'${rightParentheses}`;
} else if (propertyName === Constants.EntityKeyNames.RowKey) {
propertyName = TableEntityProcessor.keyProperties.Id;
// eslint-disable-next-line no-useless-escape
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName} ${operator} \'${value}\'${rightParentheses}`;
} else if (propertyName === Constants.EntityKeyNames.Timestamp) {
propertyName = TableEntityProcessor.keyProperties.Timestamp;
@@ -408,21 +403,16 @@ export default class QueryBuilderViewModel {
}
switch (type) {
case Constants.TableType.DateTime:
// eslint-disable-next-line no-useless-escape
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${DateTimeUtilities.convertJSDateToTicksWithPadding(
value
// eslint-disable-next-line no-useless-escape
)}\'${rightParentheses}`;
case Constants.TableType.Int64:
// eslint-disable-next-line no-useless-escape
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${Utilities.padLongWithZeros(
value
// eslint-disable-next-line no-useless-escape
)}\'${rightParentheses}`;
case Constants.TableType.String:
case Constants.TableType.Guid:
case Constants.TableType.Binary:
// eslint-disable-next-line no-useless-escape
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${value}\'${rightParentheses}`;
default:
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} ${value}${rightParentheses}`;
@@ -444,7 +434,6 @@ export default class QueryBuilderViewModel {
type === Constants.CassandraType.Ascii ||
type === Constants.CassandraType.Varchar
) {
// eslint-disable-next-line no-useless-escape
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} \'${value}\'${rightParentheses}`;
}
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} ${value}${rightParentheses}`;
@@ -465,7 +454,7 @@ export default class QueryBuilderViewModel {
case Constants.Operator.NotEqualTo:
return Constants.ODataOperator.NotEqualTo;
}
return undefined;
return null;
};
public groupClauses = (): void => {
@@ -474,11 +463,11 @@ export default class QueryBuilderViewModel {
this.updateCanGroupClauses();
};
public addClauseIndex = (index: number): void => {
public addClauseIndex = (index: number, data: any): void => {
if (index < 0) {
index = 0;
}
const newClause = new QueryClauseViewModel(
var newClause = new QueryClauseViewModel(
this,
"And",
"",
@@ -503,28 +492,28 @@ export default class QueryBuilderViewModel {
// adds a new clause to the end of the array
public addNewClause = (): void => {
this.addClauseIndex(this.clauseArray().length);
this.addClauseIndex(this.clauseArray().length, null);
};
public onAddClauseKeyDown = (index: number, event: KeyboardEvent): boolean => {
public onAddClauseKeyDown = (index: number, data: any, event: KeyboardEvent, source: any): boolean => {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.addClauseIndex(index);
this.addClauseIndex(index, data);
event.stopPropagation();
return false;
}
return true;
};
public onAddNewClauseKeyDown = (event: KeyboardEvent): boolean => {
public onAddNewClauseKeyDown = (source: any, event: KeyboardEvent): boolean => {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.addClauseIndex(this.clauseArray().length - 1);
this.addClauseIndex(this.clauseArray().length - 1, null);
event.stopPropagation();
return false;
}
return true;
};
public deleteClause = (index: number): void => {
public deleteClause = (index: number, data: any): void => {
this.deleteClauseImpl(index);
if (this.clauseArray().length !== 0) {
this.clauseArray()[0].and_or("");
@@ -534,9 +523,9 @@ export default class QueryBuilderViewModel {
$(window).resize();
};
public onDeleteClauseKeyDown = (index: number, event: KeyboardEvent): boolean => {
public onDeleteClauseKeyDown = (index: number, data: any, event: KeyboardEvent, source: any): boolean => {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.deleteClause(index);
this.deleteClause(index, data);
event.stopPropagation();
return false;
}
@@ -550,26 +539,25 @@ export default class QueryBuilderViewModel {
* (transparent) or its parent group view models.
*/
public getClauseGroupViewModels = (clause: QueryClauseViewModel): ClauseGroupViewModel[] => {
const placeHolderGroupViewModel = new ClauseGroupViewModel(this.queryClauses, false, this);
const treeDepth = this.queryClauses.getTreeDepth();
const groupViewModels = new Array<ClauseGroupViewModel>(treeDepth);
var placeHolderGroupViewModel = new ClauseGroupViewModel(this.queryClauses, false, this);
var treeDepth = this.queryClauses.getTreeDepth();
var groupViewModels = new Array<ClauseGroupViewModel>(treeDepth);
// Prefill the arry with placeholders.
for (let i = 0; i < groupViewModels.length; i++) {
for (var i = 0; i < groupViewModels.length; i++) {
groupViewModels[i] = placeHolderGroupViewModel;
}
let currentGroup = clause.clauseGroup;
var currentGroup = clause.clauseGroup;
// This function determines whether the path from clause to the current group is on the left most.
const isLeftMostPath = (): boolean => {
let group = clause.clauseGroup;
var isLeftMostPath = (): boolean => {
var group = clause.clauseGroup;
if (group.children.indexOf(clause) !== 0) {
return false;
}
// eslint-disable-next-line no-constant-condition
while (true) {
if (group.getId() === currentGroup.getId()) {
break;
@@ -585,14 +573,13 @@ export default class QueryBuilderViewModel {
};
// This function determines whether the path from clause to the current group is on the right most.
const isRightMostPath = (): boolean => {
let group = clause.clauseGroup;
var isRightMostPath = (): boolean => {
var group = clause.clauseGroup;
if (group.children.indexOf(clause) !== group.children.length - 1) {
return false;
}
// eslint-disable-next-line no-constant-condition
while (true) {
if (group.getId() === currentGroup.getId()) {
break;
@@ -607,26 +594,26 @@ export default class QueryBuilderViewModel {
return true;
};
let vmIndex = groupViewModels.length - 1;
let skipIndex = -1;
let lastDepth = clause.groupDepth;
var vmIndex = groupViewModels.length - 1;
var skipIndex = -1;
var lastDepth = clause.groupDepth;
while (!currentGroup.isRootGroup) {
// The current group will be rendered at least once, and if there are any sibling groups deeper
// than the current group, we will repeat rendering the current group to fill up the gap between
// current & deepest sibling.
const deepestInSiblings = currentGroup.findDeepestGroupInChildren(skipIndex).getCurrentGroupDepth();
var deepestInSiblings = currentGroup.findDeepestGroupInChildren(skipIndex).getCurrentGroupDepth();
// Find out the depth difference between the deepest group under the siblings of currentGroup and
// the deepest group under currentGroup. If the result n is a positive number, it means there are
// deeper groups in siblings and we need to draw n + 1 group blocks on UI to fill up the depth
// differences. If the result n is a negative number, it means current group contains the deepest
// sub-group, we only need to draw the group block once.
const repeatCount = Math.max(deepestInSiblings - lastDepth, 0);
var repeatCount = Math.max(deepestInSiblings - lastDepth, 0);
for (let i = 0; i <= repeatCount; i++) {
const isLeftMost = isLeftMostPath();
const isRightMost = isRightMostPath();
const groupViewModel = new ClauseGroupViewModel(currentGroup, i === 0 && isLeftMost, this);
for (var i = 0; i <= repeatCount; i++) {
var isLeftMost = isLeftMostPath();
var isRightMost = isRightMostPath();
var groupViewModel = new ClauseGroupViewModel(currentGroup, i === 0 && isLeftMost, this);
groupViewModel.showTopBorder(isLeftMost);
groupViewModel.showBottomBorder(isRightMost);
@@ -648,9 +635,9 @@ export default class QueryBuilderViewModel {
};
public addCustomRange(timestamp: CustomTimestampHelper.ITimestampQuery, clauseToAdd: QueryClauseViewModel): void {
const index = this.clauseArray.peek().indexOf(clauseToAdd);
var index = this.clauseArray.peek().indexOf(clauseToAdd);
const newClause = new QueryClauseViewModel(
var newClause = new QueryClauseViewModel(
this,
//this._tableEntityListViewModel.tableExplorerContext.hostProxy,
"And",
@@ -675,10 +662,10 @@ export default class QueryBuilderViewModel {
}
private scrollToBottom(): void {
const scrollBox = document.getElementById("scroll");
var scrollBox = document.getElementById("scroll");
if (!this.scrollEventListener) {
scrollBox.addEventListener("scroll", function () {
const translate = "translate(0," + this.scrollTop + "px)";
var translate = "translate(0," + this.scrollTop + "px)";
const allTh = <NodeListOf<HTMLElement>>this.querySelectorAll("thead td");
for (let i = 0; i < allTh.length; i++) {
allTh[i].style.transform = translate;
@@ -686,7 +673,7 @@ export default class QueryBuilderViewModel {
});
this.scrollEventListener = true;
}
const isScrolledToBottom = scrollBox.scrollHeight - scrollBox.clientHeight <= scrollBox.scrollHeight + 1;
var isScrolledToBottom = scrollBox.scrollHeight - scrollBox.clientHeight <= scrollBox.scrollHeight + 1;
if (isScrolledToBottom) {
scrollBox.scrollTop = scrollBox.scrollHeight - scrollBox.clientHeight;
}
@@ -698,8 +685,8 @@ export default class QueryBuilderViewModel {
}
private deleteClauseImpl(index: number): void {
const clause = this.clauseArray()[index];
const previousClause = index === 0 ? 0 : index - 1;
var clause = this.clauseArray()[index];
var previousClause = index === 0 ? 0 : index - 1;
this.queryClauses.deleteClause(clause);
this.updateClauseArray();
if (this.clauseArray()[previousClause]) {
@@ -744,7 +731,7 @@ export default class QueryBuilderViewModel {
private timestampToSqlValue(clause: QueryClauseViewModel): string {
if (clause.isValue()) {
return undefined;
return null;
} else if (clause.isTimestamp()) {
return this.getTimeStampToSqlQuery(clause);
// } else if (clause.isCustomLastTimestamp()) {
@@ -756,7 +743,7 @@ export default class QueryBuilderViewModel {
return clause.customTimeValue();
}
}
return undefined;
return null;
}
private getTimeStampToQuery(clause: QueryClauseViewModel): void {
@@ -802,7 +789,7 @@ export default class QueryBuilderViewModel {
case Constants.timeOptions.currentYear:
return CustomTimestampHelper._queryCurrentYearLocal();
}
return undefined;
return null;
}
public checkIfClauseChanged(): void {

View File

@@ -14,7 +14,7 @@ export default class QueryClauseViewModel {
public field: ko.Observable<string>;
public type: ko.Observable<string>;
public operator: ko.Observable<string>;
public value: ko.Observable<string>;
public value: ko.Observable<any>;
public timeValue: ko.Observable<string>;
public customTimeValue: ko.Observable<string>;
public canAnd: ko.Observable<boolean>;
@@ -39,7 +39,7 @@ export default class QueryClauseViewModel {
field: string,
type: string,
operator: string,
value: string,
value: any,
canAnd: boolean,
timeValue: string,
customTimeValue: string,
@@ -88,30 +88,30 @@ export default class QueryClauseViewModel {
userContext.apiType !== "Cassandra"
);
this.and_or.subscribe(() => {
this.and_or.subscribe((value) => {
this._queryBuilderViewModel.checkIfClauseChanged();
});
this.field.subscribe(() => {
this.field.subscribe((value) => {
this.changeField();
});
this.type.subscribe(() => {
this.type.subscribe((value) => {
this.changeType();
});
this.timeValue.subscribe(() => {
this.timeValue.subscribe((value) => {
// if (this.timeValue() === QueryBuilderConstants.timeOptions.custom) {
// this.customTimestampDialog();
// }
});
this.customTimeValue.subscribe(() => {
this.customTimeValue.subscribe((value) => {
this._queryBuilderViewModel.checkIfClauseChanged();
});
this.value.subscribe(() => {
this.value.subscribe((value) => {
this._queryBuilderViewModel.checkIfClauseChanged();
});
this.operator.subscribe(() => {
this.operator.subscribe((value) => {
this._queryBuilderViewModel.checkIfClauseChanged();
});
this._groupCheckSubscription = this.checkedForGrouping.subscribe(() => {
this._groupCheckSubscription = this.checkedForGrouping.subscribe((value) => {
this._queryBuilderViewModel.updateCanGroupClauses();
});
this.isAndOrFocused = ko.observable<boolean>(false);
@@ -280,7 +280,7 @@ export default class QueryClauseViewModel {
this._groupCheckSubscription.dispose();
}
this.clauseGroup = undefined;
this._queryBuilderViewModel = undefined;
this.clauseGroup = null;
this._queryBuilderViewModel = null;
}
}

View File

@@ -999,7 +999,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
"data-order": 2,
"data-title": "Query Stats",
}}
style={{ height: "100%", overflowY: "scroll" }}
style={{ height: "100%" }}
>
{this.state.allResultsMetadata.length > 0 && !this.state.error && (
<div className="queryMetricsSummaryContainer">

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