mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-12-01 01:46:57 +00:00
Remove ResourceTreeAdapter
This commit is contained in:
parent
56b5a9861b
commit
4480a7250d
@ -392,6 +392,9 @@ export class Notebook {
|
|||||||
public static readonly kernelRestartInitialDelayMs = 1000;
|
public static readonly kernelRestartInitialDelayMs = 1000;
|
||||||
public static readonly kernelRestartMaxDelayMs = 20000;
|
public static readonly kernelRestartMaxDelayMs = 20000;
|
||||||
public static readonly autoSaveIntervalMs = 120000;
|
public static readonly autoSaveIntervalMs = 120000;
|
||||||
|
|
||||||
|
public static readonly MyNotebooksTitle = "My Notebooks";
|
||||||
|
public static readonly GitHubReposTitle = "GitHub repos";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SparkLibrary {
|
export class SparkLibrary {
|
||||||
|
@ -56,7 +56,6 @@ import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
|||||||
import { QueriesClient } from "../Common/QueriesClient";
|
import { QueriesClient } from "../Common/QueriesClient";
|
||||||
import { QuerySelectPane } from "./Panes/Tables/QuerySelectPane";
|
import { QuerySelectPane } from "./Panes/Tables/QuerySelectPane";
|
||||||
import { ResourceProviderClientFactory } from "../ResourceProvider/ResourceProviderClientFactory";
|
import { ResourceProviderClientFactory } from "../ResourceProvider/ResourceProviderClientFactory";
|
||||||
import { ResourceTreeAdapter } from "./Tree/ResourceTreeAdapter";
|
|
||||||
import { ResourceTreeAdapterForResourceToken } from "./Tree/ResourceTreeAdapterForResourceToken";
|
import { ResourceTreeAdapterForResourceToken } from "./Tree/ResourceTreeAdapterForResourceToken";
|
||||||
import { RouteHandler } from "../RouteHandlers/RouteHandler";
|
import { RouteHandler } from "../RouteHandlers/RouteHandler";
|
||||||
import { SaveQueryPane } from "./Panes/SaveQueryPane";
|
import { SaveQueryPane } from "./Panes/SaveQueryPane";
|
||||||
@ -102,6 +101,8 @@ export interface ExplorerParams {
|
|||||||
closeSidePanel: () => void;
|
closeSidePanel: () => void;
|
||||||
closeDialog: () => void;
|
closeDialog: () => void;
|
||||||
openDialog: (props: DialogProps) => void;
|
openDialog: (props: DialogProps) => void;
|
||||||
|
|
||||||
|
onRefreshNotebookList: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Explorer {
|
export default class Explorer {
|
||||||
@ -160,7 +161,6 @@ export default class Explorer {
|
|||||||
public isLeftPaneExpanded: ko.Observable<boolean>;
|
public isLeftPaneExpanded: ko.Observable<boolean>;
|
||||||
public selectedNode: ko.Observable<ViewModels.TreeNode>;
|
public selectedNode: ko.Observable<ViewModels.TreeNode>;
|
||||||
public isRefreshingExplorer: ko.Observable<boolean>;
|
public isRefreshingExplorer: ko.Observable<boolean>;
|
||||||
private resourceTree: ResourceTreeAdapter;
|
|
||||||
private selfServeComponentAdapter: SelfServeComponentAdapter;
|
private selfServeComponentAdapter: SelfServeComponentAdapter;
|
||||||
|
|
||||||
// Resource Token
|
// Resource Token
|
||||||
@ -249,7 +249,7 @@ export default class Explorer {
|
|||||||
|
|
||||||
private static readonly MaxNbDatabasesToAutoExpand = 5;
|
private static readonly MaxNbDatabasesToAutoExpand = 5;
|
||||||
|
|
||||||
constructor(params?: ExplorerParams) {
|
constructor(private params?: ExplorerParams) {
|
||||||
this.setIsNotificationConsoleExpanded = params?.setIsNotificationConsoleExpanded;
|
this.setIsNotificationConsoleExpanded = params?.setIsNotificationConsoleExpanded;
|
||||||
this.setNotificationConsoleData = params?.setNotificationConsoleData;
|
this.setNotificationConsoleData = params?.setNotificationConsoleData;
|
||||||
this.setInProgressConsoleDataIdToBeDeleted = params?.setInProgressConsoleDataIdToBeDeleted;
|
this.setInProgressConsoleDataIdToBeDeleted = params?.setInProgressConsoleDataIdToBeDeleted;
|
||||||
@ -859,7 +859,6 @@ export default class Explorer {
|
|||||||
this.notebookManager.initialize({
|
this.notebookManager.initialize({
|
||||||
container: this,
|
container: this,
|
||||||
notebookBasePath: this.notebookBasePath,
|
notebookBasePath: this.notebookBasePath,
|
||||||
resourceTree: this.resourceTree,
|
|
||||||
refreshCommandBarButtons: () => this.refreshCommandBarButtons(),
|
refreshCommandBarButtons: () => this.refreshCommandBarButtons(),
|
||||||
refreshNotebookList: () => this.refreshNotebookList(),
|
refreshNotebookList: () => this.refreshNotebookList(),
|
||||||
});
|
});
|
||||||
@ -874,7 +873,6 @@ export default class Explorer {
|
|||||||
|
|
||||||
this.isSparkEnabled = ko.observable(false);
|
this.isSparkEnabled = ko.observable(false);
|
||||||
this.isSparkEnabled.subscribe((isEnabled: boolean) => this.refreshCommandBarButtons());
|
this.isSparkEnabled.subscribe((isEnabled: boolean) => this.refreshCommandBarButtons());
|
||||||
this.resourceTree = new ResourceTreeAdapter(this);
|
|
||||||
this.resourceTreeForResourceToken = new ResourceTreeAdapterForResourceToken(this);
|
this.resourceTreeForResourceToken = new ResourceTreeAdapterForResourceToken(this);
|
||||||
this.notebookServerInfo = ko.observable<DataModels.NotebookWorkspaceConnectionInfo>({
|
this.notebookServerInfo = ko.observable<DataModels.NotebookWorkspaceConnectionInfo>({
|
||||||
notebookServerEndpoint: undefined,
|
notebookServerEndpoint: undefined,
|
||||||
@ -2109,12 +2107,16 @@ export default class Explorer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private refreshNotebookList = async (): Promise<void> => {
|
private refreshNotebookList = async (): Promise<void> => {
|
||||||
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.resourceTree.initialize();
|
console.log("=======> refreshNotebookList");
|
||||||
|
// await this.resourceTree.initialize();
|
||||||
|
this.params?.onRefreshNotebookList();
|
||||||
|
|
||||||
this.notebookManager?.refreshPinnedRepos();
|
this.notebookManager?.refreshPinnedRepos();
|
||||||
if (this.notebookToImport) {
|
if (this.notebookToImport) {
|
||||||
this.importAndOpenContent(this.notebookToImport.name, this.notebookToImport.content);
|
this.importAndOpenContent(this.notebookToImport.name, this.notebookToImport.content);
|
||||||
@ -2250,7 +2252,7 @@ export default class Explorer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public refreshContentItem(item: NotebookContentItem): Promise<void> {
|
public refreshContentItem(item: NotebookContentItem): Promise<NotebookContentItem> {
|
||||||
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
||||||
const error = "Attempt to refresh notebook list, but notebook is not enabled";
|
const error = "Attempt to refresh notebook list, but notebook is not enabled";
|
||||||
handleError(error, "Explorer/refreshContentItem");
|
handleError(error, "Explorer/refreshContentItem");
|
||||||
|
@ -18,11 +18,13 @@ export class NotebookContentClient {
|
|||||||
/**
|
/**
|
||||||
* This updates the item and points all the children's parent to this item
|
* This updates the item and points all the children's parent to this item
|
||||||
* @param item
|
* @param item
|
||||||
|
* @return updated item
|
||||||
*/
|
*/
|
||||||
public updateItemChildren(item: NotebookContentItem): Promise<void> {
|
public updateItemChildren(item: NotebookContentItem): Promise<NotebookContentItem> {
|
||||||
return this.fetchNotebookFiles(item.path).then((subItems) => {
|
return this.fetchNotebookFiles(item.path).then((subItems) => {
|
||||||
item.children = subItems;
|
item.children = subItems;
|
||||||
subItems.forEach((subItem) => (subItem.parent = item));
|
subItems.forEach((subItem) => (subItem.parent = item));
|
||||||
|
return item;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ import { contents } from "rx-jupyter";
|
|||||||
import { NotebookContainerClient } from "./NotebookContainerClient";
|
import { NotebookContainerClient } from "./NotebookContainerClient";
|
||||||
import { MemoryUsageInfo } from "../../Contracts/DataModels";
|
import { MemoryUsageInfo } from "../../Contracts/DataModels";
|
||||||
import { NotebookContentClient } from "./NotebookContentClient";
|
import { NotebookContentClient } from "./NotebookContentClient";
|
||||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
|
||||||
import { PublishNotebookPaneAdapter } from "../Panes/PublishNotebookPaneAdapter";
|
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";
|
||||||
@ -30,7 +29,7 @@ import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
|||||||
export interface NotebookManagerOptions {
|
export interface NotebookManagerOptions {
|
||||||
container: Explorer;
|
container: Explorer;
|
||||||
notebookBasePath: ko.Observable<string>;
|
notebookBasePath: ko.Observable<string>;
|
||||||
resourceTree: ResourceTreeAdapter;
|
// resourceTree: ResourceTreeAdapter;
|
||||||
refreshCommandBarButtons: () => void;
|
refreshCommandBarButtons: () => void;
|
||||||
refreshNotebookList: () => void;
|
refreshNotebookList: () => void;
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,9 @@ import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRight
|
|||||||
import { CopyNotebookPaneComponent, CopyNotebookPaneProps } from "./CopyNotebookPaneComponent";
|
import { CopyNotebookPaneComponent, CopyNotebookPaneProps } from "./CopyNotebookPaneComponent";
|
||||||
import { IDropdownOption } from "office-ui-fabric-react";
|
import { IDropdownOption } from "office-ui-fabric-react";
|
||||||
import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService";
|
import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService";
|
||||||
import { HttpStatusCodes } from "../../Common/Constants";
|
import { HttpStatusCodes, Notebook } from "../../Common/Constants";
|
||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
import { NotebookContentItemType, NotebookContentItem } from "../Notebook/NotebookContentItem";
|
import { NotebookContentItemType, NotebookContentItem } from "../Notebook/NotebookContentItem";
|
||||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
|
||||||
import { handleError, getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
import { handleError, getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
||||||
|
|
||||||
interface Location {
|
interface Location {
|
||||||
@ -151,7 +150,7 @@ export class CopyNotebookPaneAdapter implements ReactAdapter {
|
|||||||
switch (location.type) {
|
switch (location.type) {
|
||||||
case "MyNotebooks":
|
case "MyNotebooks":
|
||||||
parent = {
|
parent = {
|
||||||
name: ResourceTreeAdapter.MyNotebooksTitle,
|
name: Notebook.MyNotebooksTitle,
|
||||||
path: this.container.getNotebookBasePath(),
|
path: this.container.getNotebookBasePath(),
|
||||||
type: NotebookContentItemType.Directory,
|
type: NotebookContentItemType.Directory,
|
||||||
};
|
};
|
||||||
@ -159,7 +158,7 @@ export class CopyNotebookPaneAdapter implements ReactAdapter {
|
|||||||
|
|
||||||
case "GitHub":
|
case "GitHub":
|
||||||
parent = {
|
parent = {
|
||||||
name: ResourceTreeAdapter.GitHubReposTitle,
|
name: Notebook.GitHubReposTitle,
|
||||||
path: GitHubUtils.toContentUri(
|
path: GitHubUtils.toContentUri(
|
||||||
this.selectedLocation.owner,
|
this.selectedLocation.owner,
|
||||||
this.selectedLocation.repo,
|
this.selectedLocation.repo,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { IPinnedRepo } from "../../Juno/JunoClient";
|
import { IPinnedRepo } from "../../Juno/JunoClient";
|
||||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
|
||||||
import {
|
import {
|
||||||
Stack,
|
Stack,
|
||||||
Label,
|
Label,
|
||||||
@ -13,6 +12,7 @@ import {
|
|||||||
IRenderFunction,
|
IRenderFunction,
|
||||||
ISelectableOption,
|
ISelectableOption,
|
||||||
} from "office-ui-fabric-react";
|
} from "office-ui-fabric-react";
|
||||||
|
import { Notebook } from "../../Common/Constants";
|
||||||
|
|
||||||
interface Location {
|
interface Location {
|
||||||
type: "MyNotebooks" | "GitHub";
|
type: "MyNotebooks" | "GitHub";
|
||||||
@ -70,8 +70,8 @@ export class CopyNotebookPaneComponent extends React.Component<CopyNotebookPaneP
|
|||||||
|
|
||||||
options.push({
|
options.push({
|
||||||
key: "MyNotebooks-Item",
|
key: "MyNotebooks-Item",
|
||||||
text: ResourceTreeAdapter.MyNotebooksTitle,
|
text: Notebook.MyNotebooksTitle,
|
||||||
title: ResourceTreeAdapter.MyNotebooksTitle,
|
title: Notebook.MyNotebooksTitle,
|
||||||
data: {
|
data: {
|
||||||
type: "MyNotebooks",
|
type: "MyNotebooks",
|
||||||
} as Location,
|
} as Location,
|
||||||
@ -86,7 +86,7 @@ export class CopyNotebookPaneComponent extends React.Component<CopyNotebookPaneP
|
|||||||
|
|
||||||
options.push({
|
options.push({
|
||||||
key: "GitHub-Header",
|
key: "GitHub-Header",
|
||||||
text: ResourceTreeAdapter.GitHubReposTitle,
|
text: Notebook.GitHubReposTitle,
|
||||||
itemType: SelectableOptionMenuItemType.Header,
|
itemType: SelectableOptionMenuItemType.Header,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
|
|
||||||
import { AccordionComponent, AccordionItemComponent } from "../Controls/Accordion/AccordionComponent";
|
import { AccordionComponent, AccordionItemComponent } from "../Controls/Accordion/AccordionComponent";
|
||||||
import { TreeComponent, TreeNode, TreeNodeMenuItem, TreeNodeComponent } from "../Controls/TreeComponent/TreeComponent";
|
import { TreeComponent, TreeNode, TreeNodeMenuItem } from "../Controls/TreeComponent/TreeComponent";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import { NotebookContentItem, NotebookContentItemType } from "../Notebook/NotebookContentItem";
|
import { NotebookContentItem, NotebookContentItemType } from "../Notebook/NotebookContentItem";
|
||||||
import { ResourceTreeContextMenuButtonFactory } from "../ContextMenuButtonFactory";
|
import { ResourceTreeContextMenuButtonFactory } from "../ContextMenuButtonFactory";
|
||||||
@ -18,11 +17,10 @@ import FileIcon from "../../../images/notebook/file-cosmos.svg";
|
|||||||
import PublishIcon from "../../../images/notebook/publish_content.svg";
|
import PublishIcon from "../../../images/notebook/publish_content.svg";
|
||||||
import { ArrayHashMap } from "../../Common/ArrayHashMap";
|
import { ArrayHashMap } from "../../Common/ArrayHashMap";
|
||||||
import { NotebookUtil } from "../Notebook/NotebookUtil";
|
import { NotebookUtil } from "../Notebook/NotebookUtil";
|
||||||
import _ from "underscore";
|
|
||||||
import { IPinnedRepo } from "../../Juno/JunoClient";
|
import { IPinnedRepo } from "../../Juno/JunoClient";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers, Source } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers, Source } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { Areas } from "../../Common/Constants";
|
import { Areas, Notebook } from "../../Common/Constants";
|
||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
import GalleryIcon from "../../../images/GalleryIcon.svg";
|
import GalleryIcon from "../../../images/GalleryIcon.svg";
|
||||||
import { Callout, Text, Link, DirectionalHint, Stack, ICalloutProps, ILinkProps } from "office-ui-fabric-react";
|
import { Callout, Text, Link, DirectionalHint, Stack, ICalloutProps, ILinkProps } from "office-ui-fabric-react";
|
||||||
@ -35,30 +33,44 @@ import TabsBase from "../Tabs/TabsBase";
|
|||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
|
||||||
export class ResourceTreeAdapter implements ReactAdapter {
|
export interface ResourceTreeProps {
|
||||||
public static readonly MyNotebooksTitle = "My Notebooks";
|
// TODO remove eventually
|
||||||
public static readonly GitHubReposTitle = "GitHub repos";
|
explorer: Explorer;
|
||||||
|
|
||||||
|
lastRefreshedTime: number;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResourceTreeState {
|
||||||
|
galleryContentRoot: NotebookContentItem;
|
||||||
|
myNotebooksContentRoot: NotebookContentItem;
|
||||||
|
gitHubNotebooksContentRoot: NotebookContentItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResourceTree extends React.Component<ResourceTreeProps, ResourceTreeState> {
|
||||||
private static readonly DataTitle = "DATA";
|
private static readonly DataTitle = "DATA";
|
||||||
private static readonly NotebooksTitle = "NOTEBOOKS";
|
private static readonly NotebooksTitle = "NOTEBOOKS";
|
||||||
private static readonly PseudoDirPath = "PsuedoDir";
|
private static readonly PseudoDirPath = "PseudoDir";
|
||||||
|
|
||||||
public parameters: ko.Observable<number>;
|
|
||||||
|
|
||||||
public galleryContentRoot: NotebookContentItem;
|
|
||||||
public myNotebooksContentRoot: NotebookContentItem;
|
|
||||||
public gitHubNotebooksContentRoot: NotebookContentItem;
|
|
||||||
|
|
||||||
private koSubsDatabaseIdMap: ArrayHashMap<ko.Subscription>; // database id -> ko subs
|
private koSubsDatabaseIdMap: ArrayHashMap<ko.Subscription>; // database id -> ko subs
|
||||||
private koSubsCollectionIdMap: ArrayHashMap<ko.Subscription>; // collection id -> ko subs
|
private koSubsCollectionIdMap: ArrayHashMap<ko.Subscription>; // collection id -> ko subs
|
||||||
private databaseCollectionIdMap: ArrayHashMap<string>; // database id -> collection ids
|
private databaseCollectionIdMap: ArrayHashMap<string>; // database id -> collection ids
|
||||||
|
|
||||||
public constructor(private container: Explorer) {
|
private readonly container: Explorer;
|
||||||
this.parameters = ko.observable(Date.now());
|
|
||||||
|
|
||||||
this.container.selectedNode.subscribe((newValue: any) => this.triggerRender());
|
constructor(props: ResourceTreeProps) {
|
||||||
this.container.tabsManager.activeTab.subscribe((newValue: TabsBase) => this.triggerRender());
|
super(props);
|
||||||
this.container.isNotebookEnabled.subscribe((newValue) => this.triggerRender());
|
this.state = {
|
||||||
|
galleryContentRoot: undefined,
|
||||||
|
myNotebooksContentRoot: undefined,
|
||||||
|
gitHubNotebooksContentRoot: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
this.container = props.explorer;
|
||||||
|
|
||||||
|
this.container.selectedNode.subscribe(() => this.triggerRender());
|
||||||
|
this.container.tabsManager.activeTab.subscribe(() => this.triggerRender());
|
||||||
|
this.container.isNotebookEnabled.subscribe(() => this.triggerRender());
|
||||||
|
|
||||||
this.koSubsDatabaseIdMap = new ArrayHashMap();
|
this.koSubsDatabaseIdMap = new ArrayHashMap();
|
||||||
this.koSubsCollectionIdMap = new ArrayHashMap();
|
this.koSubsCollectionIdMap = new ArrayHashMap();
|
||||||
@ -77,7 +89,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private traceMyNotebookTreeInfo() {
|
private traceMyNotebookTreeInfo() {
|
||||||
const myNotebooksTree = this.myNotebooksContentRoot;
|
const myNotebooksTree = this.state.myNotebooksContentRoot;
|
||||||
if (myNotebooksTree.children) {
|
if (myNotebooksTree.children) {
|
||||||
// Count 1st generation children (tree is lazy-loaded)
|
// Count 1st generation children (tree is lazy-loaded)
|
||||||
const nodeCounts = { files: 0, notebooks: 0, directories: 0 };
|
const nodeCounts = { files: 0, notebooks: 0, directories: 0 };
|
||||||
@ -100,7 +112,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderComponent(): JSX.Element {
|
render(): JSX.Element {
|
||||||
const dataRootNode = this.buildDataTree();
|
const dataRootNode = this.buildDataTree();
|
||||||
const notebooksRootNode = this.buildNotebooksTrees();
|
const notebooksRootNode = this.buildNotebooksTrees();
|
||||||
|
|
||||||
@ -108,15 +120,15 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AccordionComponent>
|
<AccordionComponent>
|
||||||
<AccordionItemComponent title={ResourceTreeAdapter.DataTitle} isExpanded={!this.gitHubNotebooksContentRoot}>
|
<AccordionItemComponent title={ResourceTree.DataTitle} isExpanded={!this.state.gitHubNotebooksContentRoot}>
|
||||||
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
||||||
</AccordionItemComponent>
|
</AccordionItemComponent>
|
||||||
<AccordionItemComponent title={ResourceTreeAdapter.NotebooksTitle}>
|
<AccordionItemComponent title={ResourceTree.NotebooksTitle}>
|
||||||
<TreeComponent className="notebookResourceTree" rootNode={notebooksRootNode} />
|
<TreeComponent className="notebookResourceTree" rootNode={notebooksRootNode} />
|
||||||
</AccordionItemComponent>
|
</AccordionItemComponent>
|
||||||
</AccordionComponent>
|
</AccordionComponent>
|
||||||
|
|
||||||
{this.galleryContentRoot && this.buildGalleryCallout()}
|
{this.state.galleryContentRoot && this.buildGalleryCallout()}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -124,52 +136,71 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initialize(): Promise<void[]> {
|
componentDidUpdate(prevProps: ResourceTreeProps): void {
|
||||||
|
if (this.props.lastRefreshedTime === undefined || prevProps.lastRefreshedTime === this.props.lastRefreshedTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async initialize(): Promise<void[]> {
|
||||||
const refreshTasks: Promise<void>[] = [];
|
const refreshTasks: Promise<void>[] = [];
|
||||||
|
|
||||||
this.galleryContentRoot = {
|
this.setState({
|
||||||
name: "Gallery",
|
galleryContentRoot: {
|
||||||
path: "Gallery",
|
name: "Gallery",
|
||||||
type: NotebookContentItemType.File,
|
path: "Gallery",
|
||||||
};
|
type: NotebookContentItemType.File,
|
||||||
|
},
|
||||||
|
|
||||||
this.myNotebooksContentRoot = {
|
myNotebooksContentRoot: {
|
||||||
name: ResourceTreeAdapter.MyNotebooksTitle,
|
name: Notebook.MyNotebooksTitle,
|
||||||
path: this.container.getNotebookBasePath(),
|
path: this.container.getNotebookBasePath(),
|
||||||
type: NotebookContentItemType.Directory,
|
type: NotebookContentItemType.Directory,
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("====> componentDidUpdate");
|
||||||
// Only if notebook server is available we can refresh
|
// Only if notebook server is available we can refresh
|
||||||
if (this.container.notebookServerInfo().notebookServerEndpoint) {
|
if (this.container.notebookServerInfo().notebookServerEndpoint) {
|
||||||
refreshTasks.push(
|
refreshTasks.push(
|
||||||
this.container.refreshContentItem(this.myNotebooksContentRoot).then(() => {
|
this.container.refreshContentItem(this.state.myNotebooksContentRoot).then(root => {
|
||||||
this.triggerRender();
|
this.setState({ myNotebooksContentRoot: root });
|
||||||
|
// this.triggerRender();
|
||||||
this.traceMyNotebookTreeInfo();
|
this.traceMyNotebookTreeInfo();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
if (this.container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
||||||
this.gitHubNotebooksContentRoot = {
|
this.setState({
|
||||||
name: ResourceTreeAdapter.GitHubReposTitle,
|
gitHubNotebooksContentRoot: {
|
||||||
path: ResourceTreeAdapter.PseudoDirPath,
|
name: Notebook.GitHubReposTitle,
|
||||||
type: NotebookContentItemType.Directory,
|
path: ResourceTree.PseudoDirPath,
|
||||||
};
|
type: NotebookContentItemType.Directory,
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.gitHubNotebooksContentRoot = undefined;
|
this.setState({
|
||||||
|
gitHubNotebooksContentRoot: undefined
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(refreshTasks);
|
return Promise.all(refreshTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public initializeGitHubRepos(pinnedRepos: IPinnedRepo[]): void {
|
public initializeGitHubRepos(pinnedRepos: IPinnedRepo[]): void {
|
||||||
if (this.gitHubNotebooksContentRoot) {
|
if (this.state.gitHubNotebooksContentRoot) {
|
||||||
this.gitHubNotebooksContentRoot.children = [];
|
const { gitHubNotebooksContentRoot } = this.state;
|
||||||
|
gitHubNotebooksContentRoot.children = [];
|
||||||
|
this.setState({ gitHubNotebooksContentRoot });
|
||||||
|
|
||||||
pinnedRepos?.forEach((pinnedRepo) => {
|
pinnedRepos?.forEach((pinnedRepo) => {
|
||||||
const repoFullName = GitHubUtils.toRepoFullName(pinnedRepo.owner, pinnedRepo.name);
|
const repoFullName = GitHubUtils.toRepoFullName(pinnedRepo.owner, pinnedRepo.name);
|
||||||
const repoTreeItem: NotebookContentItem = {
|
const repoTreeItem: NotebookContentItem = {
|
||||||
name: repoFullName,
|
name: repoFullName,
|
||||||
path: ResourceTreeAdapter.PseudoDirPath,
|
path: ResourceTree.PseudoDirPath,
|
||||||
type: NotebookContentItemType.Directory,
|
type: NotebookContentItemType.Directory,
|
||||||
children: [],
|
children: [],
|
||||||
};
|
};
|
||||||
@ -182,7 +213,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gitHubNotebooksContentRoot.children.push(repoTreeItem);
|
this.state.gitHubNotebooksContentRoot.children.push(repoTreeItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.triggerRender();
|
this.triggerRender();
|
||||||
@ -296,7 +327,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
children.push(schemaNode);
|
children.push(schemaNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ResourceTreeAdapter.showScriptNodes(this.container)) {
|
if (ResourceTree.showScriptNodes(this.container)) {
|
||||||
children.push(this.buildStoredProcedureNode(collection));
|
children.push(this.buildStoredProcedureNode(collection));
|
||||||
children.push(this.buildUserDefinedFunctionsNode(collection));
|
children.push(this.buildUserDefinedFunctionsNode(collection));
|
||||||
children.push(this.buildTriggerNode(collection));
|
children.push(this.buildTriggerNode(collection));
|
||||||
@ -337,7 +368,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
onExpanded: () => {
|
onExpanded: () => {
|
||||||
if (ResourceTreeAdapter.showScriptNodes(this.container)) {
|
if (ResourceTree.showScriptNodes(this.container)) {
|
||||||
collection.loadStoredProcedures();
|
collection.loadStoredProcedures();
|
||||||
collection.loadUserDefinedFunctions();
|
collection.loadUserDefinedFunctions();
|
||||||
collection.loadTriggers();
|
collection.loadTriggers();
|
||||||
@ -416,7 +447,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public buildSchemaNode(collection: ViewModels.Collection): TreeNode {
|
public buildSchemaNode(collection: ViewModels.Collection): TreeNode {
|
||||||
if (collection.analyticalStorageTtl() == undefined) {
|
if (collection.analyticalStorageTtl() === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,13 +468,15 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getSchemaNodes(fields: DataModels.IDataField[]): TreeNode[] {
|
private getSchemaNodes(fields: DataModels.IDataField[]): TreeNode[] {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const schema: any = {};
|
const schema: any = {};
|
||||||
|
|
||||||
//unflatten
|
//unflatten
|
||||||
fields.forEach((field: DataModels.IDataField, fieldIndex: number) => {
|
fields.forEach((field: DataModels.IDataField) => {
|
||||||
const path: string[] = field.path.split(".");
|
const path: string[] = field.path.split(".");
|
||||||
const fieldProperties = [field.dataType.name, `HasNulls: ${field.hasNulls}`];
|
const fieldProperties = [field.dataType.name, `HasNulls: ${field.hasNulls}`];
|
||||||
let current: any = {};
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
let current: any = {};
|
||||||
path.forEach((name: string, pathIndex: number) => {
|
path.forEach((name: string, pathIndex: number) => {
|
||||||
if (pathIndex === 0) {
|
if (pathIndex === 0) {
|
||||||
if (schema[name] === undefined) {
|
if (schema[name] === undefined) {
|
||||||
@ -467,9 +500,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const traverse = (obj: any): TreeNode[] => {
|
const traverse = (obj: any): TreeNode[] => {
|
||||||
const children: TreeNode[] = [];
|
const children: TreeNode[] = [];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-null/no-null
|
||||||
if (obj !== null && !Array.isArray(obj) && typeof obj === "object") {
|
if (obj !== null && !Array.isArray(obj) && typeof obj === "object") {
|
||||||
Object.entries(obj).forEach(([key, value]) => {
|
Object.entries(obj).forEach(([key, value]) => {
|
||||||
children.push({ label: key, children: traverse(value) });
|
children.push({ label: key, children: traverse(value) });
|
||||||
@ -485,21 +520,21 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private buildNotebooksTrees(): TreeNode {
|
private buildNotebooksTrees(): TreeNode {
|
||||||
let notebooksTree: TreeNode = {
|
const notebooksTree: TreeNode = {
|
||||||
label: undefined,
|
label: undefined,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
children: [],
|
children: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.galleryContentRoot) {
|
if (this.state.galleryContentRoot) {
|
||||||
notebooksTree.children.push(this.buildGalleryNotebooksTree());
|
notebooksTree.children.push(this.buildGalleryNotebooksTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.myNotebooksContentRoot) {
|
if (this.state.myNotebooksContentRoot) {
|
||||||
notebooksTree.children.push(this.buildMyNotebooksTree());
|
notebooksTree.children.push(this.buildMyNotebooksTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.gitHubNotebooksContentRoot) {
|
if (this.state.gitHubNotebooksContentRoot) {
|
||||||
// collapse all other notebook nodes
|
// collapse all other notebook nodes
|
||||||
notebooksTree.children.forEach((node) => (node.isExpanded = false));
|
notebooksTree.children.forEach((node) => (node.isExpanded = false));
|
||||||
notebooksTree.children.push(this.buildGitHubNotebooksTree());
|
notebooksTree.children.push(this.buildGitHubNotebooksTree());
|
||||||
@ -569,7 +604,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
|
|
||||||
private buildMyNotebooksTree(): TreeNode {
|
private buildMyNotebooksTree(): TreeNode {
|
||||||
const myNotebooksTree: TreeNode = this.buildNotebookDirectoryNode(
|
const myNotebooksTree: TreeNode = this.buildNotebookDirectoryNode(
|
||||||
this.myNotebooksContentRoot,
|
this.state.myNotebooksContentRoot,
|
||||||
(item: NotebookContentItem) => {
|
(item: NotebookContentItem) => {
|
||||||
this.container.openNotebook(item).then((hasOpened) => {
|
this.container.openNotebook(item).then((hasOpened) => {
|
||||||
if (hasOpened) {
|
if (hasOpened) {
|
||||||
@ -590,7 +625,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
|
|
||||||
private buildGitHubNotebooksTree(): TreeNode {
|
private buildGitHubNotebooksTree(): TreeNode {
|
||||||
const gitHubNotebooksTree: TreeNode = this.buildNotebookDirectoryNode(
|
const gitHubNotebooksTree: TreeNode = this.buildNotebookDirectoryNode(
|
||||||
this.gitHubNotebooksContentRoot,
|
this.state.gitHubNotebooksContentRoot,
|
||||||
(item: NotebookContentItem) => {
|
(item: NotebookContentItem) => {
|
||||||
this.container.openNotebook(item).then((hasOpened) => {
|
this.container.openNotebook(item).then((hasOpened) => {
|
||||||
if (hasOpened) {
|
if (hasOpened) {
|
||||||
@ -674,6 +709,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
/* TODO Redesign Tab interface so that resource tree doesn't need to know about NotebookV2Tab.
|
/* TODO Redesign Tab interface so that resource tree doesn't need to know about NotebookV2Tab.
|
||||||
NotebookV2Tab could be dynamically imported, but not worth it to just get this type right.
|
NotebookV2Tab could be dynamically imported, but not worth it to just get this type right.
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(activeTab as any).notebookPath() === item.path
|
(activeTab as any).notebookPath() === item.path
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -829,11 +865,12 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
/* TODO Redesign Tab interface so that resource tree doesn't need to know about NotebookV2Tab.
|
/* TODO Redesign Tab interface so that resource tree doesn't need to know about NotebookV2Tab.
|
||||||
NotebookV2Tab could be dynamically imported, but not worth it to just get this type right.
|
NotebookV2Tab could be dynamically imported, but not worth it to just get this type right.
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(activeTab as any).notebookPath() === item.path
|
(activeTab as any).notebookPath() === item.path
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
contextMenu:
|
contextMenu:
|
||||||
createDirectoryContextMenu && item.path !== ResourceTreeAdapter.PseudoDirPath
|
createDirectoryContextMenu && item.path !== ResourceTree.PseudoDirPath
|
||||||
? this.createDirectoryContextMenu(item)
|
? this.createDirectoryContextMenu(item)
|
||||||
: undefined,
|
: undefined,
|
||||||
data: item,
|
data: item,
|
||||||
@ -841,8 +878,8 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public triggerRender() {
|
private triggerRender() {
|
||||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
this.setState({});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,6 +1,6 @@
|
|||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import { ResourceTreeAdapter } from "./ResourceTreeAdapter";
|
import { ResourceTreeAdapter } from "./ResourceTree";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
import TabsBase from "../Tabs/TabsBase";
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import * as ko from "knockout";
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ResourceTreeAdapter } from "./ResourceTreeAdapter";
|
import { ResourceTreeAdapter } from "./ResourceTree";
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import { TreeComponent, TreeNode, TreeComponentProps } from "../Controls/TreeComponent/TreeComponent";
|
import { TreeComponent, TreeNode, TreeComponentProps } from "../Controls/TreeComponent/TreeComponent";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
|
17
src/Main.tsx
17
src/Main.tsx
@ -69,6 +69,8 @@ import { NotificationConsoleComponent } from "./Explorer/Menus/NotificationConso
|
|||||||
import { PanelContainerComponent } from "./Explorer/Panes/PanelContainerComponent";
|
import { PanelContainerComponent } from "./Explorer/Panes/PanelContainerComponent";
|
||||||
import { SplashScreen } from "./Explorer/SplashScreen/SplashScreen";
|
import { SplashScreen } from "./Explorer/SplashScreen/SplashScreen";
|
||||||
import { Dialog, DialogProps } from "./Explorer/Controls/Dialog";
|
import { Dialog, DialogProps } from "./Explorer/Controls/Dialog";
|
||||||
|
import { ResourceTree } from "./Explorer/Tree/ResourceTree";
|
||||||
|
import { useNotebooks } from "./hooks/useNotebooks";
|
||||||
|
|
||||||
initializeIcons();
|
initializeIcons();
|
||||||
|
|
||||||
@ -90,6 +92,7 @@ const App: React.FunctionComponent = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { isPanelOpen, panelContent, headerText, openSidePanel, closeSidePanel } = useSidePanel();
|
const { isPanelOpen, panelContent, headerText, openSidePanel, closeSidePanel } = useSidePanel();
|
||||||
|
const {lastRefreshTime, refreshList} = useNotebooks();
|
||||||
|
|
||||||
const explorerParams: ExplorerParams = {
|
const explorerParams: ExplorerParams = {
|
||||||
setIsNotificationConsoleExpanded,
|
setIsNotificationConsoleExpanded,
|
||||||
@ -99,10 +102,20 @@ const App: React.FunctionComponent = () => {
|
|||||||
closeSidePanel,
|
closeSidePanel,
|
||||||
openDialog,
|
openDialog,
|
||||||
closeDialog,
|
closeDialog,
|
||||||
|
onRefreshNotebookList: refreshList
|
||||||
};
|
};
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const explorer = useKnockoutExplorer(config?.platform, explorerParams);
|
const explorer = useKnockoutExplorer(config?.platform, explorerParams);
|
||||||
|
|
||||||
|
// const [databases, setDatabases] = useState();
|
||||||
|
// useEffect(() => {
|
||||||
|
// fetchDatabases().then((dbs) => {
|
||||||
|
// setDatabases(dbs)
|
||||||
|
// explorer.databases(dbs)
|
||||||
|
// });
|
||||||
|
// const databases = useDatabases(explorer)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flexContainer">
|
<div className="flexContainer">
|
||||||
<div
|
<div
|
||||||
@ -167,7 +180,9 @@ const App: React.FunctionComponent = () => {
|
|||||||
style={{ overflowY: "auto" }}
|
style={{ overflowY: "auto" }}
|
||||||
data-bind="if: isAuthWithResourceToken(), react:resourceTreeForResourceToken"
|
data-bind="if: isAuthWithResourceToken(), react:resourceTreeForResourceToken"
|
||||||
/>
|
/>
|
||||||
<div style={{ overflowY: "auto" }} data-bind="if: !isAuthWithResourceToken(), react:resourceTree" />
|
<div style={{ overflowY: "auto" }} data-bind="if: !isAuthWithResourceToken()">
|
||||||
|
<ResourceTree explorer={explorer} lastRefreshedTime={lastRefreshTime} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Collections Window - End */}
|
{/* Collections Window - End */}
|
||||||
</div>
|
</div>
|
||||||
|
16
src/hooks/useNotebooks.ts
Normal file
16
src/hooks/useNotebooks.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export interface NotebookHooks {
|
||||||
|
lastRefreshTime: number;
|
||||||
|
refreshList: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNotebooks = (): NotebookHooks => {
|
||||||
|
const [lastRefreshTime, setLastRefreshTime] = useState<number>(undefined);
|
||||||
|
|
||||||
|
const refreshList = (): void => {
|
||||||
|
setLastRefreshTime(new Date().getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
return { lastRefreshTime, refreshList };
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user