Migrate resource tree to react (#941)

This commit is contained in:
victor-meng
2021-07-20 11:40:04 -07:00
committed by GitHub
parent afacde4041
commit 6d46e48490
25 changed files with 915 additions and 124 deletions

View File

@@ -1,5 +1,6 @@
import { stringifyNotebook } from "@nteract/commutable";
import { FileType, IContent, IContentProvider, IEmptyContent, ServerConfig } from "@nteract/core";
import { cloneDeep } from "lodash";
import { AjaxResponse } from "rxjs/ajax";
import * as StringUtils from "../../Utils/StringUtils";
import * as FileSystemUtil from "./FileSystemUtil";
@@ -14,7 +15,17 @@ export class NotebookContentClient {
* This updates the item and points all the children's parent to this item
* @param item
*/
public updateItemChildren(item: NotebookContentItem): Promise<void> {
public async updateItemChildren(item: NotebookContentItem): Promise<NotebookContentItem> {
const subItems = await this.fetchNotebookFiles(item.path);
const clonedItem = cloneDeep(item);
subItems.forEach((subItem) => (subItem.parent = clonedItem));
clonedItem.children = subItems;
return clonedItem;
}
// TODO: Delete this function when ResourceTreeAdapter is removed.
public async updateItemChildrenInPlace(item: NotebookContentItem): Promise<void> {
return this.fetchNotebookFiles(item.path).then((subItems) => {
item.children = subItems;
subItems.forEach((subItem) => (subItem.parent = item));
@@ -55,18 +66,20 @@ export class NotebookContentClient {
});
}
public deleteContentItem(item: NotebookContentItem): Promise<void> {
return this.deleteNotebookFile(item.path).then((path: string) => {
if (!path || path !== item.path) {
throw new Error("No path provided");
}
public async deleteContentItem(item: NotebookContentItem): Promise<void> {
const path = await this.deleteNotebookFile(item.path);
useNotebook.getState().deleteNotebookItem(item);
if (item.parent && item.parent.children) {
// Remove deleted child
const newChildren = item.parent.children.filter((child) => child.path !== path);
item.parent.children = newChildren;
}
});
// TODO: Delete once old resource tree is removed
if (!path || path !== item.path) {
throw new Error("No path provided");
}
if (item.parent && item.parent.children) {
// Remove deleted child
const newChildren = item.parent.children.filter((child) => child.path !== path);
item.parent.children = newChildren;
}
}
/**

View File

@@ -1,3 +1,4 @@
import { cloneDeep } from "lodash";
import create, { UseStore } from "zustand";
import { AuthType } from "../../AuthType";
import * as Constants from "../../Common/Constants";
@@ -5,8 +6,12 @@ import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
import * as Logger from "../../Common/Logger";
import { configContext } from "../../ConfigContext";
import * as DataModels from "../../Contracts/DataModels";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem";
import NotebookManager from "./NotebookManager";
interface NotebookState {
isNotebookEnabled: boolean;
@@ -18,6 +23,9 @@ interface NotebookState {
isShellEnabled: boolean;
notebookBasePath: string;
isInitializingNotebooks: boolean;
myNotebooksContentRoot: NotebookContentItem;
gitHubNotebooksContentRoot: NotebookContentItem;
galleryContentRoot: NotebookContentItem;
setIsNotebookEnabled: (isNotebookEnabled: boolean) => void;
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => void;
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => void;
@@ -27,9 +35,13 @@ interface NotebookState {
setIsShellEnabled: (isShellEnabled: boolean) => void;
setNotebookBasePath: (notebookBasePath: string) => void;
refreshNotebooksEnabledStateForAccount: () => Promise<void>;
findItem: (root: NotebookContentItem, item: NotebookContentItem) => NotebookContentItem;
updateNotebookItem: (item: NotebookContentItem) => void;
deleteNotebookItem: (item: NotebookContentItem) => void;
initializeNotebooksTree: (notebookManager: NotebookManager) => Promise<void>;
}
export const useNotebook: UseStore<NotebookState> = create((set) => ({
export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
isNotebookEnabled: false,
isNotebooksEnabledForAccount: false,
notebookServerInfo: {
@@ -46,6 +58,9 @@ export const useNotebook: UseStore<NotebookState> = create((set) => ({
isShellEnabled: false,
notebookBasePath: Constants.Notebook.defaultBasePath,
isInitializingNotebooks: false,
myNotebooksContentRoot: undefined,
gitHubNotebooksContentRoot: undefined,
galleryContentRoot: undefined,
setIsNotebookEnabled: (isNotebookEnabled: boolean) => set({ isNotebookEnabled }),
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => set({ isNotebooksEnabledForAccount }),
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) =>
@@ -103,4 +118,92 @@ export const useNotebook: UseStore<NotebookState> = create((set) => ({
set({ isNotebooksEnabledForAccount: false });
}
},
findItem: (root: NotebookContentItem, item: NotebookContentItem): NotebookContentItem => {
const currentItem = root || get().myNotebooksContentRoot;
if (currentItem) {
if (currentItem.path === item.path && currentItem.name === item.name) {
return currentItem;
}
if (currentItem.children) {
for (const childItem of currentItem.children) {
const result = get().findItem(childItem, item);
if (result) {
return result;
}
}
}
}
return undefined;
},
updateNotebookItem: (item: NotebookContentItem): void => {
const root = cloneDeep(get().myNotebooksContentRoot);
const parentItem = get().findItem(root, item.parent);
parentItem.children = parentItem.children.filter((child) => child.path !== item.path);
parentItem.children.push(item);
item.parent = parentItem;
set({ myNotebooksContentRoot: root });
},
deleteNotebookItem: (item: NotebookContentItem): void => {
const root = cloneDeep(get().myNotebooksContentRoot);
const parentItem = get().findItem(root, item.parent);
parentItem.children = parentItem.children.filter((child) => child.path !== item.path);
set({ myNotebooksContentRoot: root });
},
initializeNotebooksTree: async (notebookManager: NotebookManager): Promise<void> => {
set({
myNotebooksContentRoot: {
name: "My Notebooks",
path: get().notebookBasePath,
type: NotebookContentItemType.Directory,
},
galleryContentRoot: {
name: "Gallery",
path: "Gallery",
type: NotebookContentItemType.File,
},
});
if (notebookManager?.gitHubOAuthService?.isLoggedIn()) {
set({
gitHubNotebooksContentRoot: {
name: "GitHub repos",
path: "PsuedoDir",
type: NotebookContentItemType.Directory,
},
});
}
if (get().notebookServerInfo?.notebookServerEndpoint) {
const updatedRoot = await notebookManager?.notebookContentClient?.updateItemChildren({
name: "My Notebooks",
path: get().notebookBasePath,
type: NotebookContentItemType.Directory,
});
set({ myNotebooksContentRoot: updatedRoot });
if (updatedRoot?.children) {
// Count 1st generation children (tree is lazy-loaded)
const nodeCounts = { files: 0, notebooks: 0, directories: 0 };
updatedRoot.children.forEach((notebookItem) => {
switch (notebookItem.type) {
case NotebookContentItemType.File:
nodeCounts.files++;
break;
case NotebookContentItemType.Directory:
nodeCounts.directories++;
break;
case NotebookContentItemType.Notebook:
nodeCounts.notebooks++;
break;
default:
break;
}
});
TelemetryProcessor.trace(Action.RefreshResourceTreeMyNotebooks, ActionModifiers.Mark, { ...nodeCounts });
}
}
},
}));