More ViewModel cleanup (#116)

This commit is contained in:
Steve Faulkner 2020-07-27 16:05:25 -05:00 committed by GitHub
parent 2e49ed45c3
commit fea321cd68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
97 changed files with 492 additions and 1904 deletions

View File

@ -42,7 +42,7 @@ module.exports = {
branches: 19.5, branches: 19.5,
functions: 24, functions: 24,
lines: 29.5, lines: 29.5,
statements: 28.5 statements: 29.0
} }
}, },

View File

@ -1,13 +0,0 @@
import * as ViewModels from "../Contracts/ViewModels";
export class DefaultApi implements ViewModels.CosmosDbApi {
public isSystemDatabasePredicate = (database: ViewModels.Database): boolean => {
return false;
};
}
export class CassandraApi implements ViewModels.CosmosDbApi {
public isSystemDatabasePredicate = (database: ViewModels.Database): boolean => {
return database.id() === "system";
};
}

View File

@ -27,6 +27,8 @@ import { RequestOptions } from "@azure/cosmos/dist-esm";
import StoredProcedure from "../Explorer/Tree/StoredProcedure"; import StoredProcedure from "../Explorer/Tree/StoredProcedure";
import { Platform, config } from "../Config"; import { Platform, config } from "../Config";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import DocumentId from "../Explorer/Tree/DocumentId";
import ConflictId from "../Explorer/Tree/ConflictId";
export function getCommonQueryOptions(options: FeedOptions): any { export function getCommonQueryOptions(options: FeedOptions): any {
const storedItemPerPageSetting: number = LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage); const storedItemPerPageSetting: number = LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage);
@ -169,7 +171,7 @@ export function executeStoredProcedure(
); );
} }
export function readDocument(collection: ViewModels.CollectionBase, documentId: ViewModels.DocumentId): Q.Promise<any> { export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
const partitionKey = documentId.partitionKeyValue; const partitionKey = documentId.partitionKeyValue;
return Q( return Q(
@ -182,7 +184,7 @@ export function readDocument(collection: ViewModels.CollectionBase, documentId:
); );
} }
export function getPartitionKeyHeaderForConflict(conflictId: ViewModels.ConflictId): Object { export function getPartitionKeyHeaderForConflict(conflictId: ConflictId): Object {
const partitionKeyDefinition: DataModels.PartitionKey = conflictId.partitionKey; const partitionKeyDefinition: DataModels.PartitionKey = conflictId.partitionKey;
const partitionKeyValue: any = conflictId.partitionKeyValue; const partitionKeyValue: any = conflictId.partitionKeyValue;
@ -220,7 +222,7 @@ export function updateCollection(
export function updateDocument( export function updateDocument(
collection: ViewModels.CollectionBase, collection: ViewModels.CollectionBase,
documentId: ViewModels.DocumentId, documentId: DocumentId,
newDocument: any newDocument: any
): Q.Promise<any> { ): Q.Promise<any> {
const partitionKey = documentId.partitionKeyValue; const partitionKey = documentId.partitionKeyValue;
@ -347,10 +349,7 @@ export function createTrigger(
); );
} }
export function deleteDocument( export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
collection: ViewModels.CollectionBase,
documentId: ViewModels.DocumentId
): Q.Promise<any> {
const partitionKey = documentId.partitionKeyValue; const partitionKey = documentId.partitionKeyValue;
return Q( return Q(
@ -364,7 +363,7 @@ export function deleteDocument(
export function deleteConflict( export function deleteConflict(
collection: ViewModels.CollectionBase, collection: ViewModels.CollectionBase,
conflictId: ViewModels.ConflictId, conflictId: ConflictId,
options: any = {} options: any = {}
): Q.Promise<any> { ): Q.Promise<any> {
options.partitionKey = options.partitionKey || getPartitionKeyHeaderForConflict(conflictId); options.partitionKey = options.partitionKey || getPartitionKeyHeaderForConflict(conflictId);

View File

@ -13,6 +13,8 @@ import { MinimalQueryIterator, nextPage } from "./IteratorUtilities";
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
import { RequestOptions } from "@azure/cosmos/dist-esm"; import { RequestOptions } from "@azure/cosmos/dist-esm";
import StoredProcedure from "../Explorer/Tree/StoredProcedure"; import StoredProcedure from "../Explorer/Tree/StoredProcedure";
import ConflictId from "../Explorer/Tree/ConflictId";
import DocumentId from "../Explorer/Tree/DocumentId";
// TODO: Log all promise resolutions and errors with verbosity levels // TODO: Log all promise resolutions and errors with verbosity levels
export function queryDocuments( export function queryDocuments(
@ -236,7 +238,7 @@ export function queryDocumentsPage(
return deferred.promise; return deferred.promise;
} }
export function readDocument(collection: ViewModels.CollectionBase, documentId: ViewModels.DocumentId): Q.Promise<any> { export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
var deferred = Q.defer<any>(); var deferred = Q.defer<any>();
const entityName = getEntityName(); const entityName = getEntityName();
const id = NotificationConsoleUtils.logConsoleMessage( const id = NotificationConsoleUtils.logConsoleMessage(
@ -303,7 +305,7 @@ export function updateCollection(
export function updateDocument( export function updateDocument(
collection: ViewModels.CollectionBase, collection: ViewModels.CollectionBase,
documentId: ViewModels.DocumentId, documentId: DocumentId,
newDocument: any newDocument: any
): Q.Promise<any> { ): Q.Promise<any> {
var deferred = Q.defer<any>(); var deferred = Q.defer<any>();
@ -658,10 +660,7 @@ export function createTrigger(
return deferred.promise; return deferred.promise;
} }
export function deleteDocument( export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise<any> {
collection: ViewModels.CollectionBase,
documentId: ViewModels.DocumentId
): Q.Promise<any> {
var deferred = Q.defer<any>(); var deferred = Q.defer<any>();
const entityName = getEntityName(); const entityName = getEntityName();
const id = NotificationConsoleUtils.logConsoleMessage( const id = NotificationConsoleUtils.logConsoleMessage(
@ -696,7 +695,7 @@ export function deleteDocument(
export function deleteConflict( export function deleteConflict(
collection: ViewModels.CollectionBase, collection: ViewModels.CollectionBase,
conflictId: ViewModels.ConflictId, conflictId: ConflictId,
options?: any options?: any
): Q.Promise<any> { ): Q.Promise<any> {
var deferred = Q.defer<any>(); var deferred = Q.defer<any>();

View File

@ -7,10 +7,12 @@ import {
updateDocument updateDocument
} from "./MongoProxyClient"; } from "./MongoProxyClient";
import { AuthType } from "../AuthType"; import { AuthType } from "../AuthType";
import { Collection, DatabaseAccount, DocumentId } from "../Contracts/ViewModels"; import { Collection } from "../Contracts/ViewModels";
import { config } from "../Config"; import { config } from "../Config";
import { CosmosClient } from "./CosmosClient"; import { CosmosClient } from "./CosmosClient";
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient"; import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
import DocumentId from "../Explorer/Tree/DocumentId";
import { DatabaseAccount } from "../Contracts/DataModels";
jest.mock("../ResourceProvider/ResourceProviderClient.ts"); jest.mock("../ResourceProvider/ResourceProviderClient.ts");
const databaseId = "testDB"; const databaseId = "testDB";

View File

@ -1,7 +1,6 @@
import * as Constants from "../Common/Constants"; import * as Constants from "../Common/Constants";
import * as DataExplorerConstants from "../Common/Constants"; import * as DataExplorerConstants from "../Common/Constants";
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
import EnvironmentUtility from "./EnvironmentUtility"; import EnvironmentUtility from "./EnvironmentUtility";
import queryString from "querystring"; import queryString from "querystring";
import { AddDbUtilities } from "../Shared/AddDatabaseUtility"; import { AddDbUtilities } from "../Shared/AddDatabaseUtility";
@ -17,6 +16,7 @@ import { MessageTypes } from "../Contracts/ExplorerContracts";
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient"; import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
import { MinimalQueryIterator } from "./IteratorUtilities"; import { MinimalQueryIterator } from "./IteratorUtilities";
import DocumentId from "../Explorer/Tree/DocumentId";
const defaultHeaders = { const defaultHeaders = {
[HttpHeaders.apiType]: ApiType.MongoDB.toString(), [HttpHeaders.apiType]: ApiType.MongoDB.toString(),
@ -123,7 +123,7 @@ export function queryDocuments(
export function readDocument( export function readDocument(
databaseId: string, databaseId: string,
collection: Collection, collection: Collection,
documentId: ViewModels.DocumentId documentId: DocumentId
): Promise<DataModels.DocumentId> { ): Promise<DataModels.DocumentId> {
const databaseAccount = CosmosClient.databaseAccount(); const databaseAccount = CosmosClient.databaseAccount();
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint; const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
@ -205,7 +205,7 @@ export function createDocument(
export function updateDocument( export function updateDocument(
databaseId: string, databaseId: string,
collection: Collection, collection: Collection,
documentId: ViewModels.DocumentId, documentId: DocumentId,
documentContent: unknown documentContent: unknown
): Promise<DataModels.DocumentId> { ): Promise<DataModels.DocumentId> {
const databaseAccount = CosmosClient.databaseAccount(); const databaseAccount = CosmosClient.databaseAccount();
@ -246,11 +246,7 @@ export function updateDocument(
}); });
} }
export function deleteDocument( export function deleteDocument(databaseId: string, collection: Collection, documentId: DocumentId): Promise<void> {
databaseId: string,
collection: Collection,
documentId: ViewModels.DocumentId
): Promise<void> {
const databaseAccount = CosmosClient.databaseAccount(); const databaseAccount = CosmosClient.databaseAccount();
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint; const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
const idComponents = documentId.self.split("/"); const idComponents = documentId.self.split("/");
@ -385,7 +381,7 @@ export function createMongoCollectionWithARM(
return _createMongoCollectionWithARM(armEndpoint, params, additionalOptions); return _createMongoCollectionWithARM(armEndpoint, params, additionalOptions);
} }
export function getEndpoint(databaseAccount: ViewModels.DatabaseAccount): string { export function getEndpoint(databaseAccount: DataModels.DatabaseAccount): string {
const serverId = window.dataExplorer.serverId(); const serverId = window.dataExplorer.serverId();
const extensionEndpoint = window.dataExplorer.extensionEndpoint(); const extensionEndpoint = window.dataExplorer.extensionEndpoint();
let url = config.MONGO_BACKEND_ENDPOINT let url = config.MONGO_BACKEND_ENDPOINT

View File

@ -6,7 +6,7 @@ import * as ViewModels from "../Contracts/ViewModels";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { CosmosClient } from "./CosmosClient"; import { CosmosClient } from "./CosmosClient";
export class NotificationsClientBase implements ViewModels.NotificationsClient { export class NotificationsClientBase {
private _extensionEndpoint: string; private _extensionEndpoint: string;
private _notificationsApiSuffix: string; private _notificationsApiSuffix: string;
@ -16,7 +16,7 @@ export class NotificationsClientBase implements ViewModels.NotificationsClient {
public fetchNotifications(): Q.Promise<DataModels.Notification[]> { public fetchNotifications(): Q.Promise<DataModels.Notification[]> {
const deferred: Q.Deferred<DataModels.Notification[]> = Q.defer<DataModels.Notification[]>(); const deferred: Q.Deferred<DataModels.Notification[]> = Q.defer<DataModels.Notification[]>();
const databaseAccount: ViewModels.DatabaseAccount = CosmosClient.databaseAccount(); const databaseAccount = CosmosClient.databaseAccount();
const subscriptionId: string = CosmosClient.subscriptionId(); const subscriptionId: string = CosmosClient.subscriptionId();
const resourceGroup: string = CosmosClient.resourceGroup(); const resourceGroup: string = CosmosClient.resourceGroup();
const url: string = `${this._extensionEndpoint}${this._notificationsApiSuffix}?accountName=${databaseAccount.name}&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`; const url: string = `${this._extensionEndpoint}${this._notificationsApiSuffix}?accountName=${databaseAccount.name}&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`;

View File

@ -18,8 +18,9 @@ import {
queryDocumentsPage, queryDocumentsPage,
deleteDocument deleteDocument
} from "./DocumentClientUtilityBase"; } from "./DocumentClientUtilityBase";
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
export class QueriesClient implements ViewModels.QueriesClient { export class QueriesClient {
private static readonly PartitionKey: DataModels.PartitionKey = { private static readonly PartitionKey: DataModels.PartitionKey = {
paths: [`/${SavedQueries.PartitionKeyProperty}`], paths: [`/${SavedQueries.PartitionKeyProperty}`],
kind: BackendDefaults.partitionKeyKind, kind: BackendDefaults.partitionKeyKind,
@ -216,11 +217,11 @@ export class QueriesClient implements ViewModels.QueriesClient {
`Deleting query ${query.queryName}` `Deleting query ${query.queryName}`
); );
query.id = query.queryName; query.id = query.queryName;
const documentId: ViewModels.DocumentId = new DocumentId( const documentId = new DocumentId(
{ {
partitionKey: QueriesClient.PartitionKey, partitionKey: QueriesClient.PartitionKey,
partitionKeyProperty: "id" partitionKeyProperty: "id"
} as ViewModels.DocumentsTab, } as DocumentsTab,
query, query,
query.queryName query.queryName
); // TODO: Remove DocumentId's dependency on DocumentsTab ); // TODO: Remove DocumentId's dependency on DocumentsTab
@ -248,7 +249,7 @@ export class QueriesClient implements ViewModels.QueriesClient {
} }
public getResourceId(): string { public getResourceId(): string {
const databaseAccount: ViewModels.DatabaseAccount = CosmosClient.databaseAccount(); const databaseAccount = CosmosClient.databaseAccount();
const databaseAccountName: string = (databaseAccount && databaseAccount.name) || ""; const databaseAccountName: string = (databaseAccount && databaseAccount.name) || "";
const subscriptionId: string = CosmosClient.subscriptionId() || ""; const subscriptionId: string = CosmosClient.subscriptionId() || "";
const resourceGroup: string = CosmosClient.resourceGroup() || ""; const resourceGroup: string = CosmosClient.resourceGroup() || "";

View File

@ -1,39 +1,16 @@
import * as DataModels from "./DataModels"; import * as DataModels from "./DataModels";
import * as monaco from "monaco-editor";
import Q from "q"; import Q from "q";
import { AccessibleVerticalList } from "../Explorer/Tree/AccessibleVerticalList";
import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient"; import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient";
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent"; import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
import { GitHubClient } from "../GitHub/GitHubClient";
import { JunoClient, IGalleryItem } from "../Juno/JunoClient";
import { NotebookContentItem } from "../Explorer/Notebook/NotebookContentItem";
import { QueryMetrics } from "@azure/cosmos"; import { QueryMetrics } from "@azure/cosmos";
import { UploadDetails } from "../workers/upload/definitions"; import { UploadDetails } from "../workers/upload/definitions";
import Explorer from "../Explorer/Explorer"; import Explorer from "../Explorer/Explorer";
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction"; import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
import StoredProcedure from "../Explorer/Tree/StoredProcedure"; import StoredProcedure from "../Explorer/Tree/StoredProcedure";
import ConflictsTab from "../Explorer/Tabs/ConflictsTab";
import Trigger from "../Explorer/Tree/Trigger"; import Trigger from "../Explorer/Tree/Trigger";
import DocumentId from "../Explorer/Tree/DocumentId";
export interface ExplorerOptions { import ConflictId from "../Explorer/Tree/ConflictId";
notificationsClient: NotificationsClient;
isEmulator: boolean;
}
export interface Capability extends DataModels.Capability {}
export interface ConfigurationOverrides extends DataModels.ConfigurationOverrides {}
export interface NavbarButtonConfig extends CommandButtonComponentProps {}
export interface DatabaseAccount extends DataModels.DatabaseAccount {}
export interface KernelConnectionMetadata {
name: string;
configurationEndpoints: DataModels.NotebookConfigurationEndpoints;
notebookConnectionInfo: DataModels.NotebookWorkspaceConnectionInfo;
}
export interface TokenProvider { export interface TokenProvider {
getAuthHeader(): Promise<Headers>; getAuthHeader(): Promise<Headers>;
@ -73,11 +50,6 @@ export interface WaitsForTemplate {
isTemplateReady: ko.Observable<boolean>; isTemplateReady: ko.Observable<boolean>;
} }
export interface AdHocAccessData {
readWriteUrl: string;
readUrl: string;
}
export interface TreeNode { export interface TreeNode {
nodeKind: string; nodeKind: string;
rid: string; rid: string;
@ -199,45 +171,6 @@ export interface Collection extends CollectionBase {
getLabel(): string; getLabel(): string;
} }
export interface DocumentId {
container: DocumentsTab;
rid: string;
self: string;
ts: string;
partitionKeyValue: any;
partitionKeyProperty: string;
partitionKey: DataModels.PartitionKey;
stringPartitionKeyValue: string;
id: ko.Observable<string>;
isDirty: ko.Observable<boolean>;
click(): void;
getPartitionKeyValueAsString(): string;
loadDocument(): Q.Promise<any>;
partitionKeyHeader(): Object;
}
export interface ConflictId {
container: ConflictsTab;
rid: string;
self: string;
ts: string;
partitionKeyValue: any;
partitionKeyProperty: string;
partitionKey: DataModels.PartitionKey;
stringPartitionKeyValue: string;
id: ko.Observable<string>;
operationType: string;
resourceId: string;
resourceType: string;
isDirty: ko.Observable<boolean>;
click(): void;
buildDocumentIdFromConflict(partitionKeyValue: any): DocumentId;
getPartitionKeyValueAsString(): string;
loadConflict(): Q.Promise<any>;
}
/** /**
* Options used to initialize pane * Options used to initialize pane
*/ */
@ -247,68 +180,6 @@ export interface PaneOptions {
container?: Explorer; container?: Explorer;
} }
export interface ContextualPane {
formErrors: ko.Observable<string>;
formErrorsDetails: ko.Observable<string>;
id: string;
title: ko.Observable<string>;
visible: ko.Observable<boolean>;
firstFieldHasFocus: ko.Observable<boolean>;
isExecuting: ko.Observable<boolean>;
submit: () => void;
cancel: () => void;
open: () => void;
close: () => void;
resetData: () => void;
showErrorDetails: () => void;
onCloseKeyPress(source: any, event: KeyboardEvent): void;
onPaneKeyDown(source: any, event: KeyboardEvent): boolean;
}
export interface GitHubReposPaneOptions extends PaneOptions {
gitHubClient: GitHubClient;
junoClient: JunoClient;
}
export interface PublishNotebookPaneOptions extends PaneOptions {
junoClient: JunoClient;
}
export interface PublishNotebookPaneOpenOptions {
name: string;
author: string;
content: string;
}
export interface AddCollectionPaneOptions extends PaneOptions {
isPreferredApiTable: ko.Computed<boolean>;
databaseId?: string;
databaseSelfLink?: string;
}
export interface UploadFilePaneOpenOptions {
paneTitle: string;
selectFileInputLabel: string;
errorMessage: string; // Could not upload notebook
inProgressMessage: string; // Uploading notebook
successMessage: string; // Successfully uploaded notebook
onSubmit: (file: File) => Promise<any>;
extensions?: string; // input accept field. E.g: .ipynb
submitButtonLabel?: string;
}
export interface StringInputPaneOpenOptions {
paneTitle: string;
inputLabel: string;
errorMessage: string;
inProgressMessage: string;
successMessage: string;
onSubmit: (input: string) => Promise<any>;
submitButtonLabel: string;
defaultInput?: string;
}
/** /**
* Graph configuration * Graph configuration
*/ */
@ -378,19 +249,6 @@ export interface DocumentRequestContainer {
resourceName?: string; resourceName?: string;
} }
export interface NotificationsClient {
fetchNotifications(): Q.Promise<DataModels.Notification[]>;
setExtensionEndpoint(extensionEndpoint: string): void;
}
export interface QueriesClient {
setupQueriesCollection(): Promise<DataModels.Collection>;
saveQuery(query: DataModels.Query): Promise<void>;
getQueries(): Promise<DataModels.Query[]>;
deleteQuery(query: DataModels.Query): Promise<void>;
getResourceId(): string;
}
export interface DocumentClientOption { export interface DocumentClientOption {
endpoint?: string; endpoint?: string;
masterKey?: string; masterKey?: string;
@ -405,7 +263,7 @@ export interface TabOptions {
selfLink: string; selfLink: string;
isActive: ko.Observable<boolean>; isActive: ko.Observable<boolean>;
hashLocation: string; hashLocation: string;
onUpdateTabsButtons: (buttons: NavbarButtonConfig[]) => void; onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]) => void;
isTabsContentExpanded?: ko.Observable<boolean>; isTabsContentExpanded?: ko.Observable<boolean>;
onLoadStartKey?: number; onLoadStartKey?: number;
@ -418,47 +276,6 @@ export interface TabOptions {
theme?: string; theme?: string;
} }
export interface SparkMasterTabOptions extends TabOptions {
clusterConnectionInfo: DataModels.SparkClusterConnectionInfo;
container: Explorer;
}
export interface GraphTabOptions extends TabOptions {
account: DatabaseAccount;
masterKey: string;
collectionId: string;
databaseId: string;
collectionPartitionKeyProperty: string;
}
export interface NotebookTabOptions extends TabOptions {
account: DatabaseAccount;
masterKey: string;
container: Explorer;
notebookContentItem: NotebookContentItem;
}
export interface TerminalTabOptions extends TabOptions {
account: DatabaseAccount;
container: Explorer;
kind: TerminalKind;
}
export interface GalleryTabOptions extends TabOptions {
account: DatabaseAccount;
container: Explorer;
junoClient: JunoClient;
notebookUrl?: string;
galleryItem?: IGalleryItem;
isFavorite?: boolean;
}
export interface NotebookViewerTabOptions extends TabOptions {
account: DatabaseAccount;
container: Explorer;
notebookUrl: string;
}
export interface DocumentsTabOptions extends TabOptions { export interface DocumentsTabOptions extends TabOptions {
partitionKey: DataModels.PartitionKey; partitionKey: DataModels.PartitionKey;
documentIds: ko.ObservableArray<DocumentId>; documentIds: ko.ObservableArray<DocumentId>;
@ -486,155 +303,15 @@ export interface ScriptTabOption extends TabOptions {
partitionKey?: DataModels.PartitionKey; partitionKey?: DataModels.PartitionKey;
} }
// Tabs
export interface Tab {
node: TreeNode; // Can be null
collection: CollectionBase;
rid: string;
tabKind: CollectionTabKind;
tabId: string;
isActive: ko.Observable<boolean>;
isMouseOver: ko.Observable<boolean>;
tabPath: ko.Observable<string>;
tabTitle: ko.Observable<string>;
hashLocation: ko.Observable<string>;
closeTabButton: Button;
onCloseTabButtonClick(): void;
onTabClick(): Q.Promise<any>;
onKeyPressActivate(source: any, event: KeyboardEvent): void;
onKeyPressClose(source: any, event: KeyboardEvent): void;
onActivate(): Q.Promise<any>;
refresh(): void;
closeButtonTabIndex: ko.Computed<number>;
isExecutionError: ko.Observable<boolean>;
isExecuting: ko.Observable<boolean>;
}
export interface DocumentsTab extends Tab {
/* Documents Grid */
selectDocument(documentId: DocumentId): Q.Promise<any>;
selectedDocumentId: ko.Observable<DocumentId>;
selectedDocumentContent: Editable<any>;
onDocumentIdClick(documentId: DocumentId): Q.Promise<any>;
dataContentsGridScrollHeight: ko.Observable<string>;
accessibleDocumentList: AccessibleVerticalList;
documentContentsGridId: string;
partitionKey: DataModels.PartitionKey;
idHeader: string;
partitionKeyPropertyHeader: string;
partitionKeyProperty: string;
documentIds: ko.ObservableArray<DocumentId>;
/* Documents Filter */
filterContent: ko.Observable<string>;
appliedFilter: ko.Observable<string>;
lastFilterContents: ko.ObservableArray<string>;
isFilterExpanded: ko.Observable<boolean>;
applyFilterButton: Button;
onShowFilterClick(): Q.Promise<any>;
onHideFilterClick(): Q.Promise<any>;
onApplyFilterClick(): Q.Promise<any>;
/* Document Editor */
isEditorDirty: ko.Computed<boolean>;
editorState: ko.Observable<DocumentExplorerState>;
onValidDocumentEdit(content: any): Q.Promise<any>;
onInvalidDocumentEdit(content: any): Q.Promise<any>;
onNewDocumentClick(): Q.Promise<any>;
onSaveNewDocumentClick(): Q.Promise<any>;
onRevertNewDocumentClick(): Q.Promise<any>;
onSaveExisitingDocumentClick(): Q.Promise<any>;
onRevertExisitingDocumentClick(): Q.Promise<any>;
onDeleteExisitingDocumentClick(): Q.Promise<any>;
/* Errors */
displayedError: ko.Observable<string>;
initDocumentEditor(documentId: DocumentId, content: any): Q.Promise<any>;
loadNextPage(): Q.Promise<any>;
}
export interface WaitsForTemplate { export interface WaitsForTemplate {
isTemplateReady: ko.Observable<boolean>; isTemplateReady: ko.Observable<boolean>;
} }
export interface QueryTab extends Tab {
queryEditorId: string;
isQueryMetricsEnabled: ko.Computed<boolean>;
activityId: ko.Observable<string>;
/* Command Bar */
executeQueryButton: Button;
fetchNextPageButton: Button;
saveQueryButton: Button;
onExecuteQueryClick(): Q.Promise<any>;
onFetchNextPageClick(): Q.Promise<any>;
/*Query Editor*/
initialEditorContent: ko.Observable<string>;
sqlQueryEditorContent: ko.Observable<string>;
sqlStatementToExecute: ko.Observable<string>;
/* Results */
allResultsMetadata: ko.ObservableArray<QueryResultsMetadata>;
/* Errors */
errors: ko.ObservableArray<QueryError>;
/* Status */
statusMessge: ko.Observable<string>;
statusIcon: ko.Observable<string>;
}
export interface ScriptTab extends Tab {
id: Editable<string>;
editorId: string;
saveButton: Button;
updateButton: Button;
discardButton: Button;
deleteButton: Button;
editorState: ko.Observable<ScriptEditorState>;
editorContent: ko.Observable<string>;
editor: ko.Observable<monaco.editor.IStandaloneCodeEditor>;
errors: ko.ObservableArray<QueryError>;
statusMessge: ko.Observable<string>;
statusIcon: ko.Observable<string>;
formFields: ko.ObservableArray<Editable<any>>;
formIsValid: ko.Computed<boolean>;
formIsDirty: ko.Computed<boolean>;
isNew: ko.Observable<boolean>;
resource: ko.Observable<DataModels.Resource>;
setBaselines(): void;
}
export interface StoredProcedureTab extends ScriptTab {
onExecuteSprocsResult(result: any, logsData: any): void;
onExecuteSprocsError(error: string): void;
}
export interface UserDefinedFunctionTab extends ScriptTab {}
export interface TriggerTab extends ScriptTab {
triggerType: Editable<string>;
triggerOperation: Editable<string>;
}
export interface GraphTab extends Tab {}
export interface EditorPosition { export interface EditorPosition {
line: number; line: number;
column: number; column: number;
} }
export interface MongoShellTab extends Tab {}
export enum DocumentExplorerState { export enum DocumentExplorerState {
noDocumentSelected, noDocumentSelected,
newDocumentValid, newDocumentValid,
@ -752,40 +429,8 @@ export interface AuthorizationTokenHeaderMetadata {
token: string; token: string;
} }
export interface TelemetryActions {
sendEvent(name: string, telemetryProperties?: { [propertyName: string]: string }): Q.Promise<any>;
sendError(errorInfo: DataModels.ITelemetryError): Q.Promise<any>;
sendMetric(
name: string,
metricNumber: number,
telemetryProperties?: { [propertyName: string]: string }
): Q.Promise<any>;
}
export interface ConfigurationOverrides {
EnableBsonSchema: string;
}
export interface CosmosDbApi {
isSystemDatabasePredicate: (database: Database) => boolean;
}
export interface DropdownOption<T> { export interface DropdownOption<T> {
text: string; text: string;
value: T; value: T;
disable?: boolean; disable?: boolean;
} }
export interface INotebookContainerClient {
resetWorkspace: () => Promise<void>;
}
export interface INotebookContentClient {
updateItemChildren: (item: NotebookContentItem) => Promise<void>;
createNewNotebookFile: (parent: NotebookContentItem) => Promise<NotebookContentItem>;
deleteContentItem: (item: NotebookContentItem) => Promise<void>;
uploadFileAsync: (name: string, content: string, parent: NotebookContentItem) => Promise<NotebookContentItem>;
renameNotebook: (item: NotebookContentItem, targetName: string) => Promise<NotebookContentItem>;
createDirectory: (parent: NotebookContentItem, newDirectoryName: string) => Promise<NotebookContentItem>;
readFileContent: (filePath: string) => Promise<string>;
}

View File

@ -13,9 +13,7 @@ import { NewVertexComponent } from "./Graph/NewVertexComponent/NewVertexComponen
import { TabsManagerKOComponent } from "./Tabs/TabsManager"; import { TabsManagerKOComponent } from "./Tabs/TabsManager";
import { ThroughputInputComponent } from "./Controls/ThroughputInput/ThroughputInputComponent"; import { ThroughputInputComponent } from "./Controls/ThroughputInput/ThroughputInputComponent";
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3"; import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
import { ToolbarComponent } from "./Controls/Toolbar/Toolbar";
ko.components.register("toolbar", new ToolbarComponent());
ko.components.register("input-typeahead", new InputTypeaheadComponent()); ko.components.register("input-typeahead", new InputTypeaheadComponent());
ko.components.register("new-vertex-form", NewVertexComponent); ko.components.register("new-vertex-form", NewVertexComponent);
ko.components.register("error-display", new ErrorDisplayComponent()); ko.components.register("error-display", new ErrorDisplayComponent());

View File

@ -27,9 +27,10 @@ import { TextField, ITextFieldProps, ITextField } from "office-ui-fabric-react/l
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import SaveQueryBannerIcon from "../../../../images/save_query_banner.png"; import SaveQueryBannerIcon from "../../../../images/save_query_banner.png";
import { QueriesClient } from "../../../Common/QueriesClient";
export interface QueriesGridComponentProps { export interface QueriesGridComponentProps {
queriesClient: ViewModels.QueriesClient; queriesClient: QueriesClient;
onQuerySelect: (query: DataModels.Query) => void; onQuerySelect: (query: DataModels.Query) => void;
containerVisible: boolean; containerVisible: boolean;
saveQueryEnabled: boolean; saveQueryEnabled: boolean;

View File

@ -1,12 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import IToolbarDisplayable from "./IToolbarDisplayable";
interface IToolbarAction extends IToolbarDisplayable {
type: "action";
action: () => void;
}
export default IToolbarAction;

View File

@ -1,18 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
interface IToolbarDisplayable {
id: string;
title: ko.Subscribable<string>;
displayName: ko.Subscribable<string>;
enabled: ko.Subscribable<boolean>;
visible: ko.Observable<boolean>;
focused: ko.Observable<boolean>;
icon: string;
mouseDown: (data: any, event: MouseEvent) => any;
keyUp: (data: any, event: KeyboardEvent) => any;
keyDown: (data: any, event: KeyboardEvent) => any;
}
export default IToolbarDisplayable;

View File

@ -1,56 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import IToolbarDisplayable from "./IToolbarDisplayable";
interface IToolbarDropDown extends IToolbarDisplayable {
type: "dropdown";
subgroup: IActionConfigItem[];
expanded: ko.Observable<boolean>;
open: () => void;
}
export interface IDropdown {
type: "dropdown";
title: string;
displayName: string;
id: string;
enabled: ko.Observable<boolean>;
visible?: ko.Observable<boolean>;
icon?: string;
subgroup?: IActionConfigItem[];
}
export interface ISeperator {
type: "separator";
visible?: ko.Observable<boolean>;
}
export interface IToggle {
type: "toggle";
title: string;
displayName: string;
checkedTitle: string;
checkedDisplayName: string;
id: string;
checked: ko.Observable<boolean>;
enabled: ko.Observable<boolean>;
visible?: ko.Observable<boolean>;
icon?: string;
}
export interface IAction {
type: "action";
title: string;
displayName: string;
id: string;
action: () => any;
enabled: ko.Subscribable<boolean>;
visible?: ko.Observable<boolean>;
icon?: string;
}
export type IActionConfigItem = ISeperator | IAction | IToggle | IDropdown;
export default IToolbarDropDown;

View File

@ -1,12 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import IToolbarAction from "./IToolbarAction";
import IToolbarToggle from "./IToolbarToggle";
import IToolbarSeperator from "./IToolbarSeperator";
import IToolbarDropDown from "./IToolbarDropDown";
type IToolbarItem = IToolbarAction | IToolbarToggle | IToolbarSeperator | IToolbarDropDown;
export default IToolbarItem;

View File

@ -1,10 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
interface IToolbarSeperator {
type: "separator";
visible: ko.Observable<boolean>;
}
export default IToolbarSeperator;

View File

@ -1,12 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import IToolbarDisplayable from "./IToolbarDisplayable";
interface IToolbarToggle extends IToolbarDisplayable {
type: "toggle";
checked: ko.Observable<boolean>;
toggle: () => void;
}
export default IToolbarToggle;

View File

@ -1,58 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
var keyCodes = {
RightClick: 3,
Enter: 13,
Esc: 27,
Tab: 9,
LeftArrow: 37,
UpArrow: 38,
RightArrow: 39,
DownArrow: 40,
Delete: 46,
A: 65,
B: 66,
C: 67,
D: 68,
E: 69,
F: 70,
G: 71,
H: 72,
I: 73,
J: 74,
K: 75,
L: 76,
M: 77,
N: 78,
O: 79,
P: 80,
Q: 81,
R: 82,
S: 83,
T: 84,
U: 85,
V: 86,
W: 87,
X: 88,
Y: 89,
Z: 90,
Period: 190,
DecimalPoint: 110,
F1: 112,
F2: 113,
F3: 114,
F4: 115,
F5: 116,
F6: 117,
F7: 118,
F8: 119,
F9: 120,
F10: 121,
F11: 122,
F12: 123,
Dash: 189
};
export default keyCodes;

View File

@ -1,145 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import { IDropdown } from "./IToolbarDropDown";
import { IActionConfigItem } from "./IToolbarDropDown";
import IToolbarItem from "./IToolbarItem";
import * as ko from "knockout";
import ToolbarDropDown from "./ToolbarDropDown";
import ToolbarAction from "./ToolbarAction";
import ToolbarToggle from "./ToolbarToggle";
import template from "./toolbar.html";
export default class Toolbar {
private _toolbarWidth = ko.observable<number>();
private _actionConfigs: IActionConfigItem[];
private _afterExecute: (id: string) => void;
private _hasFocus: boolean = false;
private _focusedSubscription: ko.Subscription;
constructor(actionItems: IActionConfigItem[], afterExecute?: (id: string) => void) {
this._actionConfigs = actionItems;
this._afterExecute = afterExecute;
this.toolbarItems.subscribe(this._focusFirstEnabledItem);
$(window).resize(() => {
this._toolbarWidth($(".toolbar").width());
});
setTimeout(() => {
this._toolbarWidth($(".toolbar").width());
}, 500);
}
public toolbarItems: ko.PureComputed<IToolbarItem[]> = ko.pureComputed(() => {
var remainingToolbarSpace = this._toolbarWidth();
var toolbarItems: IToolbarItem[] = [];
var moreItem: IDropdown = {
type: "dropdown",
title: "More",
displayName: "More",
id: "more-actions-toggle",
enabled: ko.observable(true),
visible: ko.observable(true),
icon: "images/ASX_More.svg",
subgroup: []
};
var showHasMoreItem = false;
var addSeparator = false;
this._actionConfigs.forEach(actionConfig => {
if (actionConfig.type === "separator") {
addSeparator = true;
} else if (remainingToolbarSpace / 60 > 2) {
if (addSeparator) {
addSeparator = false;
toolbarItems.push(Toolbar._createToolbarItemFromConfig({ type: "separator" }));
remainingToolbarSpace -= 10;
}
toolbarItems.push(Toolbar._createToolbarItemFromConfig(actionConfig));
remainingToolbarSpace -= 60;
} else {
showHasMoreItem = true;
if (addSeparator) {
addSeparator = false;
moreItem.subgroup.push({
type: "separator"
});
}
if (!!actionConfig) {
moreItem.subgroup.push(actionConfig);
}
}
});
if (showHasMoreItem) {
toolbarItems.push(
Toolbar._createToolbarItemFromConfig({ type: "separator" }),
Toolbar._createToolbarItemFromConfig(moreItem)
);
}
return toolbarItems;
});
public focus() {
this._hasFocus = true;
this._focusFirstEnabledItem(this.toolbarItems());
}
private _focusFirstEnabledItem = (items: IToolbarItem[]) => {
if (!!this._focusedSubscription) {
// no memory leaks! :D
this._focusedSubscription.dispose();
}
if (this._hasFocus) {
for (var i = 0; i < items.length; i++) {
if (items[i].type !== "separator" && (<any>items[i]).enabled()) {
(<any>items[i]).focused(true);
this._focusedSubscription = (<any>items[i]).focused.subscribe((newValue: any) => {
if (!newValue) {
this._hasFocus = false;
this._focusedSubscription.dispose();
}
});
break;
}
}
}
};
private static _createToolbarItemFromConfig(
configItem: IActionConfigItem,
afterExecute?: (id: string) => void
): IToolbarItem {
switch (configItem.type) {
case "dropdown":
return new ToolbarDropDown(configItem, afterExecute);
case "action":
return new ToolbarAction(configItem, afterExecute);
case "toggle":
return new ToolbarToggle(configItem, afterExecute);
case "separator":
return {
type: "separator",
visible: ko.observable(true)
};
}
}
}
/**
* Helper class for ko component registration
*/
export class ToolbarComponent {
constructor() {
return {
viewModel: Toolbar,
template
};
}
}

View File

@ -1,86 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import * as ko from "knockout";
import { IAction } from "./IToolbarDropDown";
import IToolbarAction from "./IToolbarAction";
import KeyCodes from "./KeyCodes";
import Utilities from "./Utilities";
export default class ToolbarAction implements IToolbarAction {
public type: "action" = "action";
public id: string;
public icon: string;
public title: ko.Observable<string>;
public displayName: ko.Observable<string>;
public enabled: ko.Subscribable<boolean>;
public visible: ko.Observable<boolean>;
public focused: ko.Observable<boolean>;
public action: () => void;
private _afterExecute: (id: string) => void;
constructor(actionItem: IAction, afterExecute?: (id: string) => void) {
this.action = actionItem.action;
this.title = ko.observable(actionItem.title);
this.displayName = ko.observable(actionItem.displayName);
this.id = actionItem.id;
this.enabled = actionItem.enabled;
this.visible = actionItem.visible ? actionItem.visible : ko.observable(true);
this.focused = ko.observable(false);
this.icon = actionItem.icon;
this._afterExecute = afterExecute;
}
private _executeAction = () => {
this.action();
if (!!this._afterExecute) {
this._afterExecute(this.id);
}
};
public mouseDown = (data: any, event: MouseEvent): boolean => {
this._executeAction();
return false;
};
public keyUp = (data: any, event: KeyboardEvent): boolean => {
var handled: boolean = false;
handled = Utilities.onEnter(event, ($sourceElement: JQuery) => {
this._executeAction();
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
return true;
});
return !handled;
};
public keyDown = (data: any, event: KeyboardEvent): boolean => {
var handled: boolean = false;
handled = Utilities.onEnter(event, ($sourceElement: JQuery) => {
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
return true;
});
if (!handled) {
// Reset color if [shift-] tabbing, 'up/down arrowing', or 'esc'-aping away from button while holding down 'enter'
Utilities.onKeys(
event,
[KeyCodes.Tab, KeyCodes.UpArrow, KeyCodes.DownArrow, KeyCodes.Esc],
($sourceElement: JQuery) => {
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
}
);
}
return !handled;
};
}

View File

@ -1,167 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import * as ko from "knockout";
import { IDropdown } from "./IToolbarDropDown";
import { IActionConfigItem } from "./IToolbarDropDown";
import IToolbarDropDown from "./IToolbarDropDown";
import KeyCodes from "./KeyCodes";
import Utilities from "./Utilities";
interface IMenuItem {
id?: string;
type: "normal" | "separator" | "submenu";
label?: string;
enabled?: boolean;
visible?: boolean;
submenu?: IMenuItem[];
}
export default class ToolbarDropDown implements IToolbarDropDown {
public type: "dropdown" = "dropdown";
public title: ko.Observable<string>;
public displayName: ko.Observable<string>;
public id: string;
public enabled: ko.Observable<boolean>;
public visible: ko.Observable<boolean>;
public focused: ko.Observable<boolean>;
public icon: string;
public subgroup: IActionConfigItem[] = [];
public expanded: ko.Observable<boolean> = ko.observable(false);
private _afterExecute: (id: string) => void;
constructor(dropdown: IDropdown, afterExecute?: (id: string) => void) {
this.subgroup = dropdown.subgroup;
this.title = ko.observable(dropdown.title);
this.displayName = ko.observable(dropdown.displayName);
this.id = dropdown.id;
this.enabled = dropdown.enabled;
this.visible = dropdown.visible ? dropdown.visible : ko.observable(true);
this.focused = ko.observable(false);
this.icon = dropdown.icon;
this._afterExecute = afterExecute;
}
private static _convertToMenuItem = (
actionConfigs: IActionConfigItem[],
actionMap: { [id: string]: () => void } = {}
): { menuItems: IMenuItem[]; actionMap: { [id: string]: () => void } } => {
var returnValue = {
menuItems: actionConfigs.map<IMenuItem>((actionConfig: IActionConfigItem, index, array) => {
var menuItem: IMenuItem;
switch (actionConfig.type) {
case "action":
menuItem = <IMenuItem>{
id: actionConfig.id,
type: "normal",
label: actionConfig.displayName,
enabled: actionConfig.enabled(),
visible: actionConfig.visible ? actionConfig.visible() : true
};
actionMap[actionConfig.id] = actionConfig.action;
break;
case "dropdown":
menuItem = <IMenuItem>{
id: actionConfig.id,
type: "submenu",
label: actionConfig.displayName,
enabled: actionConfig.enabled(),
visible: actionConfig.visible ? actionConfig.visible() : true,
submenu: ToolbarDropDown._convertToMenuItem(actionConfig.subgroup, actionMap).menuItems
};
break;
case "toggle":
menuItem = <IMenuItem>{
id: actionConfig.id,
type: "normal",
label: actionConfig.checked() ? actionConfig.checkedDisplayName : actionConfig.displayName,
enabled: actionConfig.enabled(),
visible: actionConfig.visible ? actionConfig.visible() : true
};
actionMap[actionConfig.id] = () => {
actionConfig.checked(!actionConfig.checked());
};
break;
case "separator":
menuItem = <IMenuItem>{
type: "separator",
visible: true
};
break;
}
return menuItem;
}),
actionMap: actionMap
};
return returnValue;
};
public open = () => {
if (!!(<any>window).host) {
var convertedMenuItem = ToolbarDropDown._convertToMenuItem(this.subgroup);
(<any>window).host
.executeProviderOperation("MenuManager.showMenu", {
iFrameStack: [`#${window.frameElement.id}`],
anchor: `#${this.id}`,
menuItems: convertedMenuItem.menuItems
})
.then((id?: string) => {
if (!!id && !!convertedMenuItem.actionMap[id]) {
convertedMenuItem.actionMap[id]();
}
});
if (!!this._afterExecute) {
this._afterExecute(this.id);
}
}
};
public mouseDown = (data: any, event: MouseEvent): boolean => {
this.open();
return false;
};
public keyUp = (data: any, event: KeyboardEvent): boolean => {
var handled: boolean = false;
handled = Utilities.onEnter(event, ($sourceElement: JQuery) => {
this.open();
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
return true;
});
return !handled;
};
public keyDown = (data: any, event: KeyboardEvent): boolean => {
var handled: boolean = false;
handled = Utilities.onEnter(event, ($sourceElement: JQuery) => {
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
return true;
});
if (!handled) {
// Reset color if [shift-] tabbing, 'up/down arrowing', or 'esc'-aping away from button while holding down 'enter'
Utilities.onKeys(
event,
[KeyCodes.Tab, KeyCodes.UpArrow, KeyCodes.DownArrow, KeyCodes.Esc],
($sourceElement: JQuery) => {
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
}
);
}
return !handled;
};
}

View File

@ -1,109 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import * as ko from "knockout";
import { IToggle } from "./IToolbarDropDown";
import IToolbarToggle from "./IToolbarToggle";
import KeyCodes from "./KeyCodes";
import Utilities from "./Utilities";
export default class ToolbarToggle implements IToolbarToggle {
public type: "toggle" = "toggle";
public checked: ko.Observable<boolean>;
public id: string;
public enabled: ko.Observable<boolean>;
public visible: ko.Observable<boolean>;
public focused: ko.Observable<boolean>;
public icon: string;
private _title: string;
private _displayName: string;
private _checkedTitle: string;
private _checkedDisplayName: string;
private _afterExecute: (id: string) => void;
constructor(toggleItem: IToggle, afterExecute?: (id: string) => void) {
this._title = toggleItem.title;
this._displayName = toggleItem.displayName;
this.id = toggleItem.id;
this.enabled = toggleItem.enabled;
this.visible = toggleItem.visible ? toggleItem.visible : ko.observable(true);
this.focused = ko.observable(false);
this.icon = toggleItem.icon;
this.checked = toggleItem.checked;
this._checkedTitle = toggleItem.checkedTitle;
this._checkedDisplayName = toggleItem.checkedDisplayName;
this._afterExecute = afterExecute;
}
public title = ko.pureComputed(() => {
if (this.checked()) {
return this._checkedTitle;
} else {
return this._title;
}
});
public displayName = ko.pureComputed(() => {
if (this.checked()) {
return this._checkedDisplayName;
} else {
return this._displayName;
}
});
public toggle = () => {
this.checked(!this.checked());
if (this.checked() && !!this._afterExecute) {
this._afterExecute(this.id);
}
};
public mouseDown = (data: any, event: MouseEvent): boolean => {
this.toggle();
return false;
};
public keyUp = (data: any, event: KeyboardEvent): boolean => {
var handled: boolean = false;
handled = Utilities.onEnter(event, ($sourceElement: JQuery) => {
this.toggle();
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
return true;
});
return !handled;
};
public keyDown = (data: any, event: KeyboardEvent): boolean => {
var handled: boolean = false;
handled = Utilities.onEnter(event, ($sourceElement: JQuery) => {
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
return true;
});
if (!handled) {
// Reset color if [shift-] tabbing, 'up/down arrowing', or 'esc'-aping away from button while holding down 'enter'
Utilities.onKeys(
event,
[KeyCodes.Tab, KeyCodes.UpArrow, KeyCodes.DownArrow, KeyCodes.Esc],
($sourceElement: JQuery) => {
if ($sourceElement.hasClass("active")) {
$sourceElement.removeClass("active");
}
}
);
}
return !handled;
};
}

View File

@ -1,166 +0,0 @@
/*!---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*----------------------------------------------------------*/
import KeyCodes from "./KeyCodes";
export default class Utilities {
/**
* Executes an action on a keyboard event.
* Modifiers: ctrlKey - control/command key, shiftKey - shift key, altKey - alt/option key;
* pass on 'null' to ignore the modifier (default).
*/
public static onKey(
event: any,
eventKeyCode: number,
action: ($sourceElement: JQuery) => void,
metaKey: boolean = null,
shiftKey: boolean = null,
altKey: boolean = null
): boolean {
var source: any = event.target || event.srcElement,
keyCode: number = event.keyCode,
$sourceElement = $(source),
handled: boolean = false;
if (
$sourceElement.length &&
keyCode === eventKeyCode &&
$.isFunction(action) &&
(metaKey === null || metaKey === event.metaKey) &&
(shiftKey === null || shiftKey === event.shiftKey) &&
(altKey === null || altKey === event.altKey)
) {
action($sourceElement);
handled = true;
}
return handled;
}
/**
* Executes an action on the first matched keyboard event.
*/
public static onKeys(
event: any,
eventKeyCodes: number[],
action: ($sourceElement: JQuery) => void,
metaKey: boolean = null,
shiftKey: boolean = null,
altKey: boolean = null
): boolean {
var handled: boolean = false,
keyCount: number,
i: number;
if ($.isArray(eventKeyCodes)) {
keyCount = eventKeyCodes.length;
for (i = 0; i < keyCount; ++i) {
handled = Utilities.onKey(event, eventKeyCodes[i], action, metaKey, shiftKey, altKey);
if (handled) {
break;
}
}
}
return handled;
}
/**
* Executes an action on an 'enter' keyboard event.
*/
public static onEnter(
event: any,
action: ($sourceElement: JQuery) => void,
metaKey: boolean = null,
shiftKey: boolean = null,
altKey: boolean = null
): boolean {
return Utilities.onKey(event, KeyCodes.Enter, action, metaKey, shiftKey, altKey);
}
/**
* Executes an action on a 'tab' keyboard event.
*/
public static onTab(
event: any,
action: ($sourceElement: JQuery) => void,
metaKey: boolean = null,
shiftKey: boolean = null,
altKey: boolean = null
): boolean {
return Utilities.onKey(event, KeyCodes.Tab, action, metaKey, shiftKey, altKey);
}
/**
* Executes an action on an 'Esc' keyboard event.
*/
public static onEsc(
event: any,
action: ($sourceElement: JQuery) => void,
metaKey: boolean = null,
shiftKey: boolean = null,
altKey: boolean = null
): boolean {
return Utilities.onKey(event, KeyCodes.Esc, action, metaKey, shiftKey, altKey);
}
/**
* Executes an action on an 'UpArrow' keyboard event.
*/
public static onUpArrow(
event: any,
action: ($sourceElement: JQuery) => void,
metaKey: boolean = null,
shiftKey: boolean = null,
altKey: boolean = null
): boolean {
return Utilities.onKey(event, KeyCodes.UpArrow, action, metaKey, shiftKey, altKey);
}
/**
* Executes an action on a 'DownArrow' keyboard event.
*/
public static onDownArrow(
event: any,
action: ($sourceElement: JQuery) => void,
metaKey: boolean = null,
shiftKey: boolean = null,
altKey: boolean = null
): boolean {
return Utilities.onKey(event, KeyCodes.DownArrow, action, metaKey, shiftKey, altKey);
}
/**
* Executes an action on a mouse event.
*/
public static onButton(event: any, eventButtonCode: number, action: ($sourceElement: JQuery) => void): boolean {
var source: any = event.currentTarget;
var buttonCode: number = event.button;
var $sourceElement = $(source);
var handled: boolean = false;
if ($sourceElement.length && buttonCode === eventButtonCode && $.isFunction(action)) {
action($sourceElement);
handled = true;
}
return handled;
}
/**
* Executes an action on a 'left' mouse event.
*/
public static onLeftButton(event: any, action: ($sourceElement: JQuery) => void): boolean {
return Utilities.onButton(event, buttonCodes.Left, action);
}
}
var buttonCodes = {
None: -1,
Left: 0,
Middle: 1,
Right: 2
};

View File

@ -1,44 +0,0 @@
<div class="toolbar">
<!-- ko template: { name: 'toolbarItemTemplate', foreach: toolbarItems } -->
<!-- /ko -->
</div>
<script type="text/html" id="toolbarItemTemplate">
<!-- ko if: type === "action" -->
<div class="toolbar-group" data-bind="visible: visible">
<button class="toolbar-group-button" data-bind="hasFocus: focused, attr: {id: id, title: title, 'aria-label': displayName}, event: { mousedown: mouseDown, keydown: keyDown, keyup: keyUp }, enable: enabled">
<div class="toolbar-group-button-icon">
<div class="toolbar_icon" data-bind="icon: icon"></div>
</div>
<span data-bind="text: displayName"></span>
</button>
</div>
<!-- /ko -->
<!-- ko if: type === "toggle" -->
<div class="toolbar-group" data-bind="visible: visible">
<button class="toolbar-group-button toggle-button" data-bind="hasFocus: focused, attr: {id: id, title: title}, event: { mousedown: mouseDown, keydown: keyDown, keyup: keyUp }, enable: enabled">
<div class="toolbar-group-button-icon" data-bind="css: { 'toggle-checked': checked }">
<div class="toolbar_icon" data-bind="icon: icon"></div>
</div>
<span data-bind="text: displayName"></span>
</button>
</div>
<!-- /ko -->
<!-- ko if: type === "dropdown" -->
<div class="toolbar-group" data-bind="visible: visible">
<div class="dropdown" data-bind="attr: {id: (id + '-dropdown')}">
<button role="menu" class="toolbar-group-button" data-bind="hasFocus: focused, attr: {id: id, title: title, 'aria-label': displayName}, event: { mousedown: mouseDown, keydown: keyDown, keyup: keyUp }, enable: enabled">
<div class="toolbar-group-button-icon">
<div class="toolbar_icon" data-bind="icon: icon"></div>
</div>
<span data-bind="text: displayName"></span>
</button>
</div>
</div>
<!-- /ko -->
<!-- ko if: type === "separator" -->
<div class="toolbar-group vertical-separator" data-bind="visible: visible"></div>
<!-- /ko -->
</script>

View File

@ -21,7 +21,7 @@ import EnvironmentUtility from "../Common/EnvironmentUtility";
import GraphStylingPane from "./Panes/GraphStylingPane"; import GraphStylingPane from "./Panes/GraphStylingPane";
import hasher from "hasher"; import hasher from "hasher";
import NewVertexPane from "./Panes/NewVertexPane"; import NewVertexPane from "./Panes/NewVertexPane";
import NotebookV2Tab from "./Tabs/NotebookV2Tab"; import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
import Q from "q"; import Q from "q";
import ResourceTokenCollection from "./Tree/ResourceTokenCollection"; import ResourceTokenCollection from "./Tree/ResourceTokenCollection";
import TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
@ -33,7 +33,6 @@ import { ArcadiaWorkspaceItem } from "./Controls/Arcadia/ArcadiaMenuPicker";
import { AuthType } from "../AuthType"; import { AuthType } from "../AuthType";
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer"; import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
import { BrowseQueriesPane } from "./Panes/BrowseQueriesPane"; import { BrowseQueriesPane } from "./Panes/BrowseQueriesPane";
import { CassandraApi } from "../Api/Apis";
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient"; import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
import { CommandBarComponentAdapter } from "./Menus/CommandBar/CommandBarComponentAdapter"; import { CommandBarComponentAdapter } from "./Menus/CommandBar/CommandBarComponentAdapter";
import { config } from "../Config"; import { config } from "../Config";
@ -82,6 +81,10 @@ import { toRawContentUri, fromContentUri } from "../Utils/GitHubUtils";
import UserDefinedFunction from "./Tree/UserDefinedFunction"; import UserDefinedFunction from "./Tree/UserDefinedFunction";
import StoredProcedure from "./Tree/StoredProcedure"; import StoredProcedure from "./Tree/StoredProcedure";
import Trigger from "./Tree/Trigger"; import Trigger from "./Tree/Trigger";
import { NotificationsClientBase } from "../Common/NotificationsClientBase";
import { ContextualPaneBase } from "./Panes/ContextualPaneBase";
import TabsBase from "./Tabs/TabsBase";
import { CommandButtonComponentProps } from "./Controls/CommandButton/CommandButtonComponent";
BindingHandlersRegisterer.registerBindingHandlers(); BindingHandlersRegisterer.registerBindingHandlers();
// Hold a reference to ComponentRegisterer to prevent transpiler to ignore import // Hold a reference to ComponentRegisterer to prevent transpiler to ignore import
@ -92,6 +95,15 @@ enum ShareAccessToggleState {
Read Read
} }
interface ExplorerOptions {
notificationsClient: NotificationsClientBase;
isEmulator: boolean;
}
interface AdHocAccessData {
readWriteUrl: string;
readUrl: string;
}
export default class Explorer { export default class Explorer {
public flight: ko.Observable<string> = ko.observable<string>( public flight: ko.Observable<string> = ko.observable<string>(
SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight
@ -107,7 +119,7 @@ export default class Explorer {
public hasWriteAccess: ko.Observable<boolean>; public hasWriteAccess: ko.Observable<boolean>;
public collapsedResourceTreeWidth: number = ExplorerMetrics.CollapsedResourceTreeWidth; public collapsedResourceTreeWidth: number = ExplorerMetrics.CollapsedResourceTreeWidth;
public databaseAccount: ko.Observable<ViewModels.DatabaseAccount>; public databaseAccount: ko.Observable<DataModels.DatabaseAccount>;
public collectionCreationDefaults: ViewModels.CollectionCreationDefaults = SharedConstants.CollectionCreationDefaults; public collectionCreationDefaults: ViewModels.CollectionCreationDefaults = SharedConstants.CollectionCreationDefaults;
public subscriptionType: ko.Observable<ViewModels.SubscriptionType>; public subscriptionType: ko.Observable<ViewModels.SubscriptionType>;
public quotaId: ko.Observable<string>; public quotaId: ko.Observable<string>;
@ -127,8 +139,8 @@ export default class Explorer {
public extensionEndpoint: ko.Observable<string>; public extensionEndpoint: ko.Observable<string>;
public armEndpoint: ko.Observable<string>; public armEndpoint: ko.Observable<string>;
public isTryCosmosDBSubscription: ko.Observable<boolean>; public isTryCosmosDBSubscription: ko.Observable<boolean>;
public notificationsClient: ViewModels.NotificationsClient; public notificationsClient: NotificationsClientBase;
public queriesClient: ViewModels.QueriesClient; public queriesClient: QueriesClient;
public tableDataClient: TableDataClient; public tableDataClient: TableDataClient;
public splitter: Splitter; public splitter: Splitter;
public parentFrameDataExplorerVersion: ko.Observable<string> = ko.observable<string>(""); public parentFrameDataExplorerVersion: ko.Observable<string> = ko.observable<string>("");
@ -139,7 +151,7 @@ export default class Explorer {
public isNotificationConsoleExpanded: ko.Observable<boolean>; public isNotificationConsoleExpanded: ko.Observable<boolean>;
// Panes // Panes
public contextPanes: ViewModels.ContextualPane[]; public contextPanes: ContextualPaneBase[];
// Resource Tree // Resource Tree
public databases: ko.ObservableArray<ViewModels.Database>; public databases: ko.ObservableArray<ViewModels.Database>;
@ -184,12 +196,12 @@ export default class Explorer {
public uploadItemsPane: UploadItemsPane; public uploadItemsPane: UploadItemsPane;
public uploadItemsPaneAdapter: UploadItemsPaneAdapter; public uploadItemsPaneAdapter: UploadItemsPaneAdapter;
public loadQueryPane: LoadQueryPane; public loadQueryPane: LoadQueryPane;
public saveQueryPane: ViewModels.ContextualPane; public saveQueryPane: ContextualPaneBase;
public browseQueriesPane: BrowseQueriesPane; public browseQueriesPane: BrowseQueriesPane;
public uploadFilePane: UploadFilePane; public uploadFilePane: UploadFilePane;
public stringInputPane: StringInputPane; public stringInputPane: StringInputPane;
public setupNotebooksPane: SetupNotebooksPane; public setupNotebooksPane: SetupNotebooksPane;
public gitHubReposPane: ViewModels.ContextualPane; public gitHubReposPane: ContextualPaneBase;
public publishNotebookPaneAdapter: ReactAdapter; public publishNotebookPaneAdapter: ReactAdapter;
// features // features
@ -202,7 +214,7 @@ export default class Explorer {
public hasAutoPilotV2FeatureFlag: ko.Computed<boolean>; public hasAutoPilotV2FeatureFlag: ko.Computed<boolean>;
public shouldShowShareDialogContents: ko.Observable<boolean>; public shouldShowShareDialogContents: ko.Observable<boolean>;
public shareAccessData: ko.Observable<ViewModels.AdHocAccessData>; public shareAccessData: ko.Observable<AdHocAccessData>;
public renewExplorerShareAccess: (explorer: Explorer, token: string) => Q.Promise<void>; public renewExplorerShareAccess: (explorer: Explorer, token: string) => Q.Promise<void>;
public renewTokenError: ko.Observable<string>; public renewTokenError: ko.Observable<string>;
public tokenForRenewal: ko.Observable<string>; public tokenForRenewal: ko.Observable<string>;
@ -228,7 +240,7 @@ export default class Explorer {
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>; public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
public notebookManager?: any; // This is dynamically loaded public notebookManager?: any; // This is dynamically loaded
private _panes: ViewModels.ContextualPane[] = []; private _panes: ContextualPaneBase[] = [];
private _importExplorerConfigComplete: boolean = false; private _importExplorerConfigComplete: boolean = false;
private _isSystemDatabasePredicate: (database: ViewModels.Database) => boolean = database => false; private _isSystemDatabasePredicate: (database: ViewModels.Database) => boolean = database => false;
private _isInitializingNotebooks: boolean; private _isInitializingNotebooks: boolean;
@ -251,7 +263,7 @@ export default class Explorer {
private static readonly MaxNbDatabasesToAutoExpand = 5; private static readonly MaxNbDatabasesToAutoExpand = 5;
constructor(options: ViewModels.ExplorerOptions) { constructor(options: ExplorerOptions) {
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, { const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
dataExplorerArea: Constants.Areas.ResourceTree dataExplorerArea: Constants.Areas.ResourceTree
}); });
@ -264,7 +276,7 @@ export default class Explorer {
this.deleteDatabaseText = ko.observable<string>("Delete Database"); this.deleteDatabaseText = ko.observable<string>("Delete Database");
this.refreshTreeTitle = ko.observable<string>("Refresh collections"); this.refreshTreeTitle = ko.observable<string>("Refresh collections");
this.databaseAccount = ko.observable<ViewModels.DatabaseAccount>(); this.databaseAccount = ko.observable<DataModels.DatabaseAccount>();
this.subscriptionType = ko.observable<ViewModels.SubscriptionType>( this.subscriptionType = ko.observable<ViewModels.SubscriptionType>(
SharedConstants.CollectionCreation.DefaultSubscriptionType SharedConstants.CollectionCreation.DefaultSubscriptionType
); );
@ -373,7 +385,7 @@ export default class Explorer {
this.resourceTokenPartitionKey = ko.observable<string>(); this.resourceTokenPartitionKey = ko.observable<string>();
this.isAuthWithResourceToken = ko.observable<boolean>(false); this.isAuthWithResourceToken = ko.observable<boolean>(false);
this.shareAccessData = ko.observable<ViewModels.AdHocAccessData>({ this.shareAccessData = ko.observable<AdHocAccessData>({
readWriteUrl: undefined, readWriteUrl: undefined,
readUrl: undefined readUrl: undefined
}); });
@ -458,7 +470,7 @@ export default class Explorer {
}); });
this.notificationConsoleData = ko.observableArray<ConsoleData>([]); this.notificationConsoleData = ko.observableArray<ConsoleData>([]);
this.defaultExperience = ko.observable<string>(); this.defaultExperience = ko.observable<string>();
this.databaseAccount.subscribe((databaseAccount: ViewModels.DatabaseAccount) => { this.databaseAccount.subscribe(databaseAccount => {
this.defaultExperience(DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(databaseAccount)); this.defaultExperience(DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(databaseAccount));
}); });
@ -551,8 +563,9 @@ export default class Explorer {
defaultExperience && defaultExperience &&
defaultExperience.toLowerCase() === Constants.DefaultAccountExperience.Cassandra.toLowerCase() defaultExperience.toLowerCase() === Constants.DefaultAccountExperience.Cassandra.toLowerCase()
) { ) {
const api = new CassandraApi(); this._isSystemDatabasePredicate = (database: ViewModels.Database): boolean => {
this._isSystemDatabasePredicate = api.isSystemDatabasePredicate; return database.id() === "system";
};
} }
}); });
@ -1003,7 +1016,7 @@ export default class Explorer {
); );
try { try {
const databaseAccount: ViewModels.DatabaseAccount = await resourceProviderClient.patchAsync( const databaseAccount: DataModels.DatabaseAccount = await resourceProviderClient.patchAsync(
this.databaseAccount().id, this.databaseAccount().id,
"2019-12-12", "2019-12-12",
{ {
@ -1951,7 +1964,7 @@ export default class Explorer {
return _.find(selectedCollection.storedProcedures(), (storedProcedure: StoredProcedure) => { return _.find(selectedCollection.storedProcedures(), (storedProcedure: StoredProcedure) => {
const openedSprocTab = this.tabsManager.getTabs( const openedSprocTab = this.tabsManager.getTabs(
ViewModels.CollectionTabKind.StoredProcedures, ViewModels.CollectionTabKind.StoredProcedures,
(tab: ViewModels.Tab) => tab.node && tab.node.rid === storedProcedure.rid tab => tab.node && tab.node.rid === storedProcedure.rid
); );
return ( return (
storedProcedure.rid === this.selectedNode().rid || storedProcedure.rid === this.selectedNode().rid ||
@ -1965,7 +1978,7 @@ export default class Explorer {
return _.find(selectedCollection.userDefinedFunctions(), (userDefinedFunction: UserDefinedFunction) => { return _.find(selectedCollection.userDefinedFunctions(), (userDefinedFunction: UserDefinedFunction) => {
const openedUdfTab = this.tabsManager.getTabs( const openedUdfTab = this.tabsManager.getTabs(
ViewModels.CollectionTabKind.UserDefinedFunctions, ViewModels.CollectionTabKind.UserDefinedFunctions,
(tab: ViewModels.Tab) => tab.node && tab.node.rid === userDefinedFunction.rid tab => tab.node && tab.node.rid === userDefinedFunction.rid
); );
return ( return (
userDefinedFunction.rid === this.selectedNode().rid || userDefinedFunction.rid === this.selectedNode().rid ||
@ -1979,7 +1992,7 @@ export default class Explorer {
return _.find(selectedCollection.triggers(), (trigger: Trigger) => { return _.find(selectedCollection.triggers(), (trigger: Trigger) => {
const openedTriggerTab = this.tabsManager.getTabs( const openedTriggerTab = this.tabsManager.getTabs(
ViewModels.CollectionTabKind.Triggers, ViewModels.CollectionTabKind.Triggers,
(tab: ViewModels.Tab) => tab.node && tab.node.rid === trigger.rid tab => tab.node && tab.node.rid === trigger.rid
); );
return ( return (
trigger.rid === this.selectedNode().rid || trigger.rid === this.selectedNode().rid ||
@ -1989,7 +2002,7 @@ export default class Explorer {
} }
public closeAllPanes(): void { public closeAllPanes(): void {
this._panes.forEach((pane: ViewModels.ContextualPane) => pane.close()); this._panes.forEach((pane: ContextualPaneBase) => pane.close());
} }
public getPlatformType(): PlatformType { public getPlatformType(): PlatformType {
@ -2004,7 +2017,7 @@ export default class Explorer {
); );
} }
public onUpdateTabsButtons(buttons: ViewModels.NavbarButtonConfig[]): void { public onUpdateTabsButtons(buttons: CommandButtonComponentProps[]): void {
this.commandBarComponentAdapter.onUpdateTabsButtons(buttons); this.commandBarComponentAdapter.onUpdateTabsButtons(buttons);
} }
@ -2064,9 +2077,7 @@ export default class Explorer {
if (isNewDatabase) { if (isNewDatabase) {
database.expandDatabase(); database.expandDatabase();
} }
this.tabsManager.refreshActiveTab( this.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.getDatabase().rid === database.rid);
(tab: ViewModels.Tab) => tab.collection && tab.collection.getDatabase().rid === database.rid
);
}) })
); );
}); });
@ -2169,7 +2180,7 @@ export default class Explorer {
} }
const urlPrefixWithKeyParam: string = `${config.hostedExplorerURL}?key=`; const urlPrefixWithKeyParam: string = `${config.hostedExplorerURL}?key=`;
const currentActiveTab: ViewModels.Tab = this.tabsManager.activeTab(); const currentActiveTab = this.tabsManager.activeTab();
return `${urlPrefixWithKeyParam}${token}#/${(currentActiveTab && currentActiveTab.hashLocation()) || ""}`; return `${urlPrefixWithKeyParam}${token}#/${(currentActiveTab && currentActiveTab.hashLocation()) || ""}`;
} }
@ -2432,18 +2443,18 @@ export default class Explorer {
throw new Error(`Invalid notebookContentItem: ${notebookContentItem}`); throw new Error(`Invalid notebookContentItem: ${notebookContentItem}`);
} }
const notebookTabs: NotebookV2Tab[] = this.tabsManager.getTabs( const notebookTabs = this.tabsManager.getTabs(
ViewModels.CollectionTabKind.NotebookV2, ViewModels.CollectionTabKind.NotebookV2,
(tab: ViewModels.Tab) => tab =>
(tab as NotebookV2Tab).notebookPath && (tab as NotebookV2Tab).notebookPath &&
FileSystemUtil.isPathEqual((tab as NotebookV2Tab).notebookPath(), notebookContentItem.path) FileSystemUtil.isPathEqual((tab as NotebookV2Tab).notebookPath(), notebookContentItem.path)
) as NotebookV2Tab[]; ) as NotebookV2Tab[];
let notebookTab: NotebookV2Tab = notebookTabs && notebookTabs[0]; let notebookTab = notebookTabs && notebookTabs[0];
if (notebookTab) { if (notebookTab) {
this.tabsManager.activateTab(notebookTab); this.tabsManager.activateTab(notebookTab);
} else { } else {
const options: ViewModels.NotebookTabOptions = { const options: NotebookTabOptions = {
account: CosmosClient.databaseAccount(), account: CosmosClient.databaseAccount(),
tabKind: ViewModels.CollectionTabKind.NotebookV2, tabKind: ViewModels.CollectionTabKind.NotebookV2,
node: null, node: null,
@ -2507,7 +2518,7 @@ export default class Explorer {
onSubmit: (input: string) => this.notebookManager?.notebookContentClient.renameNotebook(notebookFile, input) onSubmit: (input: string) => this.notebookManager?.notebookContentClient.renameNotebook(notebookFile, input)
}) })
.then(newNotebookFile => { .then(newNotebookFile => {
const notebookTabs: ViewModels.Tab[] = this.tabsManager.getTabs( const notebookTabs = this.tabsManager.getTabs(
ViewModels.CollectionTabKind.NotebookV2, ViewModels.CollectionTabKind.NotebookV2,
(tab: NotebookV2Tab) => tab.notebookPath && FileSystemUtil.isPathEqual(tab.notebookPath(), originalPath) (tab: NotebookV2Tab) => tab.notebookPath && FileSystemUtil.isPathEqual(tab.notebookPath(), originalPath)
); );
@ -2877,7 +2888,7 @@ export default class Explorer {
const terminalTabs: TerminalTab[] = this.tabsManager.getTabs( const terminalTabs: TerminalTab[] = this.tabsManager.getTabs(
ViewModels.CollectionTabKind.Terminal, ViewModels.CollectionTabKind.Terminal,
(tab: ViewModels.Tab) => tab.hashLocation() == hashLocation tab => tab.hashLocation() == hashLocation
) as TerminalTab[]; ) as TerminalTab[];
let terminalTab: TerminalTab = terminalTabs && terminalTabs[0]; let terminalTab: TerminalTab = terminalTabs && terminalTabs[0];
@ -2911,7 +2922,7 @@ export default class Explorer {
const galleryTabs = this.tabsManager.getTabs( const galleryTabs = this.tabsManager.getTabs(
ViewModels.CollectionTabKind.Gallery, ViewModels.CollectionTabKind.Gallery,
(tab: ViewModels.Tab) => tab.hashLocation() == hashLocation tab => tab.hashLocation() == hashLocation
); );
let galleryTab = galleryTabs && galleryTabs[0]; let galleryTab = galleryTabs && galleryTabs[0];
@ -2957,17 +2968,14 @@ export default class Explorer {
const notebookViewerTabModule = this.notebookViewerTab; const notebookViewerTabModule = this.notebookViewerTab;
let isNotebookViewerOpen = (tab: ViewModels.Tab) => { let isNotebookViewerOpen = (tab: TabsBase) => {
const notebookViewerTab = tab as typeof notebookViewerTabModule.default; const notebookViewerTab = tab as typeof notebookViewerTabModule.default;
return notebookViewerTab.notebookUrl === notebookUrl; return notebookViewerTab.notebookUrl === notebookUrl;
}; };
const notebookViewerTabs = this.tabsManager.getTabs( const notebookViewerTabs = this.tabsManager.getTabs(ViewModels.CollectionTabKind.NotebookV2, tab => {
ViewModels.CollectionTabKind.NotebookV2, return tab.hashLocation() == hashLocation && isNotebookViewerOpen(tab);
(tab: ViewModels.Tab) => { });
return tab.hashLocation() == hashLocation && isNotebookViewerOpen(tab);
}
);
let notebookViewerTab = notebookViewerTabs && notebookViewerTabs[0]; let notebookViewerTab = notebookViewerTabs && notebookViewerTabs[0];
if (notebookViewerTab) { if (notebookViewerTab) {

View File

@ -12,11 +12,12 @@ import { CommandBar, ICommandBarItemProps } from "office-ui-fabric-react/lib/Com
import { StyleConstants } from "../../../Common/Constants"; import { StyleConstants } from "../../../Common/Constants";
import { CommandBarUtil } from "./CommandBarUtil"; import { CommandBarUtil } from "./CommandBarUtil";
import Explorer from "../../Explorer"; import Explorer from "../../Explorer";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
export class CommandBarComponentAdapter implements ReactAdapter { export class CommandBarComponentAdapter implements ReactAdapter {
public parameters: ko.Observable<number>; public parameters: ko.Observable<number>;
public container: Explorer; public container: Explorer;
private tabsButtons: ViewModels.NavbarButtonConfig[]; private tabsButtons: CommandButtonComponentProps[];
private isNotebookTabActive: ko.Computed<boolean>; private isNotebookTabActive: ko.Computed<boolean>;
constructor(container: Explorer) { constructor(container: Explorer) {
@ -51,7 +52,7 @@ export class CommandBarComponentAdapter implements ReactAdapter {
this.parameters = ko.observable(Date.now()); this.parameters = ko.observable(Date.now());
} }
public onUpdateTabsButtons(buttons: ViewModels.NavbarButtonConfig[]): void { public onUpdateTabsButtons(buttons: CommandButtonComponentProps[]): void {
this.tabsButtons = buttons; this.tabsButtons = buttons;
this.triggerRender(); this.triggerRender();
} }

View File

@ -26,17 +26,18 @@ import GitHubIcon from "../../../../images/github.svg";
import SynapseIcon from "../../../../images/synapse-link.svg"; import SynapseIcon from "../../../../images/synapse-link.svg";
import { config, Platform } from "../../../Config"; import { config, Platform } from "../../../Config";
import Explorer from "../../Explorer"; import Explorer from "../../Explorer";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
export class CommandBarComponentButtonFactory { export class CommandBarComponentButtonFactory {
private static counter: number = 0; private static counter: number = 0;
public static createStaticCommandBarButtons(container: Explorer): ViewModels.NavbarButtonConfig[] { public static createStaticCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
if (container.isAuthWithResourceToken()) { if (container.isAuthWithResourceToken()) {
return CommandBarComponentButtonFactory.createStaticCommandBarButtonsForResourceToken(container); return CommandBarComponentButtonFactory.createStaticCommandBarButtonsForResourceToken(container);
} }
const newCollectionBtn = CommandBarComponentButtonFactory.createNewCollectionGroup(container); const newCollectionBtn = CommandBarComponentButtonFactory.createNewCollectionGroup(container);
const buttons: ViewModels.NavbarButtonConfig[] = [newCollectionBtn]; const buttons: CommandButtonComponentProps[] = [newCollectionBtn];
const addSynapseLink = CommandBarComponentButtonFactory.createOpenSynapseLinkDialogButton(container); const addSynapseLink = CommandBarComponentButtonFactory.createOpenSynapseLinkDialogButton(container);
if (addSynapseLink) { if (addSynapseLink) {
@ -112,7 +113,7 @@ export class CommandBarComponentButtonFactory {
if (CommandBarComponentButtonFactory.areScriptsSupported(container)) { if (CommandBarComponentButtonFactory.areScriptsSupported(container)) {
const label = "New Stored Procedure"; const label = "New Stored Procedure";
const newStoredProcedureBtn: ViewModels.NavbarButtonConfig = { const newStoredProcedureBtn: CommandButtonComponentProps = {
iconSrc: AddStoredProcedureIcon, iconSrc: AddStoredProcedureIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => { onCommandClick: () => {
@ -133,12 +134,12 @@ export class CommandBarComponentButtonFactory {
return buttons; return buttons;
} }
public static createContextCommandBarButtons(container: Explorer): ViewModels.NavbarButtonConfig[] { public static createContextCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
if (!container.isDatabaseNodeOrNoneSelected() && container.isPreferredApiMongoDB()) { if (!container.isDatabaseNodeOrNoneSelected() && container.isPreferredApiMongoDB()) {
const label = "New Shell"; const label = "New Shell";
const newMongoShellBtn: ViewModels.NavbarButtonConfig = { const newMongoShellBtn: CommandButtonComponentProps = {
iconSrc: HostedTerminalIcon, iconSrc: HostedTerminalIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => { onCommandClick: () => {
@ -156,15 +157,15 @@ export class CommandBarComponentButtonFactory {
return buttons; return buttons;
} }
public static createControlCommandBarButtons(container: Explorer): ViewModels.NavbarButtonConfig[] { public static createControlCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
if (window.dataExplorerPlatform === PlatformType.Hosted) { if (window.dataExplorerPlatform === PlatformType.Hosted) {
return buttons; return buttons;
} }
if (!container.isPreferredApiCassandra()) { if (!container.isPreferredApiCassandra()) {
const label = "Settings"; const label = "Settings";
const settingsPaneButton: ViewModels.NavbarButtonConfig = { const settingsPaneButton: CommandButtonComponentProps = {
iconSrc: SettingsIcon, iconSrc: SettingsIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => container.settingsPane.open(), onCommandClick: () => container.settingsPane.open(),
@ -179,7 +180,7 @@ export class CommandBarComponentButtonFactory {
if (container.isHostedDataExplorerEnabled()) { if (container.isHostedDataExplorerEnabled()) {
const label = "Open Full Screen"; const label = "Open Full Screen";
const fullScreenButton: ViewModels.NavbarButtonConfig = { const fullScreenButton: CommandButtonComponentProps = {
iconSrc: OpenInTabIcon, iconSrc: OpenInTabIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => container.generateSharedAccessData(), onCommandClick: () => container.generateSharedAccessData(),
@ -195,7 +196,7 @@ export class CommandBarComponentButtonFactory {
if (!container.hasOwnProperty("isEmulator") || !container.isEmulator) { if (!container.hasOwnProperty("isEmulator") || !container.isEmulator) {
const label = "Feedback"; const label = "Feedback";
const feedbackButtonOptions: ViewModels.NavbarButtonConfig = { const feedbackButtonOptions: CommandButtonComponentProps = {
iconSrc: FeedbackIcon, iconSrc: FeedbackIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => container.provideFeedbackEmail(), onCommandClick: () => container.provideFeedbackEmail(),
@ -211,7 +212,7 @@ export class CommandBarComponentButtonFactory {
return buttons; return buttons;
} }
public static createDivider(): ViewModels.NavbarButtonConfig { public static createDivider(): CommandButtonComponentProps {
const label = `divider${CommandBarComponentButtonFactory.counter++}`; const label = `divider${CommandBarComponentButtonFactory.counter++}`;
return { return {
isDivider: true, isDivider: true,
@ -228,7 +229,7 @@ export class CommandBarComponentButtonFactory {
return container.isPreferredApiDocumentDB() || container.isPreferredApiGraph(); return container.isPreferredApiDocumentDB() || container.isPreferredApiGraph();
} }
private static createNewCollectionGroup(container: Explorer): ViewModels.NavbarButtonConfig { private static createNewCollectionGroup(container: Explorer): CommandButtonComponentProps {
const label = container.addCollectionText(); const label = container.addCollectionText();
return { return {
iconSrc: AddCollectionIcon, iconSrc: AddCollectionIcon,
@ -241,7 +242,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createOpenSynapseLinkDialogButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonComponentProps {
if (config.platform === Platform.Emulator) { if (config.platform === Platform.Emulator) {
return null; return null;
} }
@ -276,7 +277,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createNewDatabase(container: Explorer): ViewModels.NavbarButtonConfig { private static createNewDatabase(container: Explorer): CommandButtonComponentProps {
const label = container.addDatabaseText(); const label = container.addDatabaseText();
return { return {
iconSrc: AddDatabaseIcon, iconSrc: AddDatabaseIcon,
@ -291,7 +292,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createNewSQLQueryButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createNewSQLQueryButton(container: Explorer): CommandButtonComponentProps {
if (container.isPreferredApiDocumentDB() || container.isPreferredApiGraph()) { if (container.isPreferredApiDocumentDB() || container.isPreferredApiGraph()) {
const label = "New SQL Query"; const label = "New SQL Query";
return { return {
@ -325,15 +326,15 @@ export class CommandBarComponentButtonFactory {
return null; return null;
} }
public static createScriptCommandButtons(container: Explorer): ViewModels.NavbarButtonConfig[] { public static createScriptCommandButtons(container: Explorer): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
const shouldEnableScriptsCommands: boolean = const shouldEnableScriptsCommands: boolean =
!container.isDatabaseNodeOrNoneSelected() && CommandBarComponentButtonFactory.areScriptsSupported(container); !container.isDatabaseNodeOrNoneSelected() && CommandBarComponentButtonFactory.areScriptsSupported(container);
if (shouldEnableScriptsCommands) { if (shouldEnableScriptsCommands) {
const label = "New Stored Procedure"; const label = "New Stored Procedure";
const newStoredProcedureBtn: ViewModels.NavbarButtonConfig = { const newStoredProcedureBtn: CommandButtonComponentProps = {
iconSrc: AddStoredProcedureIcon, iconSrc: AddStoredProcedureIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => { onCommandClick: () => {
@ -350,7 +351,7 @@ export class CommandBarComponentButtonFactory {
if (shouldEnableScriptsCommands) { if (shouldEnableScriptsCommands) {
const label = "New UDF"; const label = "New UDF";
const newUserDefinedFunctionBtn: ViewModels.NavbarButtonConfig = { const newUserDefinedFunctionBtn: CommandButtonComponentProps = {
iconSrc: AddUdfIcon, iconSrc: AddUdfIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => { onCommandClick: () => {
@ -367,7 +368,7 @@ export class CommandBarComponentButtonFactory {
if (shouldEnableScriptsCommands) { if (shouldEnableScriptsCommands) {
const label = "New Trigger"; const label = "New Trigger";
const newTriggerBtn: ViewModels.NavbarButtonConfig = { const newTriggerBtn: CommandButtonComponentProps = {
iconSrc: AddTriggerIcon, iconSrc: AddTriggerIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => { onCommandClick: () => {
@ -385,7 +386,7 @@ export class CommandBarComponentButtonFactory {
return buttons; return buttons;
} }
private static createScaleAndSettingsButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createScaleAndSettingsButton(container: Explorer): CommandButtonComponentProps {
let isShared = false; let isShared = false;
if (container.isDatabaseNodeSelected()) { if (container.isDatabaseNodeSelected()) {
isShared = container.findSelectedDatabase().isDatabaseShared(); isShared = container.findSelectedDatabase().isDatabaseShared();
@ -410,7 +411,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createNewNotebookButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createNewNotebookButton(container: Explorer): CommandButtonComponentProps {
const label = "New Notebook"; const label = "New Notebook";
return { return {
iconSrc: NewNotebookIcon, iconSrc: NewNotebookIcon,
@ -423,7 +424,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createuploadNotebookButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createuploadNotebookButton(container: Explorer): CommandButtonComponentProps {
const label = "Upload to Notebook Server"; const label = "Upload to Notebook Server";
return { return {
iconSrc: NewNotebookIcon, iconSrc: NewNotebookIcon,
@ -436,7 +437,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createOpenQueryButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createOpenQueryButton(container: Explorer): CommandButtonComponentProps {
const label = "Open Query"; const label = "Open Query";
return { return {
iconSrc: BrowseQueriesIcon, iconSrc: BrowseQueriesIcon,
@ -449,7 +450,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createOpenQueryFromDiskButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createOpenQueryFromDiskButton(container: Explorer): CommandButtonComponentProps {
const label = "Open Query From Disk"; const label = "Open Query From Disk";
return { return {
iconSrc: OpenQueryFromDiskIcon, iconSrc: OpenQueryFromDiskIcon,
@ -462,7 +463,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createEnableNotebooksButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createEnableNotebooksButton(container: Explorer): CommandButtonComponentProps {
if (config.platform === Platform.Emulator) { if (config.platform === Platform.Emulator) {
return null; return null;
} }
@ -483,7 +484,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createOpenTerminalButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createOpenTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open Terminal"; const label = "Open Terminal";
return { return {
iconSrc: CosmosTerminalIcon, iconSrc: CosmosTerminalIcon,
@ -496,7 +497,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createOpenMongoTerminalButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createOpenMongoTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open Mongo Shell"; const label = "Open Mongo Shell";
const tooltip = const tooltip =
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks."; "This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
@ -522,7 +523,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createOpenCassandraTerminalButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createOpenCassandraTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open Cassandra Shell"; const label = "Open Cassandra Shell";
const tooltip = const tooltip =
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks."; "This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
@ -548,7 +549,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createNotebookWorkspaceResetButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createNotebookWorkspaceResetButton(container: Explorer): CommandButtonComponentProps {
const label = "Reset Workspace"; const label = "Reset Workspace";
return { return {
iconSrc: ResetWorkspaceIcon, iconSrc: ResetWorkspaceIcon,
@ -561,7 +562,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createManageGitHubAccountButton(container: Explorer): ViewModels.NavbarButtonConfig { private static createManageGitHubAccountButton(container: Explorer): CommandButtonComponentProps {
let connectedToGitHub: boolean = container.notebookManager?.gitHubOAuthService.isLoggedIn(); let connectedToGitHub: boolean = container.notebookManager?.gitHubOAuthService.isLoggedIn();
const label = connectedToGitHub ? "Manage GitHub settings" : "Connect to GitHub"; const label = connectedToGitHub ? "Manage GitHub settings" : "Connect to GitHub";
return { return {
@ -584,7 +585,7 @@ export class CommandBarComponentButtonFactory {
}; };
} }
private static createStaticCommandBarButtonsForResourceToken(container: Explorer): ViewModels.NavbarButtonConfig[] { private static createStaticCommandBarButtonsForResourceToken(container: Explorer): CommandButtonComponentProps[] {
const newSqlQueryBtn = CommandBarComponentButtonFactory.createNewSQLQueryButton(container); const newSqlQueryBtn = CommandBarComponentButtonFactory.createNewSQLQueryButton(container);
const openQueryBtn = CommandBarComponentButtonFactory.createOpenQueryButton(container); const openQueryBtn = CommandBarComponentButtonFactory.createOpenQueryButton(container);

View File

@ -1,9 +1,10 @@
import { CommandBarUtil } from "./CommandBarUtil"; import { CommandBarUtil } from "./CommandBarUtil";
import * as ViewModels from "../../../Contracts/ViewModels"; import * as ViewModels from "../../../Contracts/ViewModels";
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar"; import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
describe("CommandBarUtil tests", () => { describe("CommandBarUtil tests", () => {
const createButton = (): ViewModels.NavbarButtonConfig => { const createButton = (): CommandButtonComponentProps => {
return { return {
iconSrc: "icon", iconSrc: "icon",
iconAlt: "label", iconAlt: "label",
@ -54,7 +55,7 @@ describe("CommandBarUtil tests", () => {
}); });
it("should create buttons with unique keys", () => { it("should create buttons with unique keys", () => {
const btns: ViewModels.NavbarButtonConfig[] = []; const btns: CommandButtonComponentProps[] = [];
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
btns.push(createButton()); btns.push(createButton());
} }

View File

@ -1,12 +1,11 @@
import _ from "underscore"; import _ from "underscore";
import * as React from "react"; import * as React from "react";
import * as ViewModels from "../../../Contracts/ViewModels";
import { Observable } from "knockout"; import { Observable } from "knockout";
import { IconType } from "office-ui-fabric-react/lib/Icon"; import { IconType } from "office-ui-fabric-react/lib/Icon";
import { IComponentAsProps } from "office-ui-fabric-react/lib/Utilities"; import { IComponentAsProps } from "office-ui-fabric-react/lib/Utilities";
import { KeyCodes, StyleConstants } from "../../../Common/Constants"; import { StyleConstants } from "../../../Common/Constants";
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar"; import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
import { Dropdown, DropdownMenuItemType, IDropdownStyles, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown"; import { Dropdown, IDropdownStyles, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import ChevronDownIcon from "../../../../images/Chevron_down.svg"; import ChevronDownIcon from "../../../../images/Chevron_down.svg";
import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker"; import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker";
@ -21,13 +20,13 @@ export class CommandBarUtil {
* Convert our NavbarButtonConfig to UI Fabric buttons * Convert our NavbarButtonConfig to UI Fabric buttons
* @param btns * @param btns
*/ */
public static convertButton(btns: ViewModels.NavbarButtonConfig[], backgroundColor: string): ICommandBarItemProps[] { public static convertButton(btns: CommandButtonComponentProps[], backgroundColor: string): ICommandBarItemProps[] {
const buttonHeightPx = StyleConstants.CommandBarButtonHeight; const buttonHeightPx = StyleConstants.CommandBarButtonHeight;
return btns return btns
.filter(btn => btn) .filter(btn => btn)
.map( .map(
(btn: ViewModels.NavbarButtonConfig, index: number): ICommandBarItemProps => { (btn: CommandButtonComponentProps, index: number): ICommandBarItemProps => {
if (btn.isDivider) { if (btn.isDivider) {
return CommandBarUtil.createDivider(btn.commandButtonLabel); return CommandBarUtil.createDivider(btn.commandButtonLabel);
} }

View File

@ -3,17 +3,19 @@
*/ */
import * as React from "react"; import * as React from "react";
import * as ViewModels from "../../../Contracts/ViewModels"; import {
import { CommandButtonComponent } from "../../Controls/CommandButton/CommandButtonComponent"; CommandButtonComponent,
CommandButtonComponentProps
} from "../../Controls/CommandButton/CommandButtonComponent";
export interface ControlBarComponentProps { export interface ControlBarComponentProps {
buttons: ViewModels.NavbarButtonConfig[]; buttons: CommandButtonComponentProps[];
} }
export class ControlBarComponent extends React.Component<ControlBarComponentProps> { export class ControlBarComponent extends React.Component<ControlBarComponentProps> {
private static renderButtons(commandButtonOptions: ViewModels.NavbarButtonConfig[]): JSX.Element[] { private static renderButtons(commandButtonOptions: CommandButtonComponentProps[]): JSX.Element[] {
return commandButtonOptions.map( return commandButtonOptions.map(
(btn: ViewModels.NavbarButtonConfig, index: number): JSX.Element => { (btn: CommandButtonComponentProps, index: number): JSX.Element => {
// Remove label // Remove label
btn.commandButtonLabel = null; btn.commandButtonLabel = null;
return CommandButtonComponent.renderButton(btn, `${index}`); return CommandButtonComponent.renderButton(btn, `${index}`);

View File

@ -8,12 +8,12 @@ import * as ko from "knockout";
import * as React from "react"; import * as React from "react";
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler"; import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
import { ControlBarComponent } from "./ControlBarComponent"; import { ControlBarComponent } from "./ControlBarComponent";
import * as ViewModels from "../../../Contracts/ViewModels"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
export class ControlBarComponentAdapter implements ReactAdapter { export class ControlBarComponentAdapter implements ReactAdapter {
public parameters: ko.Observable<number>; public parameters: ko.Observable<number>;
constructor(private buttons: ko.ObservableArray<ViewModels.NavbarButtonConfig>) { constructor(private buttons: ko.ObservableArray<CommandButtonComponentProps>) {
this.buttons.subscribe(() => this.forceRender()); this.buttons.subscribe(() => this.forceRender());
this.parameters = ko.observable<number>(Date.now()); this.parameters = ko.observable<number>(Date.now());
} }

View File

@ -2,13 +2,12 @@
* Notebook container related stuff * Notebook container related stuff
*/ */
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
export class NotebookContainerClient implements ViewModels.INotebookContainerClient { export class NotebookContainerClient {
private reconnectingNotificationId: string; private reconnectingNotificationId: string;
private isResettingWorkspace: boolean; private isResettingWorkspace: boolean;

View File

@ -1,5 +1,4 @@
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem"; import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem";
import { StringUtils } from "../../Utils/StringUtils"; import { StringUtils } from "../../Utils/StringUtils";
import { FileSystemUtil } from "./FileSystemUtil"; import { FileSystemUtil } from "./FileSystemUtil";
@ -9,7 +8,7 @@ import { ServerConfig, IContent, IContentProvider, FileType, IEmptyContent } fro
import { AjaxResponse } from "rxjs/ajax"; import { AjaxResponse } from "rxjs/ajax";
import { stringifyNotebook } from "@nteract/commutable"; import { stringifyNotebook } from "@nteract/commutable";
export class NotebookContentClient implements ViewModels.INotebookContentClient { export class NotebookContentClient {
constructor( constructor(
private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>, private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>,
private notebookBasePath: ko.Observable<string>, private notebookBasePath: ko.Observable<string>,

View File

@ -3,7 +3,6 @@
*/ */
import { JunoClient } from "../../Juno/JunoClient"; import { JunoClient } from "../../Juno/JunoClient";
import * as ViewModels from "../../Contracts/ViewModels";
import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService"; import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService";
import { GitHubClient } from "../../GitHub/GitHubClient"; import { GitHubClient } from "../../GitHub/GitHubClient";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
@ -25,6 +24,7 @@ import { PublishNotebookPaneAdapter } from "../Panes/PublishNotebookPaneAdapter"
import { getFullName } from "../../Utils/UserUtils"; import { getFullName } from "../../Utils/UserUtils";
import { ImmutableNotebook } from "@nteract/commutable"; import { ImmutableNotebook } from "@nteract/commutable";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { ContextualPaneBase } from "../Panes/ContextualPaneBase";
export interface NotebookManagerOptions { export interface NotebookManagerOptions {
container: Explorer; container: Explorer;
@ -40,14 +40,14 @@ export default class NotebookManager {
public junoClient: JunoClient; public junoClient: JunoClient;
public notebookContentProvider: IContentProvider; public notebookContentProvider: IContentProvider;
public notebookClient: ViewModels.INotebookContainerClient; public notebookClient: NotebookContainerClient;
public notebookContentClient: ViewModels.INotebookContentClient; public notebookContentClient: NotebookContentClient;
private gitHubContentProvider: GitHubContentProvider; private gitHubContentProvider: GitHubContentProvider;
public gitHubOAuthService: GitHubOAuthService; public gitHubOAuthService: GitHubOAuthService;
private gitHubClient: GitHubClient; private gitHubClient: GitHubClient;
public gitHubReposPane: ViewModels.ContextualPane; public gitHubReposPane: ContextualPaneBase;
public publishNotebookPaneAdapter: PublishNotebookPaneAdapter; public publishNotebookPaneAdapter: PublishNotebookPaneAdapter;
public initialize(params: NotebookManagerOptions): void { public initialize(params: NotebookManagerOptions): void {

View File

@ -1,14 +1,13 @@
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import * as ViewModels from "../../Contracts/ViewModels";
import AddCollectionPane from "./AddCollectionPane"; import AddCollectionPane from "./AddCollectionPane";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import ko from "knockout"; import ko from "knockout";
import { AutopilotTier } from "../../Contracts/DataModels"; import { AutopilotTier, DatabaseAccount } from "../../Contracts/DataModels";
describe("Add Collection Pane", () => { describe("Add Collection Pane", () => {
describe("isValid()", () => { describe("isValid()", () => {
let explorer: Explorer; let explorer: Explorer;
const mockDatabaseAccount: ViewModels.DatabaseAccount = { const mockDatabaseAccount: DatabaseAccount = {
id: "mock", id: "mock",
kind: "DocumentDB", kind: "DocumentDB",
location: "", location: "",
@ -24,7 +23,7 @@ describe("Add Collection Pane", () => {
tags: [] tags: []
}; };
const mockFreeTierDatabaseAccount: ViewModels.DatabaseAccount = { const mockFreeTierDatabaseAccount: DatabaseAccount = {
id: "mock", id: "mock",
kind: "DocumentDB", kind: "DocumentDB",
location: "", location: "",

View File

@ -22,6 +22,12 @@ import { HashMap } from "../../Common/HashMap";
import { PlatformType } from "../../PlatformType"; import { PlatformType } from "../../PlatformType";
import { refreshCachedResources, getOrCreateDatabaseAndCollection } from "../../Common/DocumentClientUtilityBase"; import { refreshCachedResources, getOrCreateDatabaseAndCollection } from "../../Common/DocumentClientUtilityBase";
export interface AddCollectionPaneOptions extends ViewModels.PaneOptions {
isPreferredApiTable: ko.Computed<boolean>;
databaseId?: string;
databaseSelfLink?: string;
}
export default class AddCollectionPane extends ContextualPaneBase { export default class AddCollectionPane extends ContextualPaneBase {
public defaultExperience: ko.Computed<string>; public defaultExperience: ko.Computed<string>;
public databaseIds: ko.ObservableArray<string>; public databaseIds: ko.ObservableArray<string>;
@ -100,7 +106,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
private _databaseOffers: HashMap<DataModels.Offer>; private _databaseOffers: HashMap<DataModels.Offer>;
private _isSynapseLinkEnabled: ko.Computed<boolean>; private _isSynapseLinkEnabled: ko.Computed<boolean>;
constructor(options: ViewModels.AddCollectionPaneOptions) { constructor(options: AddCollectionPaneOptions) {
super(options); super(options);
this._databaseOffers = new HashMap<DataModels.Offer>(); this._databaseOffers = new HashMap<DataModels.Offer>();
this.hasAutoPilotV2FeatureFlag = ko.pureComputed(() => this.container.hasAutoPilotV2FeatureFlag()); this.hasAutoPilotV2FeatureFlag = ko.pureComputed(() => this.container.hasAutoPilotV2FeatureFlag());
@ -619,7 +625,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
this._isSynapseLinkEnabled = ko.computed(() => { this._isSynapseLinkEnabled = ko.computed(() => {
const databaseAccount = const databaseAccount =
(this.container && this.container.databaseAccount && this.container.databaseAccount()) || (this.container && this.container.databaseAccount && this.container.databaseAccount()) ||
({} as ViewModels.DatabaseAccount); ({} as DataModels.DatabaseAccount);
const properties = databaseAccount.properties || ({} as DataModels.DatabaseAccountExtendedProperties); const properties = databaseAccount.properties || ({} as DataModels.DatabaseAccountExtendedProperties);
// TODO: remove check for capability once all accounts have been migrated // TODO: remove check for capability once all accounts have been migrated
@ -1266,10 +1272,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
: SharedConstants.CollectionCreation.NumberOfPartitionsInUnlimitedCollection; : SharedConstants.CollectionCreation.NumberOfPartitionsInUnlimitedCollection;
} }
private _convertShardKeyToPartitionKey( private _convertShardKeyToPartitionKey(shardKey: string): string {
shardKey: string,
configurationOverrides: ViewModels.ConfigurationOverrides
): string {
if (!shardKey) { if (!shardKey) {
return shardKey; return shardKey;
} }
@ -1331,10 +1334,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
}; };
if (this.container.isPreferredApiMongoDB()) { if (this.container.isPreferredApiMongoDB()) {
transform = (value: string) => { transform = (value: string) => {
return this._convertShardKeyToPartitionKey( return this._convertShardKeyToPartitionKey(value);
value,
this.container.databaseAccount().properties.configurationOverrides
);
}; };
} }

View File

@ -2,11 +2,12 @@ import * as Constants from "../../Common/Constants";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import AddDatabasePane from "./AddDatabasePane"; import AddDatabasePane from "./AddDatabasePane";
import { DatabaseAccount } from "../../Contracts/DataModels";
describe("Add Database Pane", () => { describe("Add Database Pane", () => {
describe("getSharedThroughputDefault()", () => { describe("getSharedThroughputDefault()", () => {
let explorer: Explorer; let explorer: Explorer;
const mockDatabaseAccount: ViewModels.DatabaseAccount = { const mockDatabaseAccount: DatabaseAccount = {
id: "mock", id: "mock",
kind: "DocumentDB", kind: "DocumentDB",
location: "", location: "",
@ -22,7 +23,7 @@ describe("Add Database Pane", () => {
tags: [] tags: []
}; };
const mockFreeTierDatabaseAccount: ViewModels.DatabaseAccount = { const mockFreeTierDatabaseAccount: DatabaseAccount = {
id: "mock", id: "mock",
kind: "DocumentDB", kind: "DocumentDB",
location: "", location: "",

View File

@ -6,6 +6,7 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
import { QueriesGridComponentAdapter } from "../Controls/QueriesGridReactComponent/QueriesGridComponentAdapter"; import { QueriesGridComponentAdapter } from "../Controls/QueriesGridReactComponent/QueriesGridComponentAdapter";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import QueryTab from "../Tabs/QueryTab";
export class BrowseQueriesPane extends ContextualPaneBase { export class BrowseQueriesPane extends ContextualPaneBase {
public queriesGridComponentAdapter: QueriesGridComponentAdapter; public queriesGridComponentAdapter: QueriesGridComponentAdapter;
@ -87,7 +88,7 @@ export class BrowseQueriesPane extends ContextualPaneBase {
} else { } else {
selectedCollection.onNewQueryClick(selectedCollection, null); selectedCollection.onNewQueryClick(selectedCollection, null);
} }
const queryTab: ViewModels.QueryTab = this.container.tabsManager.activeTab() as ViewModels.QueryTab; const queryTab = this.container.tabsManager.activeTab() as QueryTab;
queryTab.tabTitle(savedQuery.queryName); queryTab.tabTitle(savedQuery.queryName);
queryTab.tabPath(`${selectedCollection.databaseId}>${selectedCollection.id()}>${savedQuery.queryName}`); queryTab.tabPath(`${selectedCollection.databaseId}>${selectedCollection.id()}>${savedQuery.queryName}`);
queryTab.initialEditorContent(savedQuery.query); queryTab.initialEditorContent(savedQuery.query);

View File

@ -8,7 +8,7 @@ import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
// TODO: Use specific actions for logging telemetry data // TODO: Use specific actions for logging telemetry data
export abstract class ContextualPaneBase extends WaitsForTemplateViewModel implements ViewModels.ContextualPane { export abstract class ContextualPaneBase extends WaitsForTemplateViewModel {
public id: string; public id: string;
public container: Explorer; public container: Explorer;
public firstFieldHasFocus: ko.Observable<boolean>; public firstFieldHasFocus: ko.Observable<boolean>;

View File

@ -106,10 +106,10 @@ describe("Delete Collection Confirmation Pane", () => {
fakeExplorer.isSelectedDatabaseShared = () => false; fakeExplorer.isSelectedDatabaseShared = () => false;
const SubscriptionId = "testId"; const SubscriptionId = "testId";
const AccountName = "testAccount"; const AccountName = "testAccount";
fakeExplorer.databaseAccount = ko.observable<ViewModels.DatabaseAccount>({ fakeExplorer.databaseAccount = ko.observable<DataModels.DatabaseAccount>({
id: SubscriptionId, id: SubscriptionId,
name: AccountName name: AccountName
} as ViewModels.DatabaseAccount); } as DataModels.DatabaseAccount);
fakeExplorer.defaultExperience = ko.observable<string>("DocumentDB"); fakeExplorer.defaultExperience = ko.observable<string>("DocumentDB");
fakeExplorer.isPreferredApiCassandra = ko.computed(() => { fakeExplorer.isPreferredApiCassandra = ko.computed(() => {

View File

@ -66,9 +66,7 @@ export default class DeleteCollectionConfirmationPane extends ContextualPaneBase
this.isExecuting(false); this.isExecuting(false);
this.close(); this.close();
this.container.selectedNode(selectedCollection.database); this.container.selectedNode(selectedCollection.database);
this.container.tabsManager?.closeTabsByComparator( this.container.tabsManager?.closeTabsByComparator(tab => tab.node && tab.node.rid === selectedCollection.rid);
(tab: ViewModels.Tab) => tab.node && tab.node.rid === selectedCollection.rid
);
this.container.refreshAllDatabases(); this.container.refreshAllDatabases();
this.resetData(); this.resetData();
TelemetryProcessor.traceSuccess( TelemetryProcessor.traceSuccess(

View File

@ -97,10 +97,10 @@ describe("Delete Database Confirmation Pane", () => {
fakeExplorer.isSelectedDatabaseShared = () => false; fakeExplorer.isSelectedDatabaseShared = () => false;
const SubscriptionId = "testId"; const SubscriptionId = "testId";
const AccountName = "testAccount"; const AccountName = "testAccount";
fakeExplorer.databaseAccount = ko.observable<ViewModels.DatabaseAccount>({ fakeExplorer.databaseAccount = ko.observable<DataModels.DatabaseAccount>({
id: SubscriptionId, id: SubscriptionId,
name: AccountName name: AccountName
} as ViewModels.DatabaseAccount); } as DataModels.DatabaseAccount);
fakeExplorer.defaultExperience = ko.observable<string>("DocumentDB"); fakeExplorer.defaultExperience = ko.observable<string>("DocumentDB");
fakeExplorer.isPreferredApiCassandra = ko.computed(() => { fakeExplorer.isPreferredApiCassandra = ko.computed(() => {
return false; return false;

View File

@ -67,16 +67,12 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
this.isExecuting(false); this.isExecuting(false);
this.close(); this.close();
this.container.refreshAllDatabases(); this.container.refreshAllDatabases();
this.container.tabsManager.closeTabsByComparator( this.container.tabsManager.closeTabsByComparator(tab => tab.node && tab.node.rid === selectedDatabase.rid);
(tab: ViewModels.Tab) => tab.node && tab.node.rid === selectedDatabase.rid
);
this.container.selectedNode(null); this.container.selectedNode(null);
selectedDatabase selectedDatabase
.collections() .collections()
.forEach((collection: ViewModels.Collection) => .forEach((collection: ViewModels.Collection) =>
this.container.tabsManager.closeTabsByComparator( this.container.tabsManager.closeTabsByComparator(tab => tab.node && tab.node.rid === collection.rid)
(tab: ViewModels.Tab) => tab.node && tab.node.rid === collection.rid
)
); );
this.resetData(); this.resetData();
TelemetryProcessor.traceSuccess( TelemetryProcessor.traceSuccess(

View File

@ -16,6 +16,11 @@ import { BranchesProps, PinnedReposProps, UnpinnedReposProps } from "../Controls
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
import { ContextualPaneBase } from "./ContextualPaneBase"; import { ContextualPaneBase } from "./ContextualPaneBase";
interface GitHubReposPaneOptions extends ViewModels.PaneOptions {
gitHubClient: GitHubClient;
junoClient: JunoClient;
}
export class GitHubReposPane extends ContextualPaneBase { export class GitHubReposPane extends ContextualPaneBase {
private static readonly PageSize = 30; private static readonly PageSize = 30;
@ -33,7 +38,7 @@ export class GitHubReposPane extends ContextualPaneBase {
private allGitHubReposLastPageInfo?: IGitHubPageInfo; private allGitHubReposLastPageInfo?: IGitHubPageInfo;
private pinnedReposUpdated: boolean; private pinnedReposUpdated: boolean;
constructor(options: ViewModels.GitHubReposPaneOptions) { constructor(options: GitHubReposPaneOptions) {
super(options); super(options);
this.gitHubClient = options.gitHubClient; this.gitHubClient = options.gitHubClient;

View File

@ -6,6 +6,7 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
import QueryTab from "../Tabs/QueryTab";
export class LoadQueryPane extends ContextualPaneBase { export class LoadQueryPane extends ContextualPaneBase {
public selectedFilesTitle: ko.Observable<string>; public selectedFilesTitle: ko.Observable<string>;
@ -111,7 +112,7 @@ export class LoadQueryPane extends ContextualPaneBase {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (evt: any): void => { reader.onload = (evt: any): void => {
const fileData: string = evt.target.result; const fileData: string = evt.target.result;
const queryTab: ViewModels.QueryTab = this.container.tabsManager.activeTab() as ViewModels.QueryTab; const queryTab = this.container.tabsManager.activeTab() as QueryTab;
queryTab.initialEditorContent(fileData); queryTab.initialEditorContent(fileData);
queryTab.sqlQueryEditorContent(fileData); queryTab.sqlQueryEditorContent(fileData);
deferred.resolve(); deferred.resolve();

View File

@ -7,6 +7,7 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import QueryTab from "../Tabs/QueryTab";
export class SaveQueryPane extends ContextualPaneBase { export class SaveQueryPane extends ContextualPaneBase {
public queryName: ko.Observable<string>; public queryName: ko.Observable<string>;
@ -34,8 +35,7 @@ export class SaveQueryPane extends ContextualPaneBase {
} }
const queryName: string = this.queryName(); const queryName: string = this.queryName();
const queryTab: ViewModels.QueryTab = const queryTab = this.container && (this.container.tabsManager.activeTab() as QueryTab);
this.container && (this.container.tabsManager.activeTab() as ViewModels.QueryTab);
const query: string = queryTab && queryTab.sqlQueryEditorContent(); const query: string = queryTab && queryTab.sqlQueryEditorContent();
if (!queryName || queryName.length === 0) { if (!queryName || queryName.length === 0) {
this.formErrors("No query name specified"); this.formErrors("No query name specified");

View File

@ -5,11 +5,22 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
export interface StringInputPaneOpenOptions {
paneTitle: string;
inputLabel: string;
errorMessage: string;
inProgressMessage: string;
successMessage: string;
onSubmit: (input: string) => Promise<any>;
submitButtonLabel: string;
defaultInput?: string;
}
/** /**
* Generic pane to get a single string input from user * Generic pane to get a single string input from user
*/ */
export class StringInputPane extends ContextualPaneBase { export class StringInputPane extends ContextualPaneBase {
private openOptions: ViewModels.StringInputPaneOpenOptions; private openOptions: StringInputPaneOpenOptions;
private submitButtonLabel: ko.Observable<string>; private submitButtonLabel: ko.Observable<string>;
private inputLabel: ko.Observable<string>; private inputLabel: ko.Observable<string>;
private stringInput: ko.Observable<string>; private stringInput: ko.Observable<string>;
@ -78,7 +89,7 @@ export class StringInputPane extends ContextualPaneBase {
this.resetFileInput(); this.resetFileInput();
} }
public openWithOptions<T>(options: ViewModels.StringInputPaneOpenOptions): Q.Promise<T> { public openWithOptions<T>(options: StringInputPaneOpenOptions): Q.Promise<T> {
this.openOptions = options; this.openOptions = options;
this.title(this.openOptions.paneTitle); this.title(this.openOptions.paneTitle);
if (this.openOptions.submitButtonLabel) { if (this.openOptions.submitButtonLabel) {

View File

@ -5,10 +5,21 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
export interface UploadFilePaneOpenOptions {
paneTitle: string;
selectFileInputLabel: string;
errorMessage: string; // Could not upload notebook
inProgressMessage: string; // Uploading notebook
successMessage: string; // Successfully uploaded notebook
onSubmit: (file: File) => Promise<any>;
extensions?: string; // input accept field. E.g: .ipynb
submitButtonLabel?: string;
}
export class UploadFilePane extends ContextualPaneBase { export class UploadFilePane extends ContextualPaneBase {
public selectedFilesTitle: ko.Observable<string>; public selectedFilesTitle: ko.Observable<string>;
public files: ko.Observable<FileList>; public files: ko.Observable<FileList>;
private openOptions: ViewModels.UploadFilePaneOpenOptions; private openOptions: UploadFilePaneOpenOptions;
private submitButtonLabel: ko.Observable<string>; private submitButtonLabel: ko.Observable<string>;
private selectFileInputLabel: ko.Observable<string>; private selectFileInputLabel: ko.Observable<string>;
private extensions: ko.Observable<string>; private extensions: ko.Observable<string>;
@ -79,7 +90,7 @@ export class UploadFilePane extends ContextualPaneBase {
this.resetFileInput(); this.resetFileInput();
} }
public openWithOptions(options: ViewModels.UploadFilePaneOpenOptions): void { public openWithOptions(options: UploadFilePaneOpenOptions): void {
this.openOptions = options; this.openOptions = options;
this.title(this.openOptions.paneTitle); this.title(this.openOptions.paneTitle);
if (this.openOptions.submitButtonLabel) { if (this.openOptions.submitButtonLabel) {

View File

@ -32,7 +32,7 @@ export class SplashScreenComponentAdapter implements ReactAdapter {
constructor(private container: Explorer) { constructor(private container: Explorer) {
this.parameters = ko.observable<number>(Date.now()); this.parameters = ko.observable<number>(Date.now());
this.container.tabsManager.openedTabs.subscribe((tabs: ViewModels.Tab[]) => { this.container.tabsManager.openedTabs.subscribe(tabs => {
if (tabs.length === 0) { if (tabs.length === 0) {
this.forceRender(); this.forceRender();
} }

View File

@ -14,7 +14,6 @@ import TabsBase from "./TabsBase";
import { DocumentsGridMetrics } from "../../Common/Constants"; import { DocumentsGridMetrics } from "../../Common/Constants";
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter"; import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import Toolbar from "../Controls/Toolbar/Toolbar";
import SaveIcon from "../../../images/save-cosmos.svg"; import SaveIcon from "../../../images/save-cosmos.svg";
import DiscardIcon from "../../../images/discard.svg"; import DiscardIcon from "../../../images/discard.svg";
import DeleteIcon from "../../../images/delete.svg"; import DeleteIcon from "../../../images/delete.svg";
@ -28,16 +27,16 @@ import {
createDocument, createDocument,
updateDocument updateDocument
} from "../../Common/DocumentClientUtilityBase"; } from "../../Common/DocumentClientUtilityBase";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
export default class ConflictsTab extends TabsBase { export default class ConflictsTab extends TabsBase {
public selectedConflictId: ko.Observable<ViewModels.ConflictId>; public selectedConflictId: ko.Observable<ConflictId>;
public selectedConflictContent: ViewModels.Editable<string>; public selectedConflictContent: ViewModels.Editable<string>;
public selectedConflictCurrent: ViewModels.Editable<string>; public selectedConflictCurrent: ViewModels.Editable<string>;
public documentContentsGridId: string; public documentContentsGridId: string;
public documentContentsContainerId: string; public documentContentsContainerId: string;
public isEditorDirty: ko.Computed<boolean>; public isEditorDirty: ko.Computed<boolean>;
public editorState: ko.Observable<ViewModels.DocumentExplorerState>; public editorState: ko.Observable<ViewModels.DocumentExplorerState>;
public toolbarViewModel = ko.observable<Toolbar>();
public acceptChangesButton: ViewModels.Button; public acceptChangesButton: ViewModels.Button;
public discardButton: ViewModels.Button; public discardButton: ViewModels.Button;
public deleteButton: ViewModels.Button; public deleteButton: ViewModels.Button;
@ -54,7 +53,7 @@ export default class ConflictsTab extends TabsBase {
public partitionKeyPropertyHeader: string; public partitionKeyPropertyHeader: string;
public partitionKeyProperty: string; public partitionKeyProperty: string;
public conflictOperation: ko.Observable<string> = ko.observable<string>(); public conflictOperation: ko.Observable<string> = ko.observable<string>();
public conflictIds: ko.ObservableArray<ViewModels.ConflictId>; public conflictIds: ko.ObservableArray<ConflictId>;
private _documentsIterator: MinimalQueryIterator; private _documentsIterator: MinimalQueryIterator;
private _container: Explorer; private _container: Explorer;
@ -70,7 +69,7 @@ export default class ConflictsTab extends TabsBase {
this.editorState = ko.observable<ViewModels.DocumentExplorerState>( this.editorState = ko.observable<ViewModels.DocumentExplorerState>(
ViewModels.DocumentExplorerState.noDocumentSelected ViewModels.DocumentExplorerState.noDocumentSelected
); );
this.selectedConflictId = ko.observable<ViewModels.ConflictId>(); this.selectedConflictId = ko.observable<ConflictId>();
this.selectedConflictContent = editable.observable<any>(""); this.selectedConflictContent = editable.observable<any>("");
this.selectedConflictCurrent = editable.observable<any>(""); this.selectedConflictCurrent = editable.observable<any>("");
this.partitionKey = options.partitionKey || (this.collection && this.collection.partitionKey); this.partitionKey = options.partitionKey || (this.collection && this.collection.partitionKey);
@ -106,14 +105,14 @@ export default class ConflictsTab extends TabsBase {
this.accessibleDocumentList = new AccessibleVerticalList(this.conflictIds()); this.accessibleDocumentList = new AccessibleVerticalList(this.conflictIds());
this.accessibleDocumentList.setOnSelect( this.accessibleDocumentList.setOnSelect(
(selectedDocument: ViewModels.ConflictId) => selectedDocument && selectedDocument.click() (selectedDocument: ConflictId) => selectedDocument && selectedDocument.click()
); );
this.selectedConflictId.subscribe((newSelectedDocumentId: ViewModels.ConflictId) => { this.selectedConflictId.subscribe((newSelectedDocumentId: ConflictId) => {
this.accessibleDocumentList.updateCurrentItem(newSelectedDocumentId); this.accessibleDocumentList.updateCurrentItem(newSelectedDocumentId);
this.conflictOperation(newSelectedDocumentId && newSelectedDocumentId.operationType); this.conflictOperation(newSelectedDocumentId && newSelectedDocumentId.operationType);
}); });
this.conflictIds.subscribe((newDocuments: ViewModels.ConflictId[]) => { this.conflictIds.subscribe((newDocuments: ConflictId[]) => {
this.accessibleDocumentList.updateItemList(newDocuments); this.accessibleDocumentList.updateItemList(newDocuments);
this.dataContentsGridScrollHeight( this.dataContentsGridScrollHeight(
newDocuments.length * DocumentsGridMetrics.IndividualRowHeight + DocumentsGridMetrics.BufferHeight + "px" newDocuments.length * DocumentsGridMetrics.IndividualRowHeight + DocumentsGridMetrics.BufferHeight + "px"
@ -259,7 +258,7 @@ export default class ConflictsTab extends TabsBase {
return true; return true;
}; };
public onConflictIdClick(clickedDocumentId: ViewModels.ConflictId): Q.Promise<any> { public onConflictIdClick(clickedDocumentId: ConflictId): Q.Promise<any> {
if (this.editorState() !== ViewModels.DocumentExplorerState.noDocumentSelected) { if (this.editorState() !== ViewModels.DocumentExplorerState.noDocumentSelected) {
return Q(); return Q();
} }
@ -319,7 +318,7 @@ export default class ConflictsTab extends TabsBase {
.then( .then(
() => { () => {
return deleteConflict(this.collection, selectedConflict).then(() => { return deleteConflict(this.collection, selectedConflict).then(() => {
this.conflictIds.remove((conflictId: ViewModels.ConflictId) => conflictId.rid === selectedConflict.rid); this.conflictIds.remove((conflictId: ConflictId) => conflictId.rid === selectedConflict.rid);
this.selectedConflictContent(""); this.selectedConflictContent("");
this.selectedConflictCurrent(""); this.selectedConflictCurrent("");
this.selectedConflictId(null); this.selectedConflictId(null);
@ -380,7 +379,7 @@ export default class ConflictsTab extends TabsBase {
return deleteConflict(this.collection, selectedConflict) return deleteConflict(this.collection, selectedConflict)
.then( .then(
() => { () => {
this.conflictIds.remove((conflictId: ViewModels.ConflictId) => conflictId.rid === selectedConflict.rid); this.conflictIds.remove((conflictId: ConflictId) => conflictId.rid === selectedConflict.rid);
this.selectedConflictContent(""); this.selectedConflictContent("");
this.selectedConflictCurrent(""); this.selectedConflictCurrent("");
this.selectedConflictId(null); this.selectedConflictId(null);
@ -515,7 +514,7 @@ export default class ConflictsTab extends TabsBase {
}) })
// map raw response to view model // map raw response to view model
.map((rawDocument: any) => { .map((rawDocument: any) => {
return <ViewModels.ConflictId>new ConflictId(this, rawDocument); return <ConflictId>new ConflictId(this, rawDocument);
}); });
const merged = currentConflicts.concat(nextConflictIds); const merged = currentConflicts.concat(nextConflictIds);
@ -580,7 +579,7 @@ export default class ConflictsTab extends TabsBase {
} }
} }
public initDocumentEditorForCreate(documentId: ViewModels.ConflictId, documentToInsert: any): Q.Promise<any> { public initDocumentEditorForCreate(documentId: ConflictId, documentToInsert: any): Q.Promise<any> {
if (documentId) { if (documentId) {
let parsedConflictContent: any = JSON.parse(documentToInsert); let parsedConflictContent: any = JSON.parse(documentToInsert);
const renderedConflictContent: string = this.renderObjectForEditor(parsedConflictContent, null, 4); const renderedConflictContent: string = this.renderObjectForEditor(parsedConflictContent, null, 4);
@ -592,7 +591,7 @@ export default class ConflictsTab extends TabsBase {
} }
public initDocumentEditorForReplace( public initDocumentEditorForReplace(
documentId: ViewModels.ConflictId, documentId: ConflictId,
conflictContent: any, conflictContent: any,
currentContent: any currentContent: any
): Q.Promise<any> { ): Q.Promise<any> {
@ -612,7 +611,7 @@ export default class ConflictsTab extends TabsBase {
return Q(); return Q();
} }
public initDocumentEditorForDelete(documentId: ViewModels.ConflictId, documentToDelete: any): Q.Promise<any> { public initDocumentEditorForDelete(documentId: ConflictId, documentToDelete: any): Q.Promise<any> {
if (documentId) { if (documentId) {
let parsedDocumentToDelete: any = JSON.parse(documentToDelete); let parsedDocumentToDelete: any = JSON.parse(documentToDelete);
parsedDocumentToDelete = ConflictsTab.removeSystemProperties(parsedDocumentToDelete); parsedDocumentToDelete = ConflictsTab.removeSystemProperties(parsedDocumentToDelete);
@ -624,15 +623,15 @@ export default class ConflictsTab extends TabsBase {
return Q(); return Q();
} }
public initDocumentEditorForNoOp(documentId: ViewModels.ConflictId): Q.Promise<any> { public initDocumentEditorForNoOp(documentId: ConflictId): Q.Promise<any> {
this.selectedConflictContent(null); this.selectedConflictContent(null);
this.selectedConflictCurrent(null); this.selectedConflictCurrent(null);
this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected); this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected);
return Q(); return Q();
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
const label = this._acceptButtonLabel(); const label = this._acceptButtonLabel();
if (this.acceptChangesButton.visible()) { if (this.acceptChangesButton.visible()) {
buttons.push({ buttons.push({

View File

@ -19,6 +19,7 @@ import { PlatformType } from "../../PlatformType";
import { RequestOptions } from "@azure/cosmos/dist-esm"; import { RequestOptions } from "@azure/cosmos/dist-esm";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { updateOfferThroughputBeyondLimit, updateOffer } from "../../Common/DocumentClientUtilityBase"; import { updateOfferThroughputBeyondLimit, updateOffer } from "../../Common/DocumentClientUtilityBase";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
const updateThroughputBeyondLimitWarningMessage: string = ` const updateThroughputBeyondLimitWarningMessage: string = `
You are about to request an increase in throughput beyond the pre-allocated capacity. You are about to request an increase in throughput beyond the pre-allocated capacity.
@ -667,8 +668,8 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
} }
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
const label = "Save"; const label = "Save";
if (this.saveSettingsButton.visible()) { if (this.saveSettingsButton.visible()) {
buttons.push({ buttons.push({

View File

@ -3,13 +3,15 @@ import * as ViewModels from "../../Contracts/ViewModels";
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import DocumentsTab from "./DocumentsTab"; import DocumentsTab from "./DocumentsTab";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import DocumentId from "../Tree/DocumentId";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
describe("Documents tab", () => { describe("Documents tab", () => {
describe("buildQuery", () => { describe("buildQuery", () => {
it("should generate the right select query for SQL API", () => { it("should generate the right select query for SQL API", () => {
const documentsTab = new DocumentsTab({ const documentsTab = new DocumentsTab({
partitionKey: null, partitionKey: null,
documentIds: ko.observableArray<ViewModels.DocumentId>(), documentIds: ko.observableArray<DocumentId>(),
tabKind: ViewModels.CollectionTabKind.Documents, tabKind: ViewModels.CollectionTabKind.Documents,
title: "", title: "",
tabPath: "", tabPath: "",
@ -17,7 +19,7 @@ describe("Documents tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable<boolean>(false), isActive: ko.observable<boolean>(false),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(documentsTab.buildQuery("")).toContain("select"); expect(documentsTab.buildQuery("")).toContain("select");
@ -89,7 +91,7 @@ describe("Documents tab", () => {
it("should be false for null or undefined collection", () => { it("should be false for null or undefined collection", () => {
const documentsTab = new DocumentsTab({ const documentsTab = new DocumentsTab({
partitionKey: null, partitionKey: null,
documentIds: ko.observableArray<ViewModels.DocumentId>(), documentIds: ko.observableArray<DocumentId>(),
tabKind: ViewModels.CollectionTabKind.Documents, tabKind: ViewModels.CollectionTabKind.Documents,
title: "", title: "",
tabPath: "", tabPath: "",
@ -97,7 +99,7 @@ describe("Documents tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable<boolean>(false), isActive: ko.observable<boolean>(false),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(documentsTab.showPartitionKey).toBe(false); expect(documentsTab.showPartitionKey).toBe(false);
@ -107,7 +109,7 @@ describe("Documents tab", () => {
const documentsTab = new DocumentsTab({ const documentsTab = new DocumentsTab({
collection: collectionWithoutPartitionKey, collection: collectionWithoutPartitionKey,
partitionKey: null, partitionKey: null,
documentIds: ko.observableArray<ViewModels.DocumentId>(), documentIds: ko.observableArray<DocumentId>(),
tabKind: ViewModels.CollectionTabKind.Documents, tabKind: ViewModels.CollectionTabKind.Documents,
title: "", title: "",
tabPath: "", tabPath: "",
@ -115,7 +117,7 @@ describe("Documents tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable<boolean>(false), isActive: ko.observable<boolean>(false),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(documentsTab.showPartitionKey).toBe(false); expect(documentsTab.showPartitionKey).toBe(false);
@ -125,7 +127,7 @@ describe("Documents tab", () => {
const documentsTab = new DocumentsTab({ const documentsTab = new DocumentsTab({
collection: collectionWithSystemPartitionKey, collection: collectionWithSystemPartitionKey,
partitionKey: null, partitionKey: null,
documentIds: ko.observableArray<ViewModels.DocumentId>(), documentIds: ko.observableArray<DocumentId>(),
tabKind: ViewModels.CollectionTabKind.Documents, tabKind: ViewModels.CollectionTabKind.Documents,
title: "", title: "",
tabPath: "", tabPath: "",
@ -133,7 +135,7 @@ describe("Documents tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable<boolean>(false), isActive: ko.observable<boolean>(false),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(documentsTab.showPartitionKey).toBe(true); expect(documentsTab.showPartitionKey).toBe(true);
@ -143,7 +145,7 @@ describe("Documents tab", () => {
const documentsTab = new DocumentsTab({ const documentsTab = new DocumentsTab({
collection: mongoCollectionWithSystemPartitionKey, collection: mongoCollectionWithSystemPartitionKey,
partitionKey: null, partitionKey: null,
documentIds: ko.observableArray<ViewModels.DocumentId>(), documentIds: ko.observableArray<DocumentId>(),
tabKind: ViewModels.CollectionTabKind.Documents, tabKind: ViewModels.CollectionTabKind.Documents,
title: "", title: "",
tabPath: "", tabPath: "",
@ -151,7 +153,7 @@ describe("Documents tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable<boolean>(false), isActive: ko.observable<boolean>(false),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(documentsTab.showPartitionKey).toBe(false); expect(documentsTab.showPartitionKey).toBe(false);
@ -161,7 +163,7 @@ describe("Documents tab", () => {
const documentsTab = new DocumentsTab({ const documentsTab = new DocumentsTab({
collection: collectionWithNonSystemPartitionKey, collection: collectionWithNonSystemPartitionKey,
partitionKey: null, partitionKey: null,
documentIds: ko.observableArray<ViewModels.DocumentId>(), documentIds: ko.observableArray<DocumentId>(),
tabKind: ViewModels.CollectionTabKind.Documents, tabKind: ViewModels.CollectionTabKind.Documents,
title: "", title: "",
tabPath: "", tabPath: "",
@ -169,7 +171,7 @@ describe("Documents tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable<boolean>(false), isActive: ko.observable<boolean>(false),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(documentsTab.showPartitionKey).toBe(true); expect(documentsTab.showPartitionKey).toBe(true);

View File

@ -15,13 +15,11 @@ import { DocumentsGridMetrics } from "../../Common/Constants";
import { QueryUtils } from "../../Utils/QueryUtils"; import { QueryUtils } from "../../Utils/QueryUtils";
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter"; import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import Toolbar from "../Controls/Toolbar/Toolbar";
import NewDocumentIcon from "../../../images/NewDocument.svg"; import NewDocumentIcon from "../../../images/NewDocument.svg";
import SaveIcon from "../../../images/save-cosmos.svg"; import SaveIcon from "../../../images/save-cosmos.svg";
import DiscardIcon from "../../../images/discard.svg"; import DiscardIcon from "../../../images/discard.svg";
import DeleteDocumentIcon from "../../../images/DeleteDocument.svg"; import DeleteDocumentIcon from "../../../images/DeleteDocument.svg";
import UploadIcon from "../../../images/Upload_16x16.svg"; import UploadIcon from "../../../images/Upload_16x16.svg";
import SynapseIcon from "../../../images/synapse-link.svg";
import { extractPartitionKey, PartitionKeyDefinition, QueryIterator, ItemDefinition, Resource } from "@azure/cosmos"; import { extractPartitionKey, PartitionKeyDefinition, QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils"; import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
@ -33,9 +31,10 @@ import {
updateDocument, updateDocument,
createDocument createDocument
} from "../../Common/DocumentClientUtilityBase"; } from "../../Common/DocumentClientUtilityBase";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
export default class DocumentsTab extends TabsBase implements ViewModels.DocumentsTab { export default class DocumentsTab extends TabsBase {
public selectedDocumentId: ko.Observable<ViewModels.DocumentId>; public selectedDocumentId: ko.Observable<DocumentId>;
public selectedDocumentContent: ViewModels.Editable<string>; public selectedDocumentContent: ViewModels.Editable<string>;
public initialDocumentContent: ko.Observable<string>; public initialDocumentContent: ko.Observable<string>;
public documentContentsGridId: string; public documentContentsGridId: string;
@ -48,7 +47,6 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
public applyFilterButton: ViewModels.Button; public applyFilterButton: ViewModels.Button;
public isEditorDirty: ko.Computed<boolean>; public isEditorDirty: ko.Computed<boolean>;
public editorState: ko.Observable<ViewModels.DocumentExplorerState>; public editorState: ko.Observable<ViewModels.DocumentExplorerState>;
public toolbarViewModel = ko.observable<Toolbar>();
public newDocumentButton: ViewModels.Button; public newDocumentButton: ViewModels.Button;
public saveNewDocumentButton: ViewModels.Button; public saveNewDocumentButton: ViewModels.Button;
public saveExisitingDocumentButton: ViewModels.Button; public saveExisitingDocumentButton: ViewModels.Button;
@ -68,7 +66,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
public partitionKey: DataModels.PartitionKey; public partitionKey: DataModels.PartitionKey;
public partitionKeyPropertyHeader: string; public partitionKeyPropertyHeader: string;
public partitionKeyProperty: string; public partitionKeyProperty: string;
public documentIds: ko.ObservableArray<ViewModels.DocumentId>; public documentIds: ko.ObservableArray<DocumentId>;
private _documentsIterator: QueryIterator<ItemDefinition & Resource>; private _documentsIterator: QueryIterator<ItemDefinition & Resource>;
private _resourceTokenPartitionKey: string; private _resourceTokenPartitionKey: string;
@ -87,7 +85,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
this.editorState = ko.observable<ViewModels.DocumentExplorerState>( this.editorState = ko.observable<ViewModels.DocumentExplorerState>(
ViewModels.DocumentExplorerState.noDocumentSelected ViewModels.DocumentExplorerState.noDocumentSelected
); );
this.selectedDocumentId = ko.observable<ViewModels.DocumentId>(); this.selectedDocumentId = ko.observable<DocumentId>();
this.selectedDocumentContent = editable.observable<string>(""); this.selectedDocumentContent = editable.observable<string>("");
this.initialDocumentContent = ko.observable<string>(""); this.initialDocumentContent = ko.observable<string>("");
this.partitionKey = options.partitionKey || (this.collection && this.collection.partitionKey); this.partitionKey = options.partitionKey || (this.collection && this.collection.partitionKey);
@ -415,7 +413,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
return true; return true;
}; };
public onDocumentIdClick(clickedDocumentId: ViewModels.DocumentId): Q.Promise<any> { public onDocumentIdClick(clickedDocumentId: DocumentId): Q.Promise<any> {
if (this.editorState() !== ViewModels.DocumentExplorerState.noDocumentSelected) { if (this.editorState() !== ViewModels.DocumentExplorerState.noDocumentSelected) {
return Q(); return Q();
} }
@ -528,7 +526,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
const value: string = this.renderObjectForEditor(updatedDocument || {}, null, 4); const value: string = this.renderObjectForEditor(updatedDocument || {}, null, 4);
this.selectedDocumentContent.setBaseline(value); this.selectedDocumentContent.setBaseline(value);
this.initialDocumentContent(value); this.initialDocumentContent(value);
this.documentIds().forEach((documentId: ViewModels.DocumentId) => { this.documentIds().forEach((documentId: DocumentId) => {
if (documentId.rid === updatedDocument._rid) { if (documentId.rid === updatedDocument._rid) {
documentId.id(updatedDocument.id); documentId.id(updatedDocument.id);
} }
@ -669,11 +667,11 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
return window.confirm(msg); return window.confirm(msg);
}; };
protected __deleteDocument(documentId: ViewModels.DocumentId): Q.Promise<any> { protected __deleteDocument(documentId: DocumentId): Q.Promise<any> {
return deleteDocument(this.collection, documentId); return deleteDocument(this.collection, documentId);
} }
private _deleteDocument(selectedDocumentId: ViewModels.DocumentId): Q.Promise<any> { private _deleteDocument(selectedDocumentId: DocumentId): Q.Promise<any> {
this.isExecutionError(false); this.isExecutionError(false);
const startKey: number = TelemetryProcessor.traceStart(Action.DeleteDocument, { const startKey: number = TelemetryProcessor.traceStart(Action.DeleteDocument, {
databaseAccountName: this.collection && this.collection.container.databaseAccount().name, databaseAccountName: this.collection && this.collection.container.databaseAccount().name,
@ -685,7 +683,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
return this.__deleteDocument(selectedDocumentId) return this.__deleteDocument(selectedDocumentId)
.then( .then(
(result: any) => { (result: any) => {
this.documentIds.remove((documentId: ViewModels.DocumentId) => documentId.rid === selectedDocumentId.rid); this.documentIds.remove((documentId: DocumentId) => documentId.rid === selectedDocumentId.rid);
this.selectedDocumentContent(""); this.selectedDocumentContent("");
this.selectedDocumentId(null); this.selectedDocumentId(null);
this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected); this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected);
@ -732,7 +730,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
return queryDocuments(this.collection.databaseId, this.collection.id(), query, options); return queryDocuments(this.collection.databaseId, this.collection.id(), query, options);
} }
public selectDocument(documentId: ViewModels.DocumentId): Q.Promise<any> { public selectDocument(documentId: DocumentId): Q.Promise<any> {
this.selectedDocumentId(documentId); this.selectedDocumentId(documentId);
return readDocument(this.collection, documentId).then((content: any) => { return readDocument(this.collection, documentId).then((content: any) => {
this.initDocumentEditor(documentId, content); this.initDocumentEditor(documentId, content);
@ -755,7 +753,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
// map raw response to view model // map raw response to view model
.map((rawDocument: any) => { .map((rawDocument: any) => {
const partitionKeyValue = rawDocument._partitionKeyValue; const partitionKeyValue = rawDocument._partitionKeyValue;
return <ViewModels.DocumentId>new DocumentId(this, rawDocument, partitionKeyValue); return new DocumentId(this, rawDocument, partitionKeyValue);
}); });
const merged = currentDocuments.concat(nextDocumentIds); const merged = currentDocuments.concat(nextDocumentIds);
@ -826,7 +824,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
} }
} }
public initDocumentEditor(documentId: ViewModels.DocumentId, documentContent: any): Q.Promise<any> { public initDocumentEditor(documentId: DocumentId, documentContent: any): Q.Promise<any> {
if (documentId) { if (documentId) {
const content: string = this.renderObjectForEditor(documentContent, null, 4); const content: string = this.renderObjectForEditor(documentContent, null, 4);
this.selectedDocumentContent.setBaseline(content); this.selectedDocumentContent.setBaseline(content);
@ -844,8 +842,8 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
return QueryUtils.buildDocumentsQuery(filter, this.partitionKeyProperty, this.partitionKey); return QueryUtils.buildDocumentsQuery(filter, this.partitionKeyProperty, this.partitionKey);
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
const label = !this.isPreferredApiMongoDB ? "New Item" : "New Document"; const label = !this.isPreferredApiMongoDB ? "New Item" : "New Document";
if (this.newDocumentButton.visible()) { if (this.newDocumentButton.visible()) {
buttons.push({ buttons.push({
@ -963,7 +961,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
); );
} }
public static _createUploadButton(container: Explorer): ViewModels.NavbarButtonConfig { public static _createUploadButton(container: Explorer): CommandButtonComponentProps {
const label = "Upload Item"; const label = "Upload Item";
return { return {
iconSrc: UploadIcon, iconSrc: UploadIcon,

View File

@ -4,15 +4,26 @@ import { GalleryAndNotebookViewerComponentAdapter } from "../Controls/NotebookGa
import { GalleryTab as GalleryViewerTab, SortBy } from "../Controls/NotebookGallery/GalleryViewerComponent"; import { GalleryTab as GalleryViewerTab, SortBy } from "../Controls/NotebookGallery/GalleryViewerComponent";
import TabsBase from "./TabsBase"; import TabsBase from "./TabsBase";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { DatabaseAccount } from "../../Contracts/DataModels";
import { JunoClient, IGalleryItem } from "../../Juno/JunoClient";
interface GalleryTabOptions extends ViewModels.TabOptions {
account: DatabaseAccount;
container: Explorer;
junoClient: JunoClient;
notebookUrl?: string;
galleryItem?: IGalleryItem;
isFavorite?: boolean;
}
/** /**
* Notebook gallery tab * Notebook gallery tab
*/ */
export default class GalleryTab extends TabsBase implements ViewModels.Tab { export default class GalleryTab extends TabsBase {
private container: Explorer; private container: Explorer;
public galleryAndNotebookViewerComponentAdapter: GalleryAndNotebookViewerComponentAdapter; public galleryAndNotebookViewerComponentAdapter: GalleryAndNotebookViewerComponentAdapter;
constructor(options: ViewModels.GalleryTabOptions) { constructor(options: GalleryTabOptions) {
super(options); super(options);
this.container = options.container; this.container = options.container;

View File

@ -2,13 +2,14 @@ import * as ko from "knockout";
import * as Q from "q"; import * as Q from "q";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import TabsBase from "./TabsBase"; import TabsBase from "./TabsBase";
import Toolbar from "../Controls/Toolbar/Toolbar";
import { GraphExplorerAdapter } from "../Graph/GraphExplorerComponent/GraphExplorerAdapter"; import { GraphExplorerAdapter } from "../Graph/GraphExplorerComponent/GraphExplorerAdapter";
import { GraphAccessor, GraphExplorerError } from "../Graph/GraphExplorerComponent/GraphExplorer"; import { GraphAccessor, GraphExplorerError } from "../Graph/GraphExplorerComponent/GraphExplorer";
import NewVertexIcon from "../../../images/NewVertex.svg"; import NewVertexIcon from "../../../images/NewVertex.svg";
import StyleIcon from "../../../images/Style.svg"; import StyleIcon from "../../../images/Style.svg";
import GraphStylingPane from "../Panes/GraphStylingPane"; import GraphStylingPane from "../Panes/GraphStylingPane";
import NewVertexPane from "../Panes/NewVertexPane"; import NewVertexPane from "../Panes/NewVertexPane";
import { DatabaseAccount } from "../../Contracts/DataModels";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
export interface GraphIconMap { export interface GraphIconMap {
[key: string]: { data: string; format: string }; [key: string]: { data: string; format: string };
@ -26,7 +27,15 @@ export interface GraphConfig {
iconsMap: ko.Observable<GraphIconMap>; iconsMap: ko.Observable<GraphIconMap>;
} }
export default class GraphTab extends TabsBase implements ViewModels.Tab { interface GraphTabOptions extends ViewModels.TabOptions {
account: DatabaseAccount;
masterKey: string;
collectionId: string;
databaseId: string;
collectionPartitionKeyProperty: string;
}
export default class GraphTab extends TabsBase {
// Graph default configuration // Graph default configuration
public static readonly DEFAULT_NODE_CAPTION = "id"; public static readonly DEFAULT_NODE_CAPTION = "id";
private static readonly LINK_COLOR = "#aaa"; private static readonly LINK_COLOR = "#aaa";
@ -38,7 +47,6 @@ export default class GraphTab extends TabsBase implements ViewModels.Tab {
private isPropertyEditing: ko.Observable<boolean>; private isPropertyEditing: ko.Observable<boolean>;
private isGraphDisplayed: ko.Observable<boolean>; private isGraphDisplayed: ko.Observable<boolean>;
private graphAccessor: GraphAccessor; private graphAccessor: GraphAccessor;
public toolbarViewModel: ko.Observable<Toolbar>;
private graphConfig: GraphConfig; private graphConfig: GraphConfig;
private graphConfigUiData: ViewModels.GraphConfigUiData; private graphConfigUiData: ViewModels.GraphConfigUiData;
private isFilterQueryLoading: ko.Observable<boolean>; private isFilterQueryLoading: ko.Observable<boolean>;
@ -47,7 +55,7 @@ export default class GraphTab extends TabsBase implements ViewModels.Tab {
private graphStylingPane: GraphStylingPane; private graphStylingPane: GraphStylingPane;
private collectionPartitionKeyProperty: string; private collectionPartitionKeyProperty: string;
constructor(options: ViewModels.GraphTabOptions) { constructor(options: GraphTabOptions) {
super(options); super(options);
this.newVertexPane = options.collection && options.collection.container.newVertexPane; this.newVertexPane = options.collection && options.collection.container.newVertexPane;
@ -100,10 +108,9 @@ export default class GraphTab extends TabsBase implements ViewModels.Tab {
this.isFilterQueryLoading = ko.observable(false); this.isFilterQueryLoading = ko.observable(false);
this.isValidQuery = ko.observable(true); this.isValidQuery = ko.observable(true);
this.toolbarViewModel = ko.observable<Toolbar>();
} }
public static getGremlinEndpoint(account: ViewModels.DatabaseAccount): string { public static getGremlinEndpoint(account: DatabaseAccount): string {
return account.properties.gremlinEndpoint return account.properties.gremlinEndpoint
? GraphTab.sanitizeHost(account.properties.gremlinEndpoint) ? GraphTab.sanitizeHost(account.properties.gremlinEndpoint)
: `${account.name}.graphs.azure.com:443/`; : `${account.name}.graphs.azure.com:443/`;
@ -202,9 +209,9 @@ export default class GraphTab extends TabsBase implements ViewModels.Tab {
this.graphConfigUiData.nodeIconChoice(this.graphConfigUiData.nodePropertiesWithNone()[0]); this.graphConfigUiData.nodeIconChoice(this.graphConfigUiData.nodePropertiesWithNone()[0]);
} }
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const label = "New Vertex"; const label = "New Vertex";
const buttons: ViewModels.NavbarButtonConfig[] = [ const buttons: CommandButtonComponentProps[] = [
{ {
iconSrc: NewVertexIcon, iconSrc: NewVertexIcon,
iconAlt: label, iconAlt: label,

View File

@ -21,7 +21,7 @@ import { extractPartitionKey } from "@azure/cosmos";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
import { PartitionKeyDefinition } from "@azure/cosmos"; import { PartitionKeyDefinition } from "@azure/cosmos";
export default class MongoDocumentsTab extends DocumentsTab implements ViewModels.DocumentsTab { export default class MongoDocumentsTab extends DocumentsTab {
public collection: ViewModels.Collection; public collection: ViewModels.Collection;
private continuationToken: string; private continuationToken: string;
@ -151,7 +151,7 @@ export default class MongoDocumentsTab extends DocumentsTab implements ViewModel
let value: string = this.renderObjectForEditor(updatedDocument || {}, null, 4); let value: string = this.renderObjectForEditor(updatedDocument || {}, null, 4);
this.selectedDocumentContent.setBaseline(value); this.selectedDocumentContent.setBaseline(value);
this.documentIds().forEach((documentId: ViewModels.DocumentId) => { this.documentIds().forEach((documentId: DocumentId) => {
if (documentId.rid === updatedDocument._rid) { if (documentId.rid === updatedDocument._rid) {
const partitionKeyArray = extractPartitionKey( const partitionKeyArray = extractPartitionKey(
updatedDocument, updatedDocument,
@ -199,7 +199,7 @@ export default class MongoDocumentsTab extends DocumentsTab implements ViewModel
return filter || "{}"; return filter || "{}";
} }
public selectDocument(documentId: ViewModels.DocumentId): Q.Promise<any> { public selectDocument(documentId: DocumentId): Q.Promise<any> {
this.selectedDocumentId(documentId); this.selectedDocumentId(documentId);
return Q( return Q(
readDocument(this.collection.databaseId, this.collection, documentId).then((content: any) => { readDocument(this.collection.databaseId, this.collection, documentId).then((content: any) => {
@ -226,7 +226,7 @@ export default class MongoDocumentsTab extends DocumentsTab implements ViewModel
}) })
.map((rawDocument: any) => { .map((rawDocument: any) => {
const partitionKeyValue = rawDocument._partitionKeyValue; const partitionKeyValue = rawDocument._partitionKeyValue;
return <ViewModels.DocumentId>new DocumentId(this, rawDocument, partitionKeyValue); return new DocumentId(this, rawDocument, partitionKeyValue);
}); });
const merged = currentDocuments.concat(nextDocumentIds); const merged = currentDocuments.concat(nextDocumentIds);
@ -324,7 +324,7 @@ export default class MongoDocumentsTab extends DocumentsTab implements ViewModel
return partitionKey; return partitionKey;
} }
protected __deleteDocument(documentId: ViewModels.DocumentId): Q.Promise<any> { protected __deleteDocument(documentId: DocumentId): Q.Promise<any> {
return Q(deleteDocument(this.collection.databaseId, this.collection, documentId)); return Q(deleteDocument(this.collection.databaseId, this.collection, documentId));
} }
} }

View File

@ -6,7 +6,7 @@ import * as HeadersUtility from "../../Common/HeadersUtility";
import { queryIterator } from "../../Common/MongoProxyClient"; import { queryIterator } from "../../Common/MongoProxyClient";
import { MinimalQueryIterator } from "../../Common/IteratorUtilities"; import { MinimalQueryIterator } from "../../Common/IteratorUtilities";
export default class MongoQueryTab extends QueryTab implements ViewModels.QueryTab { export default class MongoQueryTab extends QueryTab {
public collection: ViewModels.Collection; public collection: ViewModels.Collection;
constructor(options: ViewModels.QueryTabOptions) { constructor(options: ViewModels.QueryTabOptions) {

View File

@ -15,7 +15,7 @@ import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
import { PlatformType } from "../../PlatformType"; import { PlatformType } from "../../PlatformType";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
export default class MongoShellTab extends TabsBase implements ViewModels.MongoShellTab { export default class MongoShellTab extends TabsBase {
public url: ko.Computed<string>; public url: ko.Computed<string>;
private _container: Explorer; private _container: Explorer;
private _runtimeEndpoint: string; private _runtimeEndpoint: string;
@ -26,7 +26,7 @@ export default class MongoShellTab extends TabsBase implements ViewModels.MongoS
this._logTraces = new HashMap<number>(); this._logTraces = new HashMap<number>();
this._container = options.collection.container; this._container = options.collection.container;
this.url = ko.computed<string>(() => { this.url = ko.computed<string>(() => {
const account: ViewModels.DatabaseAccount = CosmosClient.databaseAccount(); const account = CosmosClient.databaseAccount();
const resourceId: string = account && account.id; const resourceId: string = account && account.id;
const accountName = account && account.name; const accountName = account && account.name;
const mongoEndpoint = account && (account.properties.mongoEndpoint || account.properties.documentEndpoint); const mongoEndpoint = account && (account.properties.mongoEndpoint || account.properties.documentEndpoint);

View File

@ -28,15 +28,24 @@ import { NotebookConfigurationUtils } from "../../Utils/NotebookConfigurationUti
import { KernelSpecsDisplay, NotebookClientV2 } from "../Notebook/NotebookClientV2"; import { KernelSpecsDisplay, NotebookClientV2 } from "../Notebook/NotebookClientV2";
import { config } from "../../Config"; import { config } from "../../Config";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { NotebookContentItem } from "../Notebook/NotebookContentItem";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
export default class NotebookTabV2 extends TabsBase implements ViewModels.Tab { export interface NotebookTabOptions extends ViewModels.TabOptions {
account: DataModels.DatabaseAccount;
masterKey: string;
container: Explorer;
notebookContentItem: NotebookContentItem;
}
export default class NotebookTabV2 extends TabsBase {
private static clientManager: NotebookClientV2; private static clientManager: NotebookClientV2;
private container: Explorer; private container: Explorer;
public notebookPath: ko.Observable<string>; public notebookPath: ko.Observable<string>;
private selectedSparkPool: ko.Observable<string>; private selectedSparkPool: ko.Observable<string>;
private notebookComponentAdapter: NotebookComponentAdapter; private notebookComponentAdapter: NotebookComponentAdapter;
constructor(options: ViewModels.NotebookTabOptions) { constructor(options: NotebookTabOptions) {
super(options); super(options);
this.container = options.container; this.container = options.container;
@ -109,7 +118,7 @@ export default class NotebookTabV2 extends TabsBase implements ViewModels.Tab {
return this.container; return this.container;
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const availableKernels = NotebookTabV2.clientManager.getAvailableKernelSpecs(); const availableKernels = NotebookTabV2.clientManager.getAvailableKernelSpecs();
const saveLabel = "Save"; const saveLabel = "Save";
@ -136,7 +145,7 @@ export default class NotebookTabV2 extends TabsBase implements ViewModels.Tab {
const cellCodeType = "code"; const cellCodeType = "code";
const cellMarkdownType = "markdown"; const cellMarkdownType = "markdown";
const cellRawType = "raw"; const cellRawType = "raw";
let buttons: ViewModels.NavbarButtonConfig[] = [ let buttons: CommandButtonComponentProps[] = [
{ {
iconSrc: SaveIcon, iconSrc: SaveIcon,
iconAlt: saveLabel, iconAlt: saveLabel,
@ -188,7 +197,7 @@ export default class NotebookTabV2 extends TabsBase implements ViewModels.Tab {
hasPopup: false, hasPopup: false,
disabled: false, disabled: false,
ariaLabel: kernel.displayName ariaLabel: kernel.displayName
} as ViewModels.NavbarButtonConfig) } as CommandButtonComponentProps)
), ),
ariaLabel: kernelLabel ariaLabel: kernelLabel
}, },
@ -363,7 +372,7 @@ export default class NotebookTabV2 extends TabsBase implements ViewModels.Tab {
]; ];
if (this.container.hasStorageAnalyticsAfecFeature()) { if (this.container.hasStorageAnalyticsAfecFeature()) {
const arcadiaWorkspaceDropdown: ViewModels.NavbarButtonConfig = { const arcadiaWorkspaceDropdown: CommandButtonComponentProps = {
iconSrc: null, iconSrc: null,
iconAlt: workspaceLabel, iconAlt: workspaceLabel,
ariaLabel: workspaceLabel, ariaLabel: workspaceLabel,

View File

@ -8,6 +8,14 @@ import {
} from "../Controls/NotebookViewer/NotebookViewerComponent"; } from "../Controls/NotebookViewer/NotebookViewerComponent";
import TabsBase from "./TabsBase"; import TabsBase from "./TabsBase";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { DatabaseAccount } from "../../Contracts/DataModels";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
interface NotebookViewerTabOptions extends ViewModels.TabOptions {
account: DatabaseAccount;
container: Explorer;
notebookUrl: string;
}
/** /**
* Notebook Viewer tab * Notebook Viewer tab
@ -29,13 +37,13 @@ class NotebookViewerComponentAdapter implements ReactAdapter {
} }
} }
export default class NotebookViewerTab extends TabsBase implements ViewModels.Tab { export default class NotebookViewerTab extends TabsBase {
private container: Explorer; private container: Explorer;
public notebookUrl: string; public notebookUrl: string;
public notebookViewerComponentAdapter: NotebookViewerComponentAdapter; public notebookViewerComponentAdapter: NotebookViewerComponentAdapter;
constructor(options: ViewModels.NotebookViewerTabOptions) { constructor(options: NotebookViewerTabOptions) {
super(options); super(options);
this.container = options.container; this.container = options.container;
this.notebookUrl = options.notebookUrl; this.notebookUrl = options.notebookUrl;
@ -54,7 +62,7 @@ export default class NotebookViewerTab extends TabsBase implements ViewModels.Ta
return this.container; return this.container;
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
return []; return [];
} }

View File

@ -3,11 +3,10 @@ import * as Constants from "../../Common/Constants";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import QueryTab from "./QueryTab"; import QueryTab from "./QueryTab";
import { View } from "@nteract/data-explorer/lib/utilities/types"; import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
import { PartitionKey } from "../../Contracts/DataModels";
describe("Query Tab", () => { describe("Query Tab", () => {
function getNewQueryTabForContainer(container: Explorer): ViewModels.QueryTab { function getNewQueryTabForContainer(container: Explorer): QueryTab {
const database = { const database = {
container: container, container: container,
id: ko.observable<string>("test"), id: ko.observable<string>("test"),
@ -28,7 +27,7 @@ describe("Query Tab", () => {
selfLink: "", selfLink: "",
isActive: ko.observable<boolean>(false), isActive: ko.observable<boolean>(false),
hashLocation: "", hashLocation: "",
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
} }
@ -55,13 +54,13 @@ describe("Query Tab", () => {
it("should be true for accounts using SQL API", () => { it("should be true for accounts using SQL API", () => {
explorer.defaultExperience(Constants.DefaultAccountExperience.DocumentDB.toLowerCase()); explorer.defaultExperience(Constants.DefaultAccountExperience.DocumentDB.toLowerCase());
const queryTab: ViewModels.QueryTab = getNewQueryTabForContainer(explorer); const queryTab = getNewQueryTabForContainer(explorer);
expect(queryTab.isQueryMetricsEnabled()).toBe(true); expect(queryTab.isQueryMetricsEnabled()).toBe(true);
}); });
it("should be false for accounts using other APIs", () => { it("should be false for accounts using other APIs", () => {
explorer.defaultExperience(Constants.DefaultAccountExperience.Graph.toLowerCase()); explorer.defaultExperience(Constants.DefaultAccountExperience.Graph.toLowerCase());
const queryTab: ViewModels.QueryTab = getNewQueryTabForContainer(explorer); const queryTab = getNewQueryTabForContainer(explorer);
expect(queryTab.isQueryMetricsEnabled()).toBe(false); expect(queryTab.isQueryMetricsEnabled()).toBe(false);
}); });
}); });
@ -75,13 +74,13 @@ describe("Query Tab", () => {
it("should be visible when using a supported API", () => { it("should be visible when using a supported API", () => {
explorer.defaultExperience(Constants.DefaultAccountExperience.DocumentDB); explorer.defaultExperience(Constants.DefaultAccountExperience.DocumentDB);
const queryTab: ViewModels.QueryTab = getNewQueryTabForContainer(explorer); const queryTab = getNewQueryTabForContainer(explorer);
expect(queryTab.saveQueryButton.visible()).toBe(true); expect(queryTab.saveQueryButton.visible()).toBe(true);
}); });
it("should not be visible when using an unsupported API", () => { it("should not be visible when using an unsupported API", () => {
explorer.defaultExperience(Constants.DefaultAccountExperience.MongoDB); explorer.defaultExperience(Constants.DefaultAccountExperience.MongoDB);
const queryTab: ViewModels.QueryTab = getNewQueryTabForContainer(explorer); const queryTab = getNewQueryTabForContainer(explorer);
expect(queryTab.saveQueryButton.visible()).toBe(false); expect(queryTab.saveQueryButton.visible()).toBe(false);
}); });
}); });

View File

@ -17,13 +17,14 @@ import SaveQueryIcon from "../../../images/save-cosmos.svg";
import { MinimalQueryIterator } from "../../Common/IteratorUtilities"; import { MinimalQueryIterator } from "../../Common/IteratorUtilities";
import { queryDocuments, queryDocumentsPage } from "../../Common/DocumentClientUtilityBase"; import { queryDocuments, queryDocumentsPage } from "../../Common/DocumentClientUtilityBase";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
enum ToggleState { enum ToggleState {
Result, Result,
QueryMetrics QueryMetrics
} }
export default class QueryTab extends TabsBase implements ViewModels.QueryTab, ViewModels.WaitsForTemplate { export default class QueryTab extends TabsBase implements ViewModels.WaitsForTemplate {
public queryEditorId: string; public queryEditorId: string;
public executeQueryButton: ViewModels.Button; public executeQueryButton: ViewModels.Button;
public fetchNextPageButton: ViewModels.Button; public fetchNextPageButton: ViewModels.Button;
@ -586,8 +587,8 @@ export default class QueryTab extends TabsBase implements ViewModels.QueryTab, V
return csvData; return csvData;
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
if (this.executeQueryButton.visible()) { if (this.executeQueryButton.visible()) {
const label = this._executeQueryButtonTitle(); const label = this._executeQueryButtonTitle();
buttons.push({ buttons.push({

View File

@ -14,6 +14,7 @@ import AddEntityIcon from "../../../images/AddEntity.svg";
import EditEntityIcon from "../../../images/Edit-entity.svg"; import EditEntityIcon from "../../../images/Edit-entity.svg";
import DeleteEntitiesIcon from "../../../images/DeleteEntities.svg"; import DeleteEntitiesIcon from "../../../images/DeleteEntities.svg";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
// Will act as table explorer class // Will act as table explorer class
export default class QueryTablesTab extends TabsBase { export default class QueryTablesTab extends TabsBase {
@ -173,8 +174,8 @@ export default class QueryTablesTab extends TabsBase {
}); });
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
if (this.queryBuilderButton.visible()) { if (this.queryBuilderButton.visible()) {
const label = this.container.isPreferredApiCassandra() ? "CQL Query Builder" : "Query Builder"; const label = this.container.isPreferredApiCassandra() ? "CQL Query Builder" : "Query Builder";
buttons.push({ buttons.push({

View File

@ -9,9 +9,9 @@ import editable from "../../Common/EditableUtility";
import * as monaco from "monaco-editor"; import * as monaco from "monaco-editor";
import SaveIcon from "../../../images/save-cosmos.svg"; import SaveIcon from "../../../images/save-cosmos.svg";
import DiscardIcon from "../../../images/discard.svg"; import DiscardIcon from "../../../images/discard.svg";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
export default abstract class ScriptTabBase extends TabsBase export default abstract class ScriptTabBase extends TabsBase implements ViewModels.WaitsForTemplate {
implements ViewModels.ScriptTab, ViewModels.WaitsForTemplate {
public ariaLabel: ko.Observable<string>; public ariaLabel: ko.Observable<string>;
public editorState: ko.Observable<ViewModels.ScriptEditorState>; public editorState: ko.Observable<ViewModels.ScriptEditorState>;
public id: ViewModels.Editable<string>; public id: ViewModels.Editable<string>;
@ -216,8 +216,8 @@ export default abstract class ScriptTabBase extends TabsBase
return Q(); return Q();
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
const label = "Save"; const label = "Save";
if (this.saveButton.visible()) { if (this.saveButton.visible()) {
buttons.push({ buttons.push({

View File

@ -6,6 +6,7 @@ import Collection from "../Tree/Collection";
import Database from "../Tree/Database"; import Database from "../Tree/Database";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import SettingsTab from "../Tabs/SettingsTab"; import SettingsTab from "../Tabs/SettingsTab";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
describe("Settings tab", () => { describe("Settings tab", () => {
const baseCollection: DataModels.Collection = { const baseCollection: DataModels.Collection = {
@ -189,7 +190,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null), collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(settingsTab.shouldUpdateCollection()).toBe(false); expect(settingsTab.shouldUpdateCollection()).toBe(false);
@ -212,7 +213,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null), collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(settingsTab.shouldUpdateCollection()).toBe(false); expect(settingsTab.shouldUpdateCollection()).toBe(false);
@ -230,7 +231,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null), collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(settingsTab.shouldUpdateCollection()).toBe(false); expect(settingsTab.shouldUpdateCollection()).toBe(false);
@ -268,7 +269,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null), collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(settingsTab.getUpdatedConflictResolutionPolicy()).toBe(null); expect(settingsTab.getUpdatedConflictResolutionPolicy()).toBe(null);
@ -284,7 +285,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null), collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(settingsTab.getUpdatedConflictResolutionPolicy()).toBe(null); expect(settingsTab.getUpdatedConflictResolutionPolicy()).toBe(null);
@ -309,7 +310,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null), collection: new Collection(explorer, "mydb", baseCollection, quotaInfo, null),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
expect(settingsTab.getUpdatedConflictResolutionPolicy()).toBe(null); expect(settingsTab.getUpdatedConflictResolutionPolicy()).toBe(null);
@ -388,7 +389,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: getCollection(defaultApi, partitionKeyOption), collection: getCollection(defaultApi, partitionKeyOption),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
} }
@ -532,7 +533,7 @@ describe("Settings tab", () => {
hashLocation: "", hashLocation: "",
isActive: ko.observable(false), isActive: ko.observable(false),
collection: getCollection(autoPilotTier), collection: getCollection(autoPilotTier),
onUpdateTabsButtons: (buttons: ViewModels.NavbarButtonConfig[]): void => {} onUpdateTabsButtons: (buttons: CommandButtonComponentProps[]): void => {}
}); });
} }
describe("Visible", () => { describe("Visible", () => {

View File

@ -23,6 +23,7 @@ import {
updateOffer, updateOffer,
updateCollection updateCollection
} from "../../Common/DocumentClientUtilityBase"; } from "../../Common/DocumentClientUtilityBase";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
const ttlWarning: string = ` const ttlWarning: string = `
The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application. The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application.
@ -412,14 +413,14 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
}); });
this.isAutoScaleEnabled = ko.pureComputed<boolean>(() => { this.isAutoScaleEnabled = ko.pureComputed<boolean>(() => {
const accountCapabilities: ViewModels.Capability[] = const accountCapabilities: DataModels.Capability[] =
this.container && this.container &&
this.container.databaseAccount() && this.container.databaseAccount() &&
this.container.databaseAccount().properties && this.container.databaseAccount().properties &&
this.container.databaseAccount().properties.capabilities; this.container.databaseAccount().properties.capabilities;
const enableAutoScaleCapability: ViewModels.Capability = const enableAutoScaleCapability =
accountCapabilities && accountCapabilities &&
_.find(accountCapabilities, (capability: ViewModels.Capability) => { _.find(accountCapabilities, capability => {
return ( return (
capability && capability &&
capability.name && capability.name &&
@ -1692,8 +1693,8 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
return document.getElementById(this.indexingPolicyEditorId); return document.getElementById(this.indexingPolicyEditorId);
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
if (this.saveSettingsButton.visible()) { if (this.saveSettingsButton.visible()) {
const label = "Save"; const label = "Save";
buttons.push({ buttons.push({

View File

@ -4,13 +4,18 @@ import * as ViewModels from "../../Contracts/ViewModels";
import TabsBase from "./TabsBase"; import TabsBase from "./TabsBase";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
interface SparkMasterTabOptions extends ViewModels.TabOptions {
clusterConnectionInfo: DataModels.SparkClusterConnectionInfo;
container: Explorer;
}
export default class SparkMasterTab extends TabsBase { export default class SparkMasterTab extends TabsBase {
public sparkMasterSrc: ko.Observable<string>; public sparkMasterSrc: ko.Observable<string>;
private _clusterConnectionInfo: DataModels.SparkClusterConnectionInfo; private _clusterConnectionInfo: DataModels.SparkClusterConnectionInfo;
private _container: Explorer; private _container: Explorer;
constructor(options: ViewModels.SparkMasterTabOptions) { constructor(options: SparkMasterTabOptions) {
super(options); super(options);
super.onActivate.bind(this); super.onActivate.bind(this);
this._container = options.container; this._container = options.container;

View File

@ -11,13 +11,14 @@ import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg"; import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
import StoredProcedure from "../Tree/StoredProcedure"; import StoredProcedure from "../Tree/StoredProcedure";
import { createStoredProcedure, updateStoredProcedure } from "../../Common/DocumentClientUtilityBase"; import { createStoredProcedure, updateStoredProcedure } from "../../Common/DocumentClientUtilityBase";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
enum ToggleState { enum ToggleState {
Result = "result", Result = "result",
Logs = "logs" Logs = "logs"
} }
export default class StoredProcedureTab extends ScriptTabBase implements ViewModels.StoredProcedureTab { export default class StoredProcedureTab extends ScriptTabBase {
public collection: ViewModels.Collection; public collection: ViewModels.Collection;
public node: StoredProcedure; public node: StoredProcedure;
public executeResultsEditorId: string; public executeResultsEditorId: string;
@ -204,7 +205,7 @@ export default class StoredProcedureTab extends ScriptTabBase implements ViewMod
super.buildCommandBarOptions(); super.buildCommandBarOptions();
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const label = "Execute"; const label = "Execute";
return super.getTabsButtons().concat({ return super.getTabsButtons().concat({
iconSrc: ExecuteQueryIcon, iconSrc: ExecuteQueryIcon,

View File

@ -8,9 +8,10 @@ import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import ThemeUtility from "../../Common/ThemeUtility"; import ThemeUtility from "../../Common/ThemeUtility";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
// TODO: Use specific actions for logging telemetry data // TODO: Use specific actions for logging telemetry data
export default class TabsBase extends WaitsForTemplateViewModel implements ViewModels.Tab { export default class TabsBase extends WaitsForTemplateViewModel {
public closeTabButton: ViewModels.Button; public closeTabButton: ViewModels.Button;
public node: ViewModels.TreeNode; public node: ViewModels.TreeNode;
public collection: ViewModels.CollectionBase; public collection: ViewModels.CollectionBase;
@ -187,7 +188,7 @@ export default class TabsBase extends WaitsForTemplateViewModel implements ViewM
/** /**
* @return buttons that are displayed in the navbar * @return buttons that are displayed in the navbar
*/ */
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
return []; return [];
} }

View File

@ -1,9 +1,11 @@
import * as ko from "knockout"; import * as ko from "knockout";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import * as DataModels from "../../Contracts/DataModels";
import { TabsManager } from "./TabsManager"; import { TabsManager } from "./TabsManager";
import DocumentsTab from "./DocumentsTab"; import DocumentsTab from "./DocumentsTab";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import QueryTab from "./QueryTab"; import QueryTab from "./QueryTab";
import DocumentId from "../Tree/DocumentId";
describe("Tabs manager tests", () => { describe("Tabs manager tests", () => {
let tabsManager: TabsManager; let tabsManager: TabsManager;
@ -15,7 +17,7 @@ describe("Tabs manager tests", () => {
beforeAll(() => { beforeAll(() => {
explorer = new Explorer({ notificationsClient: undefined, isEmulator: false }); explorer = new Explorer({ notificationsClient: undefined, isEmulator: false });
explorer.databaseAccount = ko.observable<ViewModels.DatabaseAccount>({ explorer.databaseAccount = ko.observable<DataModels.DatabaseAccount>({
id: "test", id: "test",
name: "test", name: "test",
location: "", location: "",
@ -56,7 +58,7 @@ describe("Tabs manager tests", () => {
documentsTab = new DocumentsTab({ documentsTab = new DocumentsTab({
partitionKey: undefined, partitionKey: undefined,
documentIds: ko.observableArray<ViewModels.DocumentId>(), documentIds: ko.observableArray<DocumentId>(),
tabKind: ViewModels.CollectionTabKind.Documents, tabKind: ViewModels.CollectionTabKind.Documents,
collection, collection,
title: "", title: "",
@ -102,13 +104,13 @@ describe("Tabs manager tests", () => {
tabsManager.activateNewTab(queryTab); tabsManager.activateNewTab(queryTab);
tabsManager.activateNewTab(documentsTab); tabsManager.activateNewTab(documentsTab);
const queryTabs: ViewModels.Tab[] = tabsManager.getTabs(ViewModels.CollectionTabKind.Query); const queryTabs = tabsManager.getTabs(ViewModels.CollectionTabKind.Query);
expect(queryTabs.length).toBe(1); expect(queryTabs.length).toBe(1);
expect(queryTabs[0]).toEqual(queryTab); expect(queryTabs[0]).toEqual(queryTab);
const documentsTabs: ViewModels.Tab[] = tabsManager.getTabs( const documentsTabs = tabsManager.getTabs(
ViewModels.CollectionTabKind.Documents, ViewModels.CollectionTabKind.Documents,
(tab: ViewModels.Tab) => tab.tabId === documentsTab.tabId tab => tab.tabId === documentsTab.tabId
); );
expect(documentsTabs.length).toBe(1); expect(documentsTabs.length).toBe(1);
expect(documentsTabs[0]).toEqual(documentsTab); expect(documentsTabs[0]).toEqual(documentsTab);
@ -125,7 +127,7 @@ describe("Tabs manager tests", () => {
expect(queryTab.isActive()).toBe(true); expect(queryTab.isActive()).toBe(true);
expect(documentsTab.isActive()).toBe(false); expect(documentsTab.isActive()).toBe(false);
tabsManager.closeTabsByComparator((tab: ViewModels.Tab) => tab.tabId === queryTab.tabId); tabsManager.closeTabsByComparator(tab => tab.tabId === queryTab.tabId);
expect(tabsManager.openedTabs().length).toBe(0); expect(tabsManager.openedTabs().length).toBe(0);
expect(tabsManager.activeTab()).toEqual(undefined); expect(tabsManager.activeTab()).toEqual(undefined);
expect(queryTab.isActive()).toBe(false); expect(queryTab.isActive()).toBe(false);

View File

@ -2,39 +2,37 @@ import * as ko from "knockout";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import TabsManagerTemplate from "./TabsManager.html"; import TabsManagerTemplate from "./TabsManager.html";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import TabsBase from "./TabsBase";
export class TabsManager { export class TabsManager {
public openedTabs: ko.ObservableArray<ViewModels.Tab>; public openedTabs: ko.ObservableArray<TabsBase>;
public activeTab: ko.Observable<ViewModels.Tab>; public activeTab: ko.Observable<TabsBase>;
constructor() { constructor() {
this.openedTabs = ko.observableArray<ViewModels.Tab>([]); this.openedTabs = ko.observableArray<TabsBase>([]);
this.activeTab = ko.observable<ViewModels.Tab>(); this.activeTab = ko.observable<TabsBase>();
} }
public activateNewTab(tab: ViewModels.Tab): void { public activateNewTab(tab: TabsBase): void {
this.openedTabs.push(tab); this.openedTabs.push(tab);
this.activateTab(tab); this.activateTab(tab);
} }
public activateTab(tab: ViewModels.Tab): void { public activateTab(tab: TabsBase): void {
this.activeTab() && this.activeTab().isActive(false); this.activeTab() && this.activeTab().isActive(false);
tab.isActive(true); tab.isActive(true);
this.activeTab(tab); this.activeTab(tab);
} }
public getTabs( public getTabs(tabKind: ViewModels.CollectionTabKind, comparator?: (tab: TabsBase) => boolean): TabsBase[] {
tabKind: ViewModels.CollectionTabKind, return this.openedTabs().filter((openedTab: TabsBase) => {
comparator?: (tab: ViewModels.Tab) => boolean
): ViewModels.Tab[] {
return this.openedTabs().filter((openedTab: ViewModels.Tab) => {
return openedTab.tabKind === tabKind && (!comparator || comparator(openedTab)); return openedTab.tabKind === tabKind && (!comparator || comparator(openedTab));
}); });
} }
public refreshActiveTab(comparator: (tab: ViewModels.Tab) => boolean): void { public refreshActiveTab(comparator: (tab: TabsBase) => boolean): void {
// ensures that the tab selects/highlights the right node based on resource tree expand/collapse state // ensures that the tab selects/highlights the right node based on resource tree expand/collapse state
this.openedTabs().forEach((tab: ViewModels.Tab) => { this.openedTabs().forEach((tab: TabsBase) => {
if (comparator(tab) && tab.isActive()) { if (comparator(tab) && tab.isActive()) {
tab.onActivate(); tab.onActivate();
} }
@ -42,17 +40,17 @@ export class TabsManager {
} }
public removeTabById(tabId: string): void { public removeTabById(tabId: string): void {
this.openedTabs.remove((tab: ViewModels.Tab) => tab.tabId === tabId); this.openedTabs.remove((tab: TabsBase) => tab.tabId === tabId);
} }
public removeTabByComparator(comparator: (tab: ViewModels.Tab) => boolean): void { public removeTabByComparator(comparator: (tab: TabsBase) => boolean): void {
this.openedTabs.remove((tab: ViewModels.Tab) => comparator(tab)); this.openedTabs.remove((tab: TabsBase) => comparator(tab));
} }
public closeTabsByComparator(comparator: (tab: ViewModels.Tab) => boolean): void { public closeTabsByComparator(comparator: (tab: TabsBase) => boolean): void {
this.activeTab() && this.activeTab().isActive(false); this.activeTab() && this.activeTab().isActive(false);
this.activeTab(undefined); this.activeTab(undefined);
this.openedTabs().forEach((tab: ViewModels.Tab) => { this.openedTabs().forEach((tab: TabsBase) => {
if (comparator(tab)) { if (comparator(tab)) {
tab.onCloseTabButtonClick(); tab.onCloseTabButtonClick();
} }
@ -64,9 +62,9 @@ export class TabsManager {
} }
public closeTab(tabId: string, explorer: Explorer): void { public closeTab(tabId: string, explorer: Explorer): void {
const tabIndex: number = this.openedTabs().findIndex((tab: ViewModels.Tab) => tab.tabId === tabId); const tabIndex: number = this.openedTabs().findIndex((tab: TabsBase) => tab.tabId === tabId);
if (tabIndex !== -1) { if (tabIndex !== -1) {
const tabToActive: ViewModels.Tab = this.openedTabs()[tabIndex + 1] || this.openedTabs()[tabIndex - 1]; const tabToActive: TabsBase = this.openedTabs()[tabIndex + 1] || this.openedTabs()[tabIndex - 1];
this.openedTabs()[tabIndex].isActive(false); this.openedTabs()[tabIndex].isActive(false);
this.removeTabById(tabId); this.removeTabById(tabId);
if (tabToActive) { if (tabToActive) {

View File

@ -6,6 +6,13 @@ import * as React from "react";
import { ReactAdapter } from "../../Bindings/ReactBindingHandler"; import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
import { NotebookTerminalComponent } from "../Controls/Notebook/NotebookTerminalComponent"; import { NotebookTerminalComponent } from "../Controls/Notebook/NotebookTerminalComponent";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
export interface TerminalTabOptions extends ViewModels.TabOptions {
account: DataModels.DatabaseAccount;
container: Explorer;
kind: ViewModels.TerminalKind;
}
/** /**
* Notebook terminal tab * Notebook terminal tab
@ -30,11 +37,11 @@ class NotebookTerminalComponentAdapter implements ReactAdapter {
} }
} }
export default class TerminalTab extends TabsBase implements ViewModels.Tab { export default class TerminalTab extends TabsBase {
private container: Explorer; private container: Explorer;
private notebookTerminalComponentAdapter: NotebookTerminalComponentAdapter; private notebookTerminalComponentAdapter: NotebookTerminalComponentAdapter;
constructor(options: ViewModels.TerminalTabOptions) { constructor(options: TerminalTabOptions) {
super(options); super(options);
this.container = options.container; this.container = options.container;
this.notebookTerminalComponentAdapter = new NotebookTerminalComponentAdapter( this.notebookTerminalComponentAdapter = new NotebookTerminalComponentAdapter(
@ -53,15 +60,15 @@ export default class TerminalTab extends TabsBase implements ViewModels.Tab {
return this.container; return this.container;
} }
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] { protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: ViewModels.NavbarButtonConfig[] = []; const buttons: CommandButtonComponentProps[] = [];
return buttons; return buttons;
} }
protected buildCommandBarOptions(): void { protected buildCommandBarOptions(): void {
this.updateNavbarWithTabsButtons(); this.updateNavbarWithTabsButtons();
} }
private getNotebookServerInfo(options: ViewModels.TerminalTabOptions): DataModels.NotebookWorkspaceConnectionInfo { private getNotebookServerInfo(options: TerminalTabOptions): DataModels.NotebookWorkspaceConnectionInfo {
let endpointSuffix: string; let endpointSuffix: string;
switch (options.kind) { switch (options.kind) {

View File

@ -9,7 +9,7 @@ import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import Trigger from "../Tree/Trigger"; import Trigger from "../Tree/Trigger";
import { createTrigger, updateTrigger } from "../../Common/DocumentClientUtilityBase"; import { createTrigger, updateTrigger } from "../../Common/DocumentClientUtilityBase";
export default class TriggerTab extends ScriptTabBase implements ViewModels.TriggerTab { export default class TriggerTab extends ScriptTabBase {
public collection: ViewModels.Collection; public collection: ViewModels.Collection;
public node: Trigger; public node: Trigger;
public triggerType: ViewModels.Editable<string>; public triggerType: ViewModels.Editable<string>;

View File

@ -8,7 +8,7 @@ import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import UserDefinedFunction from "../Tree/UserDefinedFunction"; import UserDefinedFunction from "../Tree/UserDefinedFunction";
import { createUserDefinedFunction, updateUserDefinedFunction } from "../../Common/DocumentClientUtilityBase"; import { createUserDefinedFunction, updateUserDefinedFunction } from "../../Common/DocumentClientUtilityBase";
export default class UserDefinedFunctionTab extends ScriptTabBase implements ViewModels.UserDefinedFunctionTab { export default class UserDefinedFunctionTab extends ScriptTabBase {
public collection: ViewModels.Collection; public collection: ViewModels.Collection;
public node: UserDefinedFunction; public node: UserDefinedFunction;
constructor(options: ViewModels.ScriptTabOption) { constructor(options: ViewModels.ScriptTabOption) {

View File

@ -240,9 +240,7 @@ export default class Collection implements ViewModels.Collection {
this.expandCollection(); this.expandCollection();
} }
this.container.onUpdateTabsButtons([]); this.container.onUpdateTabsButtons([]);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.rid === this.rid);
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid
);
} }
public collapseCollection() { public collapseCollection() {
@ -293,7 +291,7 @@ export default class Collection implements ViewModels.Collection {
const documentsTabs: DocumentsTab[] = this.container.tabsManager.getTabs( const documentsTabs: DocumentsTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.Documents, ViewModels.CollectionTabKind.Documents,
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid tab => tab.collection && tab.collection.rid === this.rid
) as DocumentsTab[]; ) as DocumentsTab[];
let documentsTab: DocumentsTab = documentsTabs && documentsTabs[0]; let documentsTab: DocumentsTab = documentsTabs && documentsTabs[0];
@ -344,7 +342,7 @@ export default class Collection implements ViewModels.Collection {
const conflictsTabs: ConflictsTab[] = this.container.tabsManager.getTabs( const conflictsTabs: ConflictsTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.Conflicts, ViewModels.CollectionTabKind.Conflicts,
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid tab => tab.collection && tab.collection.rid === this.rid
) as ConflictsTab[]; ) as ConflictsTab[];
let conflictsTab: ConflictsTab = conflictsTabs && conflictsTabs[0]; let conflictsTab: ConflictsTab = conflictsTabs && conflictsTabs[0];
@ -401,7 +399,7 @@ export default class Collection implements ViewModels.Collection {
const queryTablesTabs: QueryTablesTab[] = this.container.tabsManager.getTabs( const queryTablesTabs: QueryTablesTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.QueryTables, ViewModels.CollectionTabKind.QueryTables,
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid tab => tab.collection && tab.collection.rid === this.rid
) as QueryTablesTab[]; ) as QueryTablesTab[];
let queryTablesTab: QueryTablesTab = queryTablesTabs && queryTablesTabs[0]; let queryTablesTab: QueryTablesTab = queryTablesTabs && queryTablesTabs[0];
@ -455,7 +453,7 @@ export default class Collection implements ViewModels.Collection {
const graphTabs: GraphTab[] = this.container.tabsManager.getTabs( const graphTabs: GraphTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.Graph, ViewModels.CollectionTabKind.Graph,
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid tab => tab.collection && tab.collection.rid === this.rid
) as GraphTab[]; ) as GraphTab[];
let graphTab: GraphTab = graphTabs && graphTabs[0]; let graphTab: GraphTab = graphTabs && graphTabs[0];
@ -511,7 +509,7 @@ export default class Collection implements ViewModels.Collection {
const mongoDocumentsTabs: MongoDocumentsTab[] = this.container.tabsManager.getTabs( const mongoDocumentsTabs: MongoDocumentsTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.Documents, ViewModels.CollectionTabKind.Documents,
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid tab => tab.collection && tab.collection.rid === this.rid
) as MongoDocumentsTab[]; ) as MongoDocumentsTab[];
let mongoDocumentsTab: MongoDocumentsTab = mongoDocumentsTabs && mongoDocumentsTabs[0]; let mongoDocumentsTab: MongoDocumentsTab = mongoDocumentsTabs && mongoDocumentsTabs[0];
@ -562,12 +560,9 @@ export default class Collection implements ViewModels.Collection {
const tabTitle = !this.offer() ? "Settings" : "Scale & Settings"; const tabTitle = !this.offer() ? "Settings" : "Scale & Settings";
const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification(); const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification();
const matchingTabs: ViewModels.Tab[] = this.container.tabsManager.getTabs( const matchingTabs = this.container.tabsManager.getTabs(ViewModels.CollectionTabKind.Settings, tab => {
ViewModels.CollectionTabKind.Settings, return tab.collection && tab.collection.rid === this.rid;
(tab: ViewModels.Tab) => { });
return tab.collection && tab.collection.rid === this.rid;
}
);
let settingsTab: SettingsTab = matchingTabs && (matchingTabs[0] as SettingsTab); let settingsTab: SettingsTab = matchingTabs && (matchingTabs[0] as SettingsTab);
if (!settingsTab) { if (!settingsTab) {
@ -902,9 +897,7 @@ export default class Collection implements ViewModels.Collection {
} else { } else {
this.expandStoredProcedures(); this.expandStoredProcedures();
} }
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.rid === this.rid);
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid
);
} }
public expandStoredProcedures() { public expandStoredProcedures() {
@ -961,9 +954,7 @@ export default class Collection implements ViewModels.Collection {
} else { } else {
this.expandUserDefinedFunctions(); this.expandUserDefinedFunctions();
} }
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.rid === this.rid);
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid
);
} }
public expandUserDefinedFunctions() { public expandUserDefinedFunctions() {
@ -1020,9 +1011,7 @@ export default class Collection implements ViewModels.Collection {
} else { } else {
this.expandTriggers(); this.expandTriggers();
} }
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.rid === this.rid);
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid
);
} }
public expandTriggers() { public expandTriggers() {

View File

@ -8,7 +8,7 @@ import { extractPartitionKey } from "@azure/cosmos";
import ConflictsTab from "../Tabs/ConflictsTab"; import ConflictsTab from "../Tabs/ConflictsTab";
import { readDocument } from "../../Common/DocumentClientUtilityBase"; import { readDocument } from "../../Common/DocumentClientUtilityBase";
export default class ConflictId implements ViewModels.ConflictId { export default class ConflictId {
public container: ConflictsTab; public container: ConflictsTab;
public rid: string; public rid: string;
public self: string; public self: string;
@ -115,7 +115,7 @@ export default class ConflictId implements ViewModels.ConflictId {
return JSON.stringify(partitionKeyValue); return JSON.stringify(partitionKeyValue);
} }
public buildDocumentIdFromConflict(partitionKeyValue: any): ViewModels.DocumentId { public buildDocumentIdFromConflict(partitionKeyValue: any): DocumentId {
const conflictDocumentRid = Constants.HashRoutePrefixes.docsWithIds( const conflictDocumentRid = Constants.HashRoutePrefixes.docsWithIds(
this.container.collection.getDatabase().rid, this.container.collection.getDatabase().rid,
this.container.collection.rid, this.container.collection.rid,

View File

@ -52,9 +52,9 @@ export default class Database implements ViewModels.Database {
}); });
const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification(); const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification();
const matchingTabs: ViewModels.Tab[] = this.container.tabsManager.getTabs( const matchingTabs = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.DatabaseSettings, ViewModels.CollectionTabKind.DatabaseSettings,
(tab: ViewModels.Tab) => tab.rid === this.rid tab => tab.rid === this.rid
); );
let settingsTab: DatabaseSettingsTab = matchingTabs && (matchingTabs[0] as DatabaseSettingsTab); let settingsTab: DatabaseSettingsTab = matchingTabs && (matchingTabs[0] as DatabaseSettingsTab);
if (!settingsTab) { if (!settingsTab) {
@ -223,9 +223,7 @@ export default class Database implements ViewModels.Database {
this.expandDatabase(); this.expandDatabase();
} }
this.container.onUpdateTabsButtons([]); this.container.onUpdateTabsButtons([]);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.getDatabase().rid === this.rid);
(tab: ViewModels.Tab) => tab.collection && tab.collection.getDatabase().rid === this.rid
);
} }
public expandDatabase() { public expandDatabase() {

View File

@ -1,9 +1,9 @@
import * as ko from "knockout"; import * as ko from "knockout";
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels"; import DocumentsTab from "../Tabs/DocumentsTab";
export default class DocumentId implements ViewModels.DocumentId { export default class DocumentId {
public container: ViewModels.DocumentsTab; public container: DocumentsTab;
public rid: string; public rid: string;
public self: string; public self: string;
public ts: string; public ts: string;
@ -14,7 +14,7 @@ export default class DocumentId implements ViewModels.DocumentId {
public stringPartitionKeyValue: string; public stringPartitionKeyValue: string;
public isDirty: ko.Observable<boolean>; public isDirty: ko.Observable<boolean>;
constructor(container: ViewModels.DocumentsTab, data: any, partitionKeyValue: any) { constructor(container: DocumentsTab, data: any, partitionKeyValue: any) {
this.container = container; this.container = container;
this.self = data._self; this.self = data._self;
this.rid = data._rid; this.rid = data._rid;

View File

@ -1,9 +1,9 @@
import * as ko from "knockout"; import * as ko from "knockout";
import * as ViewModels from "../../Contracts/ViewModels";
import DocumentId from "./DocumentId"; import DocumentId from "./DocumentId";
import DocumentsTab from "../Tabs/DocumentsTab";
export default class ObjectId extends DocumentId implements ViewModels.DocumentId { export default class ObjectId extends DocumentId {
constructor(container: ViewModels.DocumentsTab, data: any, partitionKeyValue: any) { constructor(container: DocumentsTab, data: any, partitionKeyValue: any) {
super(container, data, partitionKeyValue); super(container, data, partitionKeyValue);
if (typeof data._id === "object") { if (typeof data._id === "object") {
this.id = ko.observable(data._id[Object.keys(data._id)[0]]); this.id = ko.observable(data._id[Object.keys(data._id)[0]]);

View File

@ -9,6 +9,7 @@ import Q from "q";
import QueryTab from "../Tabs/QueryTab"; import QueryTab from "../Tabs/QueryTab";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import TabsBase from "../Tabs/TabsBase";
export default class ResourceTokenCollection implements ViewModels.CollectionBase { export default class ResourceTokenCollection implements ViewModels.CollectionBase {
public nodeKind: string; public nodeKind: string;
@ -120,7 +121,7 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
const documentsTabs: DocumentsTab[] = this.container.tabsManager.getTabs( const documentsTabs: DocumentsTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.Documents, ViewModels.CollectionTabKind.Documents,
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid (tab: TabsBase) => tab.collection && tab.collection.rid === this.rid
) as DocumentsTab[]; ) as DocumentsTab[];
let documentsTab: DocumentsTab = documentsTabs && documentsTabs[0]; let documentsTab: DocumentsTab = documentsTabs && documentsTabs[0];

View File

@ -30,6 +30,7 @@ import Explorer from "../Explorer";
import UserDefinedFunction from "./UserDefinedFunction"; import UserDefinedFunction from "./UserDefinedFunction";
import StoredProcedure from "./StoredProcedure"; import StoredProcedure from "./StoredProcedure";
import Trigger from "./Trigger"; import Trigger from "./Trigger";
import TabsBase from "../Tabs/TabsBase";
export class ResourceTreeAdapter implements ReactAdapter { export class ResourceTreeAdapter implements ReactAdapter {
private static readonly DataTitle = "DATA"; private static readonly DataTitle = "DATA";
@ -50,7 +51,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
this.parameters = ko.observable(Date.now()); this.parameters = ko.observable(Date.now());
this.container.selectedNode.subscribe((newValue: any) => this.triggerRender()); this.container.selectedNode.subscribe((newValue: any) => this.triggerRender());
this.container.tabsManager.activeTab.subscribe((newValue: ViewModels.Tab) => this.triggerRender()); this.container.tabsManager.activeTab.subscribe((newValue: TabsBase) => this.triggerRender());
this.container.isNotebookEnabled.subscribe(newValue => this.triggerRender()); this.container.isNotebookEnabled.subscribe(newValue => this.triggerRender());
this.koSubsDatabaseIdMap = new ArrayHashMap(); this.koSubsDatabaseIdMap = new ArrayHashMap();
@ -176,7 +177,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
database.selectDatabase(); database.selectDatabase();
this.container.onUpdateTabsButtons([]); this.container.onUpdateTabsButtons([]);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(
(tab: ViewModels.Tab) => tab.collection && tab.collection.getDatabase().rid === database.rid (tab: TabsBase) => tab.collection && tab.collection.getDatabase().rid === database.rid
); );
}, },
onContextMenuOpen: () => this.container.selectedNode(database) onContextMenuOpen: () => this.container.selectedNode(database)
@ -275,7 +276,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
this.container.selectedNode(collection); this.container.selectedNode(collection);
this.container.onUpdateTabsButtons([]); this.container.onUpdateTabsButtons([]);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === collection.rid (tab: TabsBase) => tab.collection && tab.collection.rid === collection.rid
); );
}, },
onExpanded: () => { onExpanded: () => {
@ -303,7 +304,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
onClick: () => { onClick: () => {
collection.selectedSubnodeKind(ViewModels.CollectionTabKind.StoredProcedures); collection.selectedSubnodeKind(ViewModels.CollectionTabKind.StoredProcedures);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === collection.rid (tab: TabsBase) => tab.collection && tab.collection.rid === collection.rid
); );
} }
}; };
@ -322,7 +323,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
onClick: () => { onClick: () => {
collection.selectedSubnodeKind(ViewModels.CollectionTabKind.UserDefinedFunctions); collection.selectedSubnodeKind(ViewModels.CollectionTabKind.UserDefinedFunctions);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === collection.rid (tab: TabsBase) => tab.collection && tab.collection.rid === collection.rid
); );
} }
}; };
@ -340,7 +341,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
onClick: () => { onClick: () => {
collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Triggers); collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Triggers);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === collection.rid (tab: TabsBase) => tab.collection && tab.collection.rid === collection.rid
); );
} }
}; };

View File

@ -16,10 +16,9 @@ export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
public constructor(private container: Explorer) { public constructor(private container: Explorer) {
this.parameters = ko.observable(Date.now()); this.parameters = ko.observable(Date.now());
this.container.resourceTokenCollection.subscribe((collection: ViewModels.CollectionBase) => this.triggerRender()); this.container.resourceTokenCollection.subscribe(() => this.triggerRender());
this.container.selectedNode.subscribe((newValue: any) => this.triggerRender()); this.container.selectedNode.subscribe((newValue: any) => this.triggerRender());
this.container.tabsManager && this.container.tabsManager && this.container.tabsManager.activeTab.subscribe(() => this.triggerRender());
this.container.tabsManager.activeTab.subscribe((newValue: ViewModels.Tab) => this.triggerRender());
this.triggerRender(); this.triggerRender();
} }
@ -65,9 +64,7 @@ export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
// Rewritten version of expandCollapseCollection // Rewritten version of expandCollapseCollection
this.container.selectedNode(collection); this.container.selectedNode(collection);
this.container.onUpdateTabsButtons([]); this.container.onUpdateTabsButtons([]);
this.container.tabsManager.refreshActiveTab( this.container.tabsManager.refreshActiveTab(tab => tab.collection && tab.collection.rid === collection.rid);
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === collection.rid
);
}, },
isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", undefined) isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", undefined)
}; };

View File

@ -8,6 +8,7 @@ import StoredProcedureTab from "../Tabs/StoredProcedureTab";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import { deleteStoredProcedure, executeStoredProcedure } from "../../Common/DocumentClientUtilityBase"; import { deleteStoredProcedure, executeStoredProcedure } from "../../Common/DocumentClientUtilityBase";
import TabsBase from "../Tabs/TabsBase";
const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE
function sample(prefix) { function sample(prefix) {
@ -96,7 +97,7 @@ export default class StoredProcedure {
const storedProcedureTabs: StoredProcedureTab[] = this.container.tabsManager.getTabs( const storedProcedureTabs: StoredProcedureTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.StoredProcedures, ViewModels.CollectionTabKind.StoredProcedures,
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid (tab: TabsBase) => tab.node && tab.node.rid === this.rid
) as StoredProcedureTab[]; ) as StoredProcedureTab[];
let storedProcedureTab: StoredProcedureTab = storedProcedureTabs && storedProcedureTabs[0]; let storedProcedureTab: StoredProcedureTab = storedProcedureTabs && storedProcedureTabs[0];
@ -145,9 +146,7 @@ export default class StoredProcedure {
deleteStoredProcedure(this.collection, storedProcedureData).then( deleteStoredProcedure(this.collection, storedProcedureData).then(
() => { () => {
this.container.tabsManager.removeTabByComparator( this.container.tabsManager.removeTabByComparator((tab: TabsBase) => tab.node && tab.node.rid === this.rid);
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid
);
this.collection.children.remove(this); this.collection.children.remove(this);
}, },
reason => {} reason => {}
@ -155,11 +154,11 @@ export default class StoredProcedure {
} }
public execute(params: string[], partitionKeyValue?: string): void { public execute(params: string[], partitionKeyValue?: string): void {
const sprocTabs: ViewModels.StoredProcedureTab[] = this.container.tabsManager.getTabs( const sprocTabs = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.StoredProcedures, ViewModels.CollectionTabKind.StoredProcedures,
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid (tab: TabsBase) => tab.node && tab.node.rid === this.rid
) as ViewModels.StoredProcedureTab[]; ) as StoredProcedureTab[];
const sprocTab: ViewModels.StoredProcedureTab = sprocTabs && sprocTabs.length > 0 && sprocTabs[0]; const sprocTab = sprocTabs && sprocTabs.length > 0 && sprocTabs[0];
sprocTab.isExecuting(true); sprocTab.isExecuting(true);
this.container && this.container &&
executeStoredProcedure(this.collection, this, partitionKeyValue, params) executeStoredProcedure(this.collection, this, partitionKeyValue, params)

View File

@ -72,7 +72,7 @@ export default class Trigger {
const triggerTabs: TriggerTab[] = this.container.tabsManager.getTabs( const triggerTabs: TriggerTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.Triggers, ViewModels.CollectionTabKind.Triggers,
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid tab => tab.node && tab.node.rid === this.rid
) as TriggerTab[]; ) as TriggerTab[];
let triggerTab: TriggerTab = triggerTabs && triggerTabs[0]; let triggerTab: TriggerTab = triggerTabs && triggerTabs[0];
@ -125,9 +125,7 @@ export default class Trigger {
deleteTrigger(this.collection, triggerData).then( deleteTrigger(this.collection, triggerData).then(
() => { () => {
this.container.tabsManager.removeTabByComparator( this.container.tabsManager.removeTabByComparator(tab => tab.node && tab.node.rid === this.rid);
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid
);
this.collection.children.remove(this); this.collection.children.remove(this);
}, },
reason => {} reason => {}

View File

@ -57,7 +57,7 @@ export default class UserDefinedFunction {
const userDefinedFunctionTabs: UserDefinedFunctionTab[] = this.container.tabsManager.getTabs( const userDefinedFunctionTabs: UserDefinedFunctionTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.UserDefinedFunctions, ViewModels.CollectionTabKind.UserDefinedFunctions,
(tab: ViewModels.Tab) => tab.collection && tab.collection.rid === this.rid tab => tab.collection && tab.collection.rid === this.rid
) as UserDefinedFunctionTab[]; ) as UserDefinedFunctionTab[];
let userDefinedFunctionTab: UserDefinedFunctionTab = userDefinedFunctionTabs && userDefinedFunctionTabs[0]; let userDefinedFunctionTab: UserDefinedFunctionTab = userDefinedFunctionTabs && userDefinedFunctionTabs[0];
@ -115,9 +115,7 @@ export default class UserDefinedFunction {
}; };
deleteUserDefinedFunction(this.collection, userDefinedFunctionData).then( deleteUserDefinedFunction(this.collection, userDefinedFunctionData).then(
() => { () => {
this.container.tabsManager.removeTabByComparator( this.container.tabsManager.removeTabByComparator(tab => tab.node && tab.node.rid === this.rid);
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid
);
this.collection.children.remove(this); this.collection.children.remove(this);
}, },
reason => {} reason => {}

View File

@ -1,6 +1,6 @@
import ko from "knockout"; import ko from "knockout";
import { HttpStatusCodes } from "../Common/Constants"; import { HttpStatusCodes } from "../Common/Constants";
import * as ViewModels from "../Contracts/ViewModels"; import * as DataModels from "../Contracts/DataModels";
import { JunoClient } from "../Juno/JunoClient"; import { JunoClient } from "../Juno/JunoClient";
import { GitHubConnector, IGitHubConnectorParams } from "./GitHubConnector"; import { GitHubConnector, IGitHubConnectorParams } from "./GitHubConnector";
import { GitHubOAuthService } from "./GitHubOAuthService"; import { GitHubOAuthService } from "./GitHubOAuthService";
@ -8,7 +8,7 @@ import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/Notificat
import NotebookManager from "../Explorer/Notebook/NotebookManager"; import NotebookManager from "../Explorer/Notebook/NotebookManager";
import Explorer from "../Explorer/Explorer"; import Explorer from "../Explorer/Explorer";
const sampleDatabaseAccount: ViewModels.DatabaseAccount = { const sampleDatabaseAccount: DataModels.DatabaseAccount = {
id: "id", id: "id",
name: "name", name: "name",
location: "location", location: "location",
@ -29,7 +29,7 @@ describe("GitHubOAuthService", () => {
let originalDataExplorer: Explorer; let originalDataExplorer: Explorer;
beforeEach(() => { beforeEach(() => {
junoClient = new JunoClient(ko.observable<ViewModels.DatabaseAccount>(sampleDatabaseAccount)); junoClient = new JunoClient(ko.observable<DataModels.DatabaseAccount>(sampleDatabaseAccount));
gitHubOAuthService = new GitHubOAuthService(junoClient); gitHubOAuthService = new GitHubOAuthService(junoClient);
originalDataExplorer = window.dataExplorer; originalDataExplorer = window.dataExplorer;
window.dataExplorer = { window.dataExplorer = {

View File

@ -27,7 +27,6 @@ import * as Logger from "./Common/Logger";
import { MeControlComponentProps } from "./Explorer/Menus/NavBar/MeControlComponent"; import { MeControlComponentProps } from "./Explorer/Menus/NavBar/MeControlComponent";
import { MeControlComponentAdapter } from "./Explorer/Menus/NavBar/MeControlComponentAdapter"; import { MeControlComponentAdapter } from "./Explorer/Menus/NavBar/MeControlComponentAdapter";
import { MessageTypes } from "./Contracts/ExplorerContracts"; import { MessageTypes } from "./Contracts/ExplorerContracts";
import { NavbarButtonConfig } from "./Contracts/ViewModels";
import * as ReactBindingHandler from "./Bindings/ReactBindingHandler"; import * as ReactBindingHandler from "./Bindings/ReactBindingHandler";
import { SwitchDirectoryPane, SwitchDirectoryPaneComponent } from "./Explorer/Panes/SwitchDirectoryPane"; import { SwitchDirectoryPane, SwitchDirectoryPaneComponent } from "./Explorer/Panes/SwitchDirectoryPane";
import TelemetryProcessor from "./Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "./Shared/Telemetry/TelemetryProcessor";
@ -38,6 +37,7 @@ import ConnectIcon from "../images/HostedConnectwhite.svg";
import SettingsIcon from "../images/HostedSettings.svg"; import SettingsIcon from "../images/HostedSettings.svg";
import FeedbackIcon from "../images/Feedback.svg"; import FeedbackIcon from "../images/Feedback.svg";
import SwitchDirectoryIcon from "../images/DirectorySwitch.svg"; import SwitchDirectoryIcon from "../images/DirectorySwitch.svg";
import { CommandButtonComponentProps } from "./Explorer/Controls/CommandButton/CommandButtonComponent";
ReactBindingHandler.Registerer.register(); ReactBindingHandler.Registerer.register();
ko.components.register("switch-directory-pane", new SwitchDirectoryPaneComponent()); ko.components.register("switch-directory-pane", new SwitchDirectoryPaneComponent());
@ -56,7 +56,7 @@ class HostedExplorer {
private _dialogProps: ko.Observable<DialogProps>; private _dialogProps: ko.Observable<DialogProps>;
private _meControlProps: ko.Observable<MeControlComponentProps>; private _meControlProps: ko.Observable<MeControlComponentProps>;
private _accountSwitchProps: ko.Observable<AccountSwitchComponentProps>; private _accountSwitchProps: ko.Observable<AccountSwitchComponentProps>;
private _controlbarCommands: ko.ObservableArray<NavbarButtonConfig>; private _controlbarCommands: ko.ObservableArray<CommandButtonComponentProps>;
private _directoryDropdownProps: ko.Observable<DefaultDirectoryDropdownProps>; private _directoryDropdownProps: ko.Observable<DefaultDirectoryDropdownProps>;
private _directoryListProps: ko.Observable<DirectoryListProps>; private _directoryListProps: ko.Observable<DirectoryListProps>;
@ -1086,7 +1086,7 @@ class HostedExplorer {
} }
private _setAadControlBar() { private _setAadControlBar() {
const switchDirectoryCommand: NavbarButtonConfig = { const switchDirectoryCommand: CommandButtonComponentProps = {
iconSrc: SwitchDirectoryIcon, iconSrc: SwitchDirectoryIcon,
iconAlt: "switch directory button", iconAlt: "switch directory button",
onCommandClick: () => this.openDirectoryPane(), onCommandClick: () => this.openDirectoryPane(),

View File

@ -4,8 +4,9 @@ import * as ViewModels from "../Contracts/ViewModels";
import { IPinnedRepo, JunoClient, IGalleryItem } from "./JunoClient"; import { IPinnedRepo, JunoClient, IGalleryItem } from "./JunoClient";
import { config } from "../Config"; import { config } from "../Config";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { DatabaseAccount } from "../Contracts/DataModels";
const sampleDatabaseAccount: ViewModels.DatabaseAccount = { const sampleDatabaseAccount: DatabaseAccount = {
id: "id", id: "id",
name: "name", name: "name",
location: "location", location: "location",
@ -51,7 +52,7 @@ const sampleGalleryItems: IGalleryItem[] = [
]; ];
describe("Pinned repos", () => { describe("Pinned repos", () => {
const junoClient = new JunoClient(ko.observable<ViewModels.DatabaseAccount>(sampleDatabaseAccount)); const junoClient = new JunoClient(ko.observable<DatabaseAccount>(sampleDatabaseAccount));
beforeEach(() => { beforeEach(() => {
window.fetch = jest.fn().mockImplementation(() => { window.fetch = jest.fn().mockImplementation(() => {
@ -88,7 +89,7 @@ describe("Pinned repos", () => {
}); });
describe("GitHub", () => { describe("GitHub", () => {
const junoClient = new JunoClient(ko.observable<ViewModels.DatabaseAccount>(sampleDatabaseAccount)); const junoClient = new JunoClient(ko.observable<DatabaseAccount>(sampleDatabaseAccount));
afterEach(() => { afterEach(() => {
jest.resetAllMocks(); jest.resetAllMocks();
@ -147,7 +148,7 @@ describe("GitHub", () => {
}); });
describe("Gallery", () => { describe("Gallery", () => {
const junoClient = new JunoClient(ko.observable<ViewModels.DatabaseAccount>(sampleDatabaseAccount)); const junoClient = new JunoClient(ko.observable<DatabaseAccount>(sampleDatabaseAccount));
afterEach(() => { afterEach(() => {
jest.resetAllMocks(); jest.resetAllMocks();

View File

@ -1,7 +1,7 @@
import ko from "knockout"; import ko from "knockout";
import { HttpStatusCodes } from "../Common/Constants"; import { HttpStatusCodes } from "../Common/Constants";
import { config } from "../Config"; import { config } from "../Config";
import * as ViewModels from "../Contracts/ViewModels"; import * as DataModels from "../Contracts/DataModels";
import { AuthorizeAccessComponent } from "../Explorer/Controls/GitHub/AuthorizeAccessComponent"; import { AuthorizeAccessComponent } from "../Explorer/Controls/GitHub/AuthorizeAccessComponent";
import { IGitHubResponse } from "../GitHub/GitHubClient"; import { IGitHubResponse } from "../GitHub/GitHubClient";
import { IGitHubOAuthToken } from "../GitHub/GitHubOAuthService"; import { IGitHubOAuthToken } from "../GitHub/GitHubOAuthService";
@ -55,7 +55,7 @@ interface IPublishNotebookRequest {
export class JunoClient { export class JunoClient {
private cachedPinnedRepos: ko.Observable<IPinnedRepo[]>; private cachedPinnedRepos: ko.Observable<IPinnedRepo[]>;
constructor(private databaseAccount?: ko.Observable<ViewModels.DatabaseAccount>) { constructor(private databaseAccount?: ko.Observable<DataModels.DatabaseAccount>) {
this.cachedPinnedRepos = ko.observable<IPinnedRepo[]>([]); this.cachedPinnedRepos = ko.observable<IPinnedRepo[]>([]);
} }

View File

@ -272,7 +272,7 @@ export default class AuthHeadersUtil {
} }
private static _generateResourceUrl(): string { private static _generateResourceUrl(): string {
const databaseAccount: ViewModels.DatabaseAccount = CosmosClient.databaseAccount(); const databaseAccount = CosmosClient.databaseAccount();
const subscriptionId: string = CosmosClient.subscriptionId(); const subscriptionId: string = CosmosClient.subscriptionId();
const resourceGroup: string = CosmosClient.resourceGroup(); const resourceGroup: string = CosmosClient.resourceGroup();
const defaultExperience: string = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(databaseAccount); const defaultExperience: string = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(databaseAccount);

View File

@ -4,6 +4,8 @@ import * as ViewModels from "../Contracts/ViewModels";
import crossroads from "crossroads"; import crossroads from "crossroads";
import hasher from "hasher"; import hasher from "hasher";
import ScriptTabBase from "../Explorer/Tabs/ScriptTabBase";
import TabsBase from "../Explorer/Tabs/TabsBase";
export class TabRouteHandler { export class TabRouteHandler {
private _tabRouter: any; private _tabRouter: any;
@ -187,7 +189,7 @@ export class TabRouteHandler {
databaseId, databaseId,
collectionId collectionId
); );
const matchingTab: ViewModels.Tab = this._findMatchingTabByTabKind( const matchingTab: TabsBase = this._findMatchingTabByTabKind(
databaseId, databaseId,
collectionId, collectionId,
ViewModels.CollectionTabKind.Query ViewModels.CollectionTabKind.Query
@ -206,7 +208,7 @@ export class TabRouteHandler {
databaseId, databaseId,
collectionId collectionId
); );
const matchingTab: ViewModels.Tab = this._findMatchingTabByTabKind( const matchingTab: TabsBase = this._findMatchingTabByTabKind(
databaseId, databaseId,
collectionId, collectionId,
ViewModels.CollectionTabKind.Query ViewModels.CollectionTabKind.Query
@ -228,7 +230,7 @@ export class TabRouteHandler {
databaseId, databaseId,
collectionId collectionId
); );
const matchingTab: ViewModels.Tab = this._findMatchingTabByTabKind( const matchingTab: TabsBase = this._findMatchingTabByTabKind(
databaseId, databaseId,
collectionId, collectionId,
ViewModels.CollectionTabKind.MongoShell ViewModels.CollectionTabKind.MongoShell
@ -271,7 +273,7 @@ export class TabRouteHandler {
databaseId, databaseId,
collectionId collectionId
); );
const matchingTab: ViewModels.Tab = this._findMatchingTabByTabKind( const matchingTab: TabsBase = this._findMatchingTabByTabKind(
databaseId, databaseId,
collectionId, collectionId,
ViewModels.CollectionTabKind.StoredProcedures, ViewModels.CollectionTabKind.StoredProcedures,
@ -302,7 +304,7 @@ export class TabRouteHandler {
databaseId, databaseId,
collectionId collectionId
); );
const matchingTab: ViewModels.Tab = this._findMatchingTabByTabKind( const matchingTab: TabsBase = this._findMatchingTabByTabKind(
databaseId, databaseId,
collectionId, collectionId,
ViewModels.CollectionTabKind.Triggers, ViewModels.CollectionTabKind.Triggers,
@ -333,7 +335,7 @@ export class TabRouteHandler {
databaseId, databaseId,
collectionId collectionId
); );
const matchingTab: ViewModels.Tab = this._findMatchingTabByTabKind( const matchingTab: TabsBase = this._findMatchingTabByTabKind(
databaseId, databaseId,
collectionId, collectionId,
ViewModels.CollectionTabKind.UserDefinedFunctions, ViewModels.CollectionTabKind.UserDefinedFunctions,
@ -380,15 +382,15 @@ export class TabRouteHandler {
collectionId: string, collectionId: string,
tabKind: ViewModels.CollectionTabKind, tabKind: ViewModels.CollectionTabKind,
isNewScriptTab?: boolean isNewScriptTab?: boolean
): ViewModels.Tab { ): TabsBase {
const explorer = window.dataExplorer; const explorer = window.dataExplorer;
const matchingTabs: ViewModels.Tab[] = explorer.tabsManager.getTabs( const matchingTabs: TabsBase[] = explorer.tabsManager.getTabs(
tabKind, tabKind,
(tab: ViewModels.Tab) => (tab: TabsBase) =>
tab.collection && tab.collection &&
tab.collection.databaseId === databaseId && tab.collection.databaseId === databaseId &&
tab.collection.id() === collectionId && tab.collection.id() === collectionId &&
(!isNewScriptTab || (tab as ViewModels.ScriptTab).isNew()) (!isNewScriptTab || (tab as ScriptTabBase).isNew())
); );
return matchingTabs && matchingTabs[0]; return matchingTabs && matchingTabs[0];
} }

View File

@ -71,12 +71,12 @@ describe("Default Experience Utility", () => {
}); });
describe("getDefaultExperienceFromDatabaseAccount()", () => { describe("getDefaultExperienceFromDatabaseAccount()", () => {
function runScenario(databaseAccount: ViewModels.DatabaseAccount, expectedDefaultExperience: string): void { function runScenario(databaseAccount: DataModels.DatabaseAccount, expectedDefaultExperience: string): void {
const resolvedExperience = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(databaseAccount); const resolvedExperience = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(databaseAccount);
expect(resolvedExperience).toEqual(expectedDefaultExperience); expect(resolvedExperience).toEqual(expectedDefaultExperience);
} }
const databaseAccountWithWrongTagsAndCapabilities: ViewModels.DatabaseAccount = { const databaseAccountWithWrongTagsAndCapabilities: DataModels.DatabaseAccount = {
id: "test", id: "test",
kind: "GlobalDocumentDB", kind: "GlobalDocumentDB",
name: "test", name: "test",
@ -99,7 +99,7 @@ describe("Default Experience Utility", () => {
} }
}; };
const databaseAccountWithApiKind: ViewModels.DatabaseAccount = { const databaseAccountWithApiKind: DataModels.DatabaseAccount = {
id: "test", id: "test",
kind: Constants.AccountKind.MongoDB, kind: Constants.AccountKind.MongoDB,
name: "test", name: "test",

View File

@ -1,18 +1,16 @@
import * as _ from "underscore"; import * as _ from "underscore";
import * as Constants from "../Common/Constants"; import * as Constants from "../Common/Constants";
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
export class DefaultExperienceUtility { export class DefaultExperienceUtility {
public static getDefaultExperienceFromDatabaseAccount(databaseAccount: ViewModels.DatabaseAccount): string { public static getDefaultExperienceFromDatabaseAccount(databaseAccount: DataModels.DatabaseAccount): string {
if (!databaseAccount) { if (!databaseAccount) {
return null; return null;
} }
const kind: string = const kind: string =
databaseAccount && databaseAccount.kind && databaseAccount.kind && databaseAccount.kind.toLowerCase(); databaseAccount && databaseAccount.kind && databaseAccount.kind && databaseAccount.kind.toLowerCase();
const capabilities: ViewModels.Capability[] = const capabilities = (databaseAccount.properties && databaseAccount.properties.capabilities) || [];
(databaseAccount.properties && databaseAccount.properties.capabilities) || [];
return DefaultExperienceUtility._getDefaultExperience(kind, capabilities); return DefaultExperienceUtility._getDefaultExperience(kind, capabilities);
} }
@ -61,7 +59,7 @@ export class DefaultExperienceUtility {
} }
} }
private static _getDefaultExperience(kind: string, capabilities: ViewModels.Capability[]): string { private static _getDefaultExperience(kind: string, capabilities: DataModels.Capability[]): string {
const defaultDefaultExperience: string = Constants.DefaultAccountExperience.DocumentDB; const defaultDefaultExperience: string = Constants.DefaultAccountExperience.DocumentDB;
const defaultExperienceFromKind: string = DefaultExperienceUtility._getDefaultExperienceFromAccountKind(kind); const defaultExperienceFromKind: string = DefaultExperienceUtility._getDefaultExperienceFromAccountKind(kind);
const defaultExperienceFromCapabilities: string = DefaultExperienceUtility._getDefaultExperienceFromAccountCapabilities( const defaultExperienceFromCapabilities: string = DefaultExperienceUtility._getDefaultExperienceFromAccountCapabilities(
@ -95,7 +93,7 @@ export class DefaultExperienceUtility {
return null; return null;
} }
private static _getDefaultExperienceFromAccountCapabilities(capabilities: ViewModels.Capability[]): string { private static _getDefaultExperienceFromAccountCapabilities(capabilities: DataModels.Capability[]): string {
if (!capabilities) { if (!capabilities) {
return null; return null;
} }
@ -104,15 +102,12 @@ export class DefaultExperienceUtility {
return null; return null;
} }
const enableTable: ViewModels.Capability = DefaultExperienceUtility._findCapability( const enableTable = DefaultExperienceUtility._findCapability(capabilities, Constants.CapabilityNames.EnableTable);
capabilities,
Constants.CapabilityNames.EnableTable
);
if (enableTable) { if (enableTable) {
return Constants.DefaultAccountExperience.Table; return Constants.DefaultAccountExperience.Table;
} }
const enableGremlin: ViewModels.Capability = DefaultExperienceUtility._findCapability( const enableGremlin = DefaultExperienceUtility._findCapability(
capabilities, capabilities,
Constants.CapabilityNames.EnableGremlin Constants.CapabilityNames.EnableGremlin
); );
@ -120,7 +115,7 @@ export class DefaultExperienceUtility {
return Constants.DefaultAccountExperience.Graph; return Constants.DefaultAccountExperience.Graph;
} }
const enableCassandra: ViewModels.Capability = DefaultExperienceUtility._findCapability( const enableCassandra = DefaultExperienceUtility._findCapability(
capabilities, capabilities,
Constants.CapabilityNames.EnableCassandra Constants.CapabilityNames.EnableCassandra
); );
@ -131,8 +126,8 @@ export class DefaultExperienceUtility {
return null; return null;
} }
private static _findCapability(capabilities: ViewModels.Capability[], capabilityName: string): ViewModels.Capability { private static _findCapability(capabilities: DataModels.Capability[], capabilityName: string): DataModels.Capability {
return _.find(capabilities, (capability: ViewModels.Capability) => { return _.find(capabilities, capability => {
return capability && capability.name && capability.name.toLowerCase() === capabilityName.toLowerCase(); return capability && capability.name && capability.name.toLowerCase() === capabilityName.toLowerCase();
}); });
} }

View File

@ -1,154 +0,0 @@
import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
import { DatabaseAccountUtils } from "./DatabaseAccountUtils";
describe("DatabaseAccountUtils Tests", () => {
describe("mergeDatabaseAccountWithGateway", () => {
const databaseAccountWithProperties: ViewModels.DatabaseAccount = {
id: "test",
kind: "GlobalDocumentDB",
name: "test",
location: "somewhere",
type: "DocumentDB",
tags: [],
properties: {
documentEndpoint: "",
cassandraEndpoint: "",
gremlinEndpoint: "",
tableEndpoint: ""
}
};
const databaseAccountWithLocations: ViewModels.DatabaseAccount = {
id: "test",
kind: "GlobalDocumentDB",
name: "test",
location: "somewhere",
type: "DocumentDB",
tags: [],
properties: {
documentEndpoint: "",
cassandraEndpoint: "",
gremlinEndpoint: "",
tableEndpoint: "",
enableMultipleWriteLocations: false,
readLocations: [
{
documentEndpoint: "https://centralus",
failoverPriority: 0,
id: "",
locationId: "",
locationName: "Central US",
provisioningState: "Succeeded"
}
],
writeLocations: [
{
documentEndpoint: "https://centralus",
failoverPriority: 0,
id: "",
locationId: "",
locationName: "Central US",
provisioningState: "Succeeded"
}
]
}
};
const databaseAccountWithoutProperties: ViewModels.DatabaseAccount = {
id: "test",
kind: "GlobalDocumentDB",
name: "test",
location: "somewhere",
type: "DocumentDB",
tags: [],
properties: null
};
const gatewayDatabaseAccount: DataModels.GatewayDatabaseAccount = {
EnableMultipleWriteLocations: true,
CurrentMediaStorageUsageInMB: 0,
DatabasesLink: "",
MaxMediaStorageUsageInMB: 0,
MediaLink: "",
ReadableLocations: [
{
name: "Central US",
documentAccountEndpoint: "https://centralus"
},
{
name: "North Central US",
documentAccountEndpoint: "https://northcentralus"
}
],
WritableLocations: [
{
name: "Central US",
documentAccountEndpoint: "https://centralus"
}
]
};
it("should return databaseAccount when gatewayDatabaseAccount is not defined", () => {
expect(DatabaseAccountUtils.mergeDatabaseAccountWithGateway(databaseAccountWithoutProperties, null)).toBe(
databaseAccountWithoutProperties
);
});
it("should return null when databaseAccount is not defined", () => {
expect(DatabaseAccountUtils.mergeDatabaseAccountWithGateway(null, null)).toBeNull();
});
it("should return merged with no properties when databaseAccount has no properties", () => {
const merged = DatabaseAccountUtils.mergeDatabaseAccountWithGateway(
databaseAccountWithoutProperties,
gatewayDatabaseAccount
);
expect(merged).toBeDefined();
expect(merged.properties).toBeNull();
});
it("should return merged writableLocations", () => {
const merged = DatabaseAccountUtils.mergeDatabaseAccountWithGateway(
databaseAccountWithProperties,
gatewayDatabaseAccount
);
expect(merged.properties).toBeDefined();
expect(merged.properties.writeLocations).toBeDefined();
expect(merged.properties.writeLocations.length).toBe(gatewayDatabaseAccount.WritableLocations.length);
});
it("should return merged readableLocations", () => {
const merged = DatabaseAccountUtils.mergeDatabaseAccountWithGateway(
databaseAccountWithProperties,
gatewayDatabaseAccount
);
expect(merged.properties).toBeDefined();
expect(merged.properties.readLocations).toBeDefined();
expect(merged.properties.readLocations.length).toBe(gatewayDatabaseAccount.ReadableLocations.length);
});
it("should return merged enableMultipleWriteLocations", () => {
const merged = DatabaseAccountUtils.mergeDatabaseAccountWithGateway(
databaseAccountWithProperties,
gatewayDatabaseAccount
);
expect(merged.properties).toBeDefined();
expect(merged.properties.enableMultipleWriteLocations).toBe(gatewayDatabaseAccount.EnableMultipleWriteLocations);
});
it("should not overwrite existing values", () => {
const merged = DatabaseAccountUtils.mergeDatabaseAccountWithGateway(
databaseAccountWithLocations,
gatewayDatabaseAccount
);
expect(merged.properties.enableMultipleWriteLocations).toBe(
databaseAccountWithLocations.properties.enableMultipleWriteLocations
);
expect(merged.properties.readLocations.length).toBe(databaseAccountWithLocations.properties.readLocations.length);
expect(merged.properties.writeLocations.length).toBe(
databaseAccountWithLocations.properties.writeLocations.length
);
});
});
});

View File

@ -1,53 +0,0 @@
import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
import { StringUtils } from "./StringUtils";
export class DatabaseAccountUtils {
public static mergeDatabaseAccountWithGateway(
databaseAccount: ViewModels.DatabaseAccount,
gatewayDatabaseAccount: DataModels.GatewayDatabaseAccount
): ViewModels.DatabaseAccount {
if (!databaseAccount || !gatewayDatabaseAccount) {
return databaseAccount;
}
if (databaseAccount.properties && gatewayDatabaseAccount.EnableMultipleWriteLocations) {
databaseAccount.properties.enableMultipleWriteLocations = gatewayDatabaseAccount.EnableMultipleWriteLocations;
}
if (databaseAccount.properties && !databaseAccount.properties.readLocations) {
databaseAccount.properties.readLocations = DatabaseAccountUtils._convertToDatabaseAccountResponseLocation(
gatewayDatabaseAccount.ReadableLocations
);
}
if (databaseAccount.properties && !databaseAccount.properties.writeLocations) {
databaseAccount.properties.writeLocations = DatabaseAccountUtils._convertToDatabaseAccountResponseLocation(
gatewayDatabaseAccount.WritableLocations
);
}
return databaseAccount;
}
private static _convertToDatabaseAccountResponseLocation(
gatewayLocations: DataModels.RegionEndpoint[]
): DataModels.DatabaseAccountResponseLocation[] {
if (!gatewayLocations) {
return undefined;
}
return gatewayLocations.map((gatewayLocation: DataModels.RegionEndpoint, index: number) => {
const responseLocation: DataModels.DatabaseAccountResponseLocation = {
documentEndpoint: gatewayLocation.documentAccountEndpoint,
locationName: gatewayLocation.name,
failoverPriority: index,
locationId: StringUtils.stripSpacesFromString(gatewayLocation.name).toLowerCase(),
provisioningState: "Succeeded",
id: gatewayLocation.name
};
return responseLocation;
});
}
}

View File

@ -1,7 +1,12 @@
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import { KernelConnectionMetadata } from "../Contracts/ViewModels";
import * as Logger from "../Common/Logger"; import * as Logger from "../Common/Logger";
interface KernelConnectionMetadata {
name: string;
configurationEndpoints: DataModels.NotebookConfigurationEndpoints;
notebookConnectionInfo: DataModels.NotebookWorkspaceConnectionInfo;
}
export class NotebookConfigurationUtils { export class NotebookConfigurationUtils {
private constructor() {} private constructor() {}

View File

@ -38,13 +38,6 @@
"./src/Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.ts", "./src/Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.ts",
"./src/Explorer/Controls/GitHub/GitHubStyleConstants.ts", "./src/Explorer/Controls/GitHub/GitHubStyleConstants.ts",
"./src/Explorer/Controls/SmartUi/InputUtils.ts", "./src/Explorer/Controls/SmartUi/InputUtils.ts",
"./src/Explorer/Controls/Toolbar/IToolbarAction.ts",
"./src/Explorer/Controls/Toolbar/IToolbarDisplayable.ts",
"./src/Explorer/Controls/Toolbar/IToolbarDropDown.ts",
"./src/Explorer/Controls/Toolbar/IToolbarItem.ts",
"./src/Explorer/Controls/Toolbar/IToolbarSeperator.ts",
"./src/Explorer/Controls/Toolbar/IToolbarToggle.ts",
"./src/Explorer/Controls/Toolbar/KeyCodes.ts",
"./src/Explorer/Notebook/FileSystemUtil.ts", "./src/Explorer/Notebook/FileSystemUtil.ts",
"./src/Explorer/Notebook/NTeractUtil.ts", "./src/Explorer/Notebook/NTeractUtil.ts",
"./src/Explorer/Notebook/NotebookComponent/actions.ts", "./src/Explorer/Notebook/NotebookComponent/actions.ts",