mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-22 18:32:00 +00:00
Refactor MemoryTracker to use SWR
This commit is contained in:
23
package-lock.json
generated
23
package-lock.json
generated
@@ -23516,9 +23516,9 @@
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "16.9.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.9.0.tgz",
|
||||
"integrity": "sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==",
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
||||
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -25755,6 +25755,23 @@
|
||||
"resolved": "https://registry.npmjs.org/svgpath/-/svgpath-2.2.3.tgz",
|
||||
"integrity": "sha512-xA0glXYpJ9SYT4JeMp3c0psbqdZsG1c0ywGvdJUPY2FKEgwJV7NgkeYuuQiOxMp+XsK9nCqjm3KDw0LkM1YLXw=="
|
||||
},
|
||||
"swr": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-0.3.2.tgz",
|
||||
"integrity": "sha512-Bs5Bihq1hQ66O5bdKaL47iZ2nlAaBsd8tTLRLkw9stZeuBEfH7zSuQI95S2TpchL0ybsMq3isWwuso2uPvCfHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"promise-polyfill": "8.1.0",
|
||||
"promise.prototype.finally": "3.1.0",
|
||||
"q": "1.5.1",
|
||||
"react": "16.9.0",
|
||||
"react": "16.13.1",
|
||||
"react-animate-height": "2.0.8",
|
||||
"react-dnd": "9.4.0",
|
||||
"react-dnd-html5-backend": "9.4.0",
|
||||
@@ -160,6 +160,7 @@
|
||||
"rimraf": "3.0.0",
|
||||
"sinon": "3.2.1",
|
||||
"style-loader": "0.23.0",
|
||||
"swr": "0.3.2",
|
||||
"terser-webpack-plugin": "3.0.5",
|
||||
"ts-loader": "6.2.2",
|
||||
"tslint": "5.11.0",
|
||||
|
||||
@@ -6,23 +6,26 @@ import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/Contai
|
||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
||||
import { client } from "../CosmosClient";
|
||||
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import {
|
||||
createUpdateSqlContainer,
|
||||
getSqlContainer
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import {
|
||||
createUpdateCassandraTable,
|
||||
getCassandraTable
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBCollection,
|
||||
getMongoDBCollection
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinGraph,
|
||||
getGremlinGraph
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
||||
|
||||
@@ -9,21 +9,24 @@ import {
|
||||
MongoDBDatabaseCreateUpdateParameters,
|
||||
SqlDatabaseCreateUpdateParameters,
|
||||
CreateUpdateOptions
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
||||
import { client } from "../CosmosClient";
|
||||
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import {
|
||||
createUpdateSqlDatabase,
|
||||
getSqlDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import {
|
||||
createUpdateCassandraKeyspace,
|
||||
getCassandraKeyspace
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBDatabase,
|
||||
getMongoDBDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinDatabase,
|
||||
getGremlinDatabase
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { refreshCachedOffers, refreshCachedResources } from "../DataAccessUtilityBase";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { client } from "../CosmosClient";
|
||||
|
||||
@@ -2,11 +2,11 @@ import * as DataModels from "../../Contracts/DataModels";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { client } from "../CosmosClient";
|
||||
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
@@ -2,10 +2,10 @@ import * as DataModels from "../../Contracts/DataModels";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||
import { client } from "../CosmosClient";
|
||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { sendNotificationForError } from "./sendNotificationForError";
|
||||
|
||||
@@ -6,23 +6,26 @@ import {
|
||||
ExtendedResourceProperties,
|
||||
SqlContainerCreateUpdateParameters,
|
||||
SqlContainerResource
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import { client } from "../CosmosClient";
|
||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||
import {
|
||||
createUpdateSqlContainer,
|
||||
getSqlContainer
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
||||
import {
|
||||
createUpdateCassandraTable,
|
||||
getCassandraTable
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
||||
import {
|
||||
createUpdateMongoDBCollection,
|
||||
getMongoDBCollection
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
||||
import {
|
||||
createUpdateGremlinGraph,
|
||||
getGremlinGraph
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { logError } from "../Logger";
|
||||
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
||||
|
||||
@@ -709,11 +709,6 @@ export interface SparkPool extends ArmResource {
|
||||
properties: SparkPoolProperties;
|
||||
}
|
||||
|
||||
export interface MemoryUsageInfo {
|
||||
freeKB: number;
|
||||
totalKB: number;
|
||||
}
|
||||
|
||||
export interface resourceTokenConnectionStringProperties {
|
||||
accountEndpoint: string;
|
||||
collectionId: string;
|
||||
|
||||
@@ -243,7 +243,6 @@ export default class Explorer {
|
||||
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
||||
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
||||
public isSynapseLinkUpdating: ko.Observable<boolean>;
|
||||
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
|
||||
public notebookManager?: any; // This is dynamically loaded
|
||||
|
||||
private _panes: ContextualPaneBase[] = [];
|
||||
@@ -374,7 +373,6 @@ export default class Explorer {
|
||||
);
|
||||
}
|
||||
});
|
||||
this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>();
|
||||
this.notificationsClient = options.notificationsClient;
|
||||
this.isEmulator = options.isEmulator;
|
||||
|
||||
|
||||
@@ -82,9 +82,7 @@ export class CommandBarComponentAdapter implements ReactAdapter {
|
||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||
|
||||
if (this.isNotebookTabActive()) {
|
||||
uiFabricControlButtons.unshift(
|
||||
CommandBarUtil.createMemoryTracker("memoryTracker", this.container.memoryUsageInfo)
|
||||
);
|
||||
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import _ from "underscore";
|
||||
import * as React from "react";
|
||||
import { Observable } from "knockout";
|
||||
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
import { Dropdown, IDropdownOption, IDropdownStyles } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { IconType } from "office-ui-fabric-react/lib/Icon";
|
||||
import { IComponentAsProps } from "office-ui-fabric-react/lib/Utilities";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
import { Dropdown, IDropdownStyles, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import * as React from "react";
|
||||
import _ from "underscore";
|
||||
import ChevronDownIcon from "../../../../images/Chevron_down.svg";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import { MemoryTrackerComponent } from "./MemoryTrackerComponent";
|
||||
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||
|
||||
/**
|
||||
* Utilities for CommandBar
|
||||
@@ -178,10 +176,10 @@ export class CommandBarUtil {
|
||||
};
|
||||
}
|
||||
|
||||
public static createMemoryTracker(key: string, memoryUsageInfo: Observable<MemoryUsageInfo>): ICommandBarItemProps {
|
||||
public static createMemoryTracker(key: string): ICommandBarItemProps {
|
||||
return {
|
||||
key,
|
||||
onRender: () => <MemoryTrackerComponent memoryUsageInfo={memoryUsageInfo} />
|
||||
onRender: () => <MemoryTrackerComponent />
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +1,71 @@
|
||||
import * as React from "react";
|
||||
import { Observable, Subscription } from "knockout";
|
||||
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import useSWR from "swr";
|
||||
import { ProgressIndicator } from "office-ui-fabric-react/lib/ProgressIndicator";
|
||||
import { Spinner, SpinnerSize } from "office-ui-fabric-react/lib/Spinner";
|
||||
import { Stack } from "office-ui-fabric-react/lib/Stack";
|
||||
import { listConnectionInfo } from "../../../Utils/arm/generatedClients/2020-04-01-notebooks/notebookWorkspaces";
|
||||
import { NotebookWorkspaceConnectionInfoResult } from "../../../Utils/arm/generatedClients/2020-04-01-notebooks/types";
|
||||
import { userContext } from "../../../UserContext";
|
||||
|
||||
interface MemoryTrackerProps {
|
||||
memoryUsageInfo: Observable<MemoryUsageInfo>;
|
||||
export interface MemoryUsageInfo {
|
||||
total: number;
|
||||
free: number;
|
||||
}
|
||||
|
||||
export class MemoryTrackerComponent extends React.Component<MemoryTrackerProps> {
|
||||
private memoryUsageInfoSubscription: Subscription;
|
||||
const kbInGB = 1048576;
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.memoryUsageInfoSubscription = this.props.memoryUsageInfo.subscribe(() => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.memoryUsageInfoSubscription && this.memoryUsageInfoSubscription.dispose();
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const memoryUsageInfo: MemoryUsageInfo = this.props.memoryUsageInfo();
|
||||
if (!memoryUsageInfo) {
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<Spinner size={SpinnerSize.medium} />
|
||||
</Stack>
|
||||
);
|
||||
const fetchMemoryInfo = async (_key: unknown, connectionInfo: NotebookWorkspaceConnectionInfoResult) => {
|
||||
const response = await fetch(`${connectionInfo.notebookServerEndpoint}/api/metrics/memory`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Token ${connectionInfo.authToken}`,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(await response.text());
|
||||
}
|
||||
const memoryUsageInfo = (await response.json()) as MemoryUsageInfo;
|
||||
return {
|
||||
totalKB: memoryUsageInfo.total,
|
||||
freeKB: memoryUsageInfo.free
|
||||
};
|
||||
};
|
||||
|
||||
const totalGB = memoryUsageInfo.totalKB / 1048576;
|
||||
const usedGB = totalGB - memoryUsageInfo.freeKB / 1048576;
|
||||
export const MemoryTrackerComponent: FunctionComponent = () => {
|
||||
const { data: connectionInfo } = useSWR<NotebookWorkspaceConnectionInfoResult>(
|
||||
[
|
||||
"notebooksConnectionInfo",
|
||||
userContext.subscriptionId,
|
||||
userContext.resourceGroup,
|
||||
userContext.databaseAccount.name,
|
||||
"default"
|
||||
],
|
||||
(_key, subscriptionId, resourceGroup, accountName, workspace) =>
|
||||
listConnectionInfo(subscriptionId, resourceGroup, accountName, workspace)
|
||||
);
|
||||
const { data } = useSWR<any>(connectionInfo ? ["memoryUsage", connectionInfo] : null, fetchMemoryInfo, {
|
||||
refreshInterval: 2000
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<ProgressIndicator
|
||||
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
||||
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
||||
percentComplete={usedGB / totalGB}
|
||||
/>
|
||||
<Spinner size={SpinnerSize.medium} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
}
|
||||
const totalGB = data.totalKB / kbInGB;
|
||||
const usedGB = totalGB - data.freeKB / kbInGB;
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<ProgressIndicator
|
||||
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
||||
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
||||
percentComplete={usedGB / totalGB}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,89 +2,13 @@
|
||||
* Notebook container related stuff
|
||||
*/
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
|
||||
export class NotebookContainerClient {
|
||||
private reconnectingNotificationId: string;
|
||||
private isResettingWorkspace: boolean;
|
||||
|
||||
constructor(
|
||||
private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>,
|
||||
private onConnectionLost: () => void,
|
||||
private onMemoryUsageInfoUpdate: (update: DataModels.MemoryUsageInfo) => void
|
||||
) {
|
||||
if (notebookServerInfo() && notebookServerInfo().notebookServerEndpoint) {
|
||||
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||
} else {
|
||||
const subscription = notebookServerInfo.subscribe((newServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => {
|
||||
if (newServerInfo && newServerInfo.notebookServerEndpoint) {
|
||||
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||
}
|
||||
subscription.dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Heartbeat: each ping schedules another ping
|
||||
*/
|
||||
private scheduleHeartbeat(delayMs: number): void {
|
||||
setTimeout(() => {
|
||||
this.getMemoryUsage()
|
||||
.then(memoryUsageInfo => this.onMemoryUsageInfoUpdate(memoryUsageInfo))
|
||||
.finally(() => this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs));
|
||||
}, delayMs);
|
||||
}
|
||||
|
||||
private async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
||||
if (!this.notebookServerInfo() || !this.notebookServerInfo().notebookServerEndpoint) {
|
||||
const error = "No server endpoint detected";
|
||||
Logger.logError(error, "NotebookContainerClient/getMemoryUsage");
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (this.isResettingWorkspace) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { notebookServerEndpoint, authToken } = this.getNotebookServerConfig();
|
||||
try {
|
||||
const response = await fetch(`${notebookServerEndpoint}/api/metrics/memory`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: authToken,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
if (this.reconnectingNotificationId) {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(this.reconnectingNotificationId);
|
||||
this.reconnectingNotificationId = "";
|
||||
}
|
||||
const memoryUsageInfo = await response.json();
|
||||
if (memoryUsageInfo) {
|
||||
return {
|
||||
totalKB: memoryUsageInfo.total,
|
||||
freeKB: memoryUsageInfo.free
|
||||
};
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
Logger.logError(error, "NotebookContainerClient/getMemoryUsage");
|
||||
if (!this.reconnectingNotificationId) {
|
||||
this.reconnectingNotificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
"Connection lost with Notebook server. Attempting to reconnect..."
|
||||
);
|
||||
}
|
||||
this.onConnectionLost();
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
constructor(private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>) {}
|
||||
|
||||
public async resetWorkspace(): Promise<void> {
|
||||
this.isResettingWorkspace = true;
|
||||
|
||||
@@ -16,7 +16,6 @@ import { NotebookContentProvider } from "./NotebookComponent/NotebookContentProv
|
||||
import { GitHubContentProvider } from "../../GitHub/GitHubContentProvider";
|
||||
import { contents } from "rx-jupyter";
|
||||
import { NotebookContainerClient } from "./NotebookContainerClient";
|
||||
import { MemoryUsageInfo } from "../../Contracts/DataModels";
|
||||
import { NotebookContentClient } from "./NotebookContentClient";
|
||||
import { DialogProps } from "../Controls/DialogReactComponent/DialogComponent";
|
||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
||||
@@ -76,11 +75,7 @@ export default class NotebookManager {
|
||||
contents.JupyterContentProvider
|
||||
);
|
||||
|
||||
this.notebookClient = new NotebookContainerClient(
|
||||
this.params.container.notebookServerInfo,
|
||||
() => this.params.container.initNotebooks(this.params.container.databaseAccount()),
|
||||
(update: MemoryUsageInfo) => this.params.container.memoryUsageInfo(update)
|
||||
);
|
||||
this.notebookClient = new NotebookContainerClient(this.params.container.notebookServerInfo);
|
||||
|
||||
this.notebookContentClient = new NotebookContentClient(
|
||||
this.params.container.notebookServerInfo,
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
AUTOGENERATED FILE
|
||||
Do not manually edit
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
*/
|
||||
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2020-04-01";
|
||||
|
||||
/* Gets the notebook workspace resources of an existing Cosmos DB account. */
|
||||
export async function listByDatabaseAccount(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string
|
||||
): Promise<Types.NotebookWorkspaceListResult | unknown> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Gets the notebook workspace for a Cosmos DB account. */
|
||||
export async function get(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
notebookWorkspaceName: string
|
||||
): Promise<Types.NotebookWorkspace | unknown> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||
}
|
||||
|
||||
/* Creates the notebook workspace for a Cosmos DB account. */
|
||||
export async function createOrUpdate(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
notebookWorkspaceName: string,
|
||||
body: Types.NotebookWorkspaceCreateUpdateParameters
|
||||
): Promise<Types.NotebookWorkspace | unknown> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
||||
}
|
||||
|
||||
/* Deletes the notebook workspace for a Cosmos DB account. */
|
||||
export async function destroy(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
notebookWorkspaceName: string
|
||||
): Promise<void | unknown> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
|
||||
}
|
||||
|
||||
/* Retrieves the connection info for the notebook workspace */
|
||||
export async function listConnectionInfo(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
notebookWorkspaceName: string
|
||||
): Promise<Types.NotebookWorkspaceConnectionInfoResult | unknown> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/listConnectionInfo`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
/* Regenerates the auth token for the notebook workspace */
|
||||
export async function regenerateAuthToken(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
notebookWorkspaceName: string
|
||||
): Promise<void | unknown> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/regenerateAuthToken`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
|
||||
/* Starts the notebook workspace */
|
||||
export async function start(
|
||||
subscriptionId: string,
|
||||
resourceGroupName: string,
|
||||
accountName: string,
|
||||
notebookWorkspaceName: string
|
||||
): Promise<void | unknown> {
|
||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/start`;
|
||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
||||
}
|
||||
36
src/Utils/arm/generatedClients/2020-04-01-notebooks/types.ts
Normal file
36
src/Utils/arm/generatedClients/2020-04-01-notebooks/types.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
AUTOGENERATED FILE
|
||||
Do not manually edit
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
*/
|
||||
|
||||
/* Parameters to create a notebook workspace resource */
|
||||
export type NotebookWorkspaceCreateUpdateParameters = unknown;
|
||||
|
||||
/* A list of notebook workspace resources */
|
||||
export interface NotebookWorkspaceListResult {
|
||||
/* Array of notebook workspace resources */
|
||||
value?: NotebookWorkspace[];
|
||||
}
|
||||
|
||||
/* A notebook workspace resource */
|
||||
export type NotebookWorkspace = unknown & {
|
||||
/* Resource properties. */
|
||||
properties?: NotebookWorkspaceProperties;
|
||||
};
|
||||
|
||||
/* Properties of a notebook workspace resource. */
|
||||
export interface NotebookWorkspaceProperties {
|
||||
/* Specifies the endpoint of Notebook server. */
|
||||
readonly notebookServerEndpoint?: string;
|
||||
/* Status of the notebook workspace. Possible values are: Creating, Online, Deleting, Failed, Updating. */
|
||||
readonly status?: string;
|
||||
}
|
||||
|
||||
/* The connection info for the given notebook workspace */
|
||||
export interface NotebookWorkspaceConnectionInfoResult {
|
||||
/* Specifies auth token used for connecting to Notebook server (uses token-based auth). */
|
||||
readonly authToken?: string;
|
||||
/* Specifies the endpoint of Notebook server. */
|
||||
readonly notebookServerEndpoint?: string;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ Instead, generate ARM clients that consume this function with stricter typing.
|
||||
*/
|
||||
|
||||
import promiseRetry, { AbortError } from "p-retry";
|
||||
import { ErrorResponse } from "./generatedClients/2020-04-01/types";
|
||||
import { ErrorResponse } from "./generatedClients/2020-04-01-cosmos-db/types";
|
||||
import { userContext } from "../../UserContext";
|
||||
|
||||
interface ARMError extends Error {
|
||||
|
||||
@@ -14,12 +14,14 @@ But it does work well enough to generate a fully typed tree-shakeable client for
|
||||
Results of this file should be checked into the repo.
|
||||
*/
|
||||
|
||||
const rpname = "cosmos-db"; // Can also use "notebooks"
|
||||
|
||||
// Array of strings to use for eventual output
|
||||
const outputTypes: string[] = [""];
|
||||
const version = "2020-04-01";
|
||||
const schemaURL = `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/${version}/cosmos-db.json`;
|
||||
const schemaURL = `https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/${version}/${rpname}.json`;
|
||||
|
||||
const outputDir = path.join(__dirname, `../../src/Utils/arm/generatedClients/${version}`);
|
||||
const outputDir = path.join(__dirname, `../../src/Utils/arm/generatedClients/${version}-${rpname}`);
|
||||
mkdirp.sync(outputDir);
|
||||
|
||||
// Buckets for grouping operations based on their name
|
||||
|
||||
Reference in New Issue
Block a user