diff --git a/src/extension.ts b/src/extension.ts index 8167c7ff..66754b50 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -90,12 +90,19 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { return config }) - const myWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.Mine, storage) + const myWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.Mine, storage, 5) const allWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.All, storage) - vscode.window.registerTreeDataProvider("myWorkspaces", myWorkspacesProvider) + // createTreeView, unlike registerTreeDataProvider, gives us the tree view API + // (so we can see when it is visible) but otherwise they have the same effect. + const wsTree = vscode.window.createTreeView("myWorkspaces", { treeDataProvider: myWorkspacesProvider }) vscode.window.registerTreeDataProvider("allWorkspaces", allWorkspacesProvider) + myWorkspacesProvider.setVisibility(wsTree.visible) + wsTree.onDidChangeVisibility((event) => { + myWorkspacesProvider.setVisibility(event.visible) + }) + const url = storage.getURL() if (url) { getAuthenticatedUser() diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts index fba0f65a..830409a3 100644 --- a/src/workspacesProvider.ts +++ b/src/workspacesProvider.ts @@ -14,17 +14,22 @@ export enum WorkspaceQuery { export class WorkspaceProvider implements vscode.TreeDataProvider { private workspaces: WorkspaceTreeItem[] = [] private agentWatchers: Record void; metadata?: AgentMetadataEvent[] }> = {} + private timeout: NodeJS.Timeout | undefined + private visible = false private fetching = false constructor( private readonly getWorkspacesQuery: WorkspaceQuery, private readonly storage: Storage, + private readonly timerSeconds?: number, ) { this.fetchAndRefresh() } - // fetchAndRefresh fetches new workspaces then re-renders the entire tree. - // Trying to call this while already refreshing is a no-op and will return + // fetchAndRefresh fetches new workspaces, re-renders the entire tree, then + // keeps refreshing (if a timer length was provided) as long as the user is + // still logged in and no errors were encountered fetching workspaces. + // Calling this while already refreshing is a no-op and will return // immediately. async fetchAndRefresh() { if (this.fetching) { @@ -32,16 +37,30 @@ export class WorkspaceProvider implements vscode.TreeDataProvider watcher.dispose()) + // It is possible we called fetchAndRefresh() manually (through the button + // for example), in which case we might still have a pending refresh that + // needs to be cleared. + this.cancelPendingRefresh() + + let hadError = false try { this.workspaces = await this.fetch() } catch (error) { + hadError = true this.workspaces = [] } - this.refresh() this.fetching = false + + this.refresh() + + // As long as there was no error we can schedule the next refresh. + if (hadError) { + this.maybeScheduleRefresh() + } } /** @@ -82,6 +101,37 @@ export class WorkspaceProvider implements vscode.TreeDataProvider { + this.fetchAndRefresh() + }, this.timerSeconds * 1000) + } + } + private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter() readonly onDidChangeTreeData: vscode.Event =