Skip to content

Automatically refresh workspaces #203

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,19 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
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()
Expand Down
56 changes: 53 additions & 3 deletions src/workspacesProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,53 @@ export enum WorkspaceQuery {
export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
private workspaces: WorkspaceTreeItem[] = []
private agentWatchers: Record<WorkspaceAgent["id"], { dispose: () => 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) {
return
}
this.fetching = true

// TODO: It would be better to reuse these.
Object.values(this.agentWatchers).forEach((watcher) => 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()
}
}

/**
Expand Down Expand Up @@ -82,6 +101,37 @@ export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeIte
})
}

/**
* Either start or stop the refresh timer based on visibility.
*/
setVisibility(visible: boolean) {
this.visible = visible
if (!visible) {
this.cancelPendingRefresh()
} else {
this.maybeScheduleRefresh()
}
}

private cancelPendingRefresh() {
if (this.timeout) {
clearTimeout(this.timeout)
this.timeout = undefined
}
}

/**
* Schedule a refresh if one is not already scheduled or underway and a
* timeout length was provided.
*/
private maybeScheduleRefresh() {
if (this.timerSeconds && !this.timeout && !this.fetching) {
this.timeout = setTimeout(() => {
this.fetchAndRefresh()
}, this.timerSeconds * 1000)
}
}

private _onDidChangeTreeData: vscode.EventEmitter<vscode.TreeItem | undefined | null | void> =
new vscode.EventEmitter<vscode.TreeItem | undefined | null | void>()
readonly onDidChangeTreeData: vscode.Event<vscode.TreeItem | undefined | null | void> =
Expand Down