Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: show agent metadata#92

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
rodrimaia merged 7 commits intomainfromshow-agent-metadata
May 9, 2023
Merged
Show file tree
Hide file tree
Changes fromall 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
3 changes: 2 additions & 1 deletionpackage.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -226,6 +226,7 @@
"tar-fs": "^2.1.1",
"which": "^2.0.2",
"ws": "^8.11.0",
"yaml": "^1.10.0"
"yaml": "^1.10.0",
"zod": "^3.21.4"
}
}
21 changes: 21 additions & 0 deletionssrc/api-helper.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
import { z } from "zod"

export function extractAgents(workspace: Workspace): WorkspaceAgent[] {
const agents = workspace.latest_build.resources.reduce((acc, resource) => {
Expand All@@ -7,3 +8,23 @@ export function extractAgents(workspace: Workspace): WorkspaceAgent[] {

return agents
}

export const AgentMetadataEventSchema = z.object({
result: z.object({
collected_at: z.string(),
age: z.number(),
value: z.string(),
error: z.string(),
}),
description: z.object({
display_name: z.string(),
key: z.string(),
script: z.string(),
interval: z.number(),
timeout: z.number(),
}),
})

export const AgentMetadataEventSchemaArray = z.array(AgentMetadataEventSchema)

export type AgentMetadataEvent = z.infer<typeof AgentMetadataEventSchema>
8 changes: 4 additions & 4 deletionssrc/commands.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@ import * as vscode from "vscode"
import { extractAgents } from "./api-helper"
import { Remote } from "./remote"
import { Storage } from "./storage"
import {WorkspaceTreeItem } from "./workspacesProvider"
import {OpenableTreeItem } from "./workspacesProvider"

export class Commands {
public constructor(private readonly vscodeProposed: typeof vscode, private readonly storage: Storage) {}
Expand DownExpand Up@@ -118,7 +118,7 @@ export class Commands {
await vscode.commands.executeCommand("vscode.open", uri)
}

public async navigateToWorkspace(workspace:WorkspaceTreeItem) {
public async navigateToWorkspace(workspace:OpenableTreeItem) {
if (workspace) {
const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}`
await vscode.commands.executeCommand("vscode.open", uri)
Expand All@@ -130,7 +130,7 @@ export class Commands {
}
}

public async navigateToWorkspaceSettings(workspace:WorkspaceTreeItem) {
public async navigateToWorkspaceSettings(workspace:OpenableTreeItem) {
if (workspace) {
const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}/settings`
await vscode.commands.executeCommand("vscode.open", uri)
Expand All@@ -143,7 +143,7 @@ export class Commands {
}
}

public async openFromSidebar(treeItem:WorkspaceTreeItem) {
public async openFromSidebar(treeItem:OpenableTreeItem) {
if (treeItem) {
await openWorkspace(
treeItem.workspaceOwner,
Expand Down
5 changes: 2 additions & 3 deletionssrc/extension.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
"use strict"

import { getAuthenticatedUser } from "coder/site/src/api/api"
import * as module from "module"
import * as vscode from "vscode"
Expand All@@ -13,8 +12,8 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
const storage = new Storage(output, ctx.globalState, ctx.secrets, ctx.globalStorageUri, ctx.logUri)
await storage.init()

const myWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.Mine)
const allWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.All)
const myWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.Mine, storage)
const allWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.All, storage)

vscode.window.registerTreeDataProvider("myWorkspaces", myWorkspacesProvider)
vscode.window.registerTreeDataProvider("allWorkspaces", allWorkspacesProvider)
Expand Down
6 changes: 0 additions & 6 deletionssrc/remote.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -282,12 +282,6 @@ export class Remote {
"Coder-Session-Token": await this.storage.getSessionToken(),
},
})
eventSource.addEventListener("open", () => {
// TODO: Add debug output that we began watching here!
})
eventSource.addEventListener("error", () => {
// TODO: Add debug output that we got an error here!
})

const workspaceUpdatedStatus = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 999)
disposables.push(workspaceUpdatedStatus)
Expand Down
187 changes: 136 additions & 51 deletionssrc/workspacesProvider.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,178 @@
import { getWorkspaces } from "coder/site/src/api/api"
import { WorkspaceAgent } from "coder/site/src/api/typesGenerated"
import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
import EventSource from "eventsource"
import * as path from "path"
import * as vscode from "vscode"
import { extractAgents } from "./api-helper"
import { AgentMetadataEvent, AgentMetadataEventSchemaArray, extractAgents } from "./api-helper"
import { Storage } from "./storage"

export enum WorkspaceQuery {
Mine = "owner:me",
All = "",
}

export class WorkspaceProvider implements vscode.TreeDataProvider<WorkspaceTreeItem> {
constructor(private readonly getWorkspacesQuery: WorkspaceQuery) {}
export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
private workspaces: WorkspaceTreeItem[] = []
private agentMetadata: Record<WorkspaceAgent["id"], AgentMetadataEvent[]> = {}

private _onDidChangeTreeData: vscode.EventEmitter<WorkspaceTreeItem | undefined | null | void> =
new vscode.EventEmitter<WorkspaceTreeItem | undefined | null | void>()
readonly onDidChangeTreeData: vscode.Event<WorkspaceTreeItem | undefined | null | void> =
constructor(private readonly getWorkspacesQuery: WorkspaceQuery, private readonly storage: Storage) {
getWorkspaces({ q: this.getWorkspacesQuery })
.then((workspaces) => {
const workspacesTreeItem: WorkspaceTreeItem[] = []
workspaces.workspaces.forEach((workspace) => {
const showMetadata = this.getWorkspacesQuery === WorkspaceQuery.Mine
if (showMetadata) {
const agents = extractAgents(workspace)
agents.forEach((agent) => this.monitorMetadata(agent.id)) // monitor metadata for all agents
}
const treeItem = new WorkspaceTreeItem(
workspace,
this.getWorkspacesQuery === WorkspaceQuery.All,
showMetadata,
)
workspacesTreeItem.push(treeItem)
})
return workspacesTreeItem
})
.then((workspaces) => {
this.workspaces = workspaces
this.refresh()
})
}

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> =
this._onDidChangeTreeData.event

refresh(): void {
this._onDidChangeTreeData.fire()
refresh(item: vscode.TreeItem | undefined | null | void): void {
this._onDidChangeTreeData.fire(item)
}

getTreeItem(element:WorkspaceTreeItem): vscode.TreeItem {
asyncgetTreeItem(element:vscode.TreeItem):Promise<vscode.TreeItem> {
return element
}

getChildren(element?:WorkspaceTreeItem): Thenable<WorkspaceTreeItem[]> {
getChildren(element?:vscode.TreeItem): Thenable<vscode.TreeItem[]> {
if (element) {
if (element.agents.length > 0) {
return Promise.resolve(
element.agents.map((agent) => {
const label = agent.name
const detail = `Status: ${agent.status}`
return new WorkspaceTreeItem(label, detail, "", "", agent.name, agent.expanded_directory, [], "coderAgent")
}),
)
if (element instanceof WorkspaceTreeItem) {
const agents = extractAgents(element.workspace)
const agentTreeItems = agents.map((agent) => new AgentTreeItem(agent, element.watchMetadata))
return Promise.resolve(agentTreeItems)
} else if (element instanceof AgentTreeItem) {
const savedMetadata = this.agentMetadata[element.agent.id] || []
return Promise.resolve(savedMetadata.map((metadata) => new AgentMetadataTreeItem(metadata)))
}

return Promise.resolve([])
}
return getWorkspaces({ q: this.getWorkspacesQuery }).then((workspaces) => {
return workspaces.workspaces.map((workspace) => {
const status =
workspace.latest_build.status.substring(0, 1).toUpperCase() + workspace.latest_build.status.substring(1)

const label =
this.getWorkspacesQuery === WorkspaceQuery.All
? `${workspace.owner_name} / ${workspace.name}`
: workspace.name
const detail = `Template: ${workspace.template_display_name || workspace.template_name} • Status: ${status}`
const agents = extractAgents(workspace)
return new WorkspaceTreeItem(
label,
detail,
workspace.owner_name,
workspace.name,
undefined,
agents[0]?.expanded_directory,
agents,
agents.length > 1 ? "coderWorkspaceMultipleAgents" : "coderWorkspaceSingleAgent",
)
})
return Promise.resolve(this.workspaces)
}

async monitorMetadata(agentId: WorkspaceAgent["id"]): Promise<void> {
const agentMetadataURL = new URL(`${this.storage.getURL()}/api/v2/workspaceagents/${agentId}/watch-metadata`)
const agentMetadataEventSource = new EventSource(agentMetadataURL.toString(), {
headers: {
"Coder-Session-Token": await this.storage.getSessionToken(),
},
})

agentMetadataEventSource.addEventListener("data", (event) => {
try {
const dataEvent = JSON.parse(event.data)
const agentMetadata = AgentMetadataEventSchemaArray.parse(dataEvent)

if (agentMetadata.length === 0) {
agentMetadataEventSource.close()
}

const savedMetadata = this.agentMetadata[agentId]
if (JSON.stringify(savedMetadata) !== JSON.stringify(agentMetadata)) {
this.agentMetadata[agentId] = agentMetadata // overwrite existing metadata
this.refresh()
}
} catch (error) {
agentMetadataEventSource.close()
}
})
}
}

type CoderTreeItemType = "coderWorkspaceSingleAgent" | "coderWorkspaceMultipleAgents" | "coderAgent"

export class WorkspaceTreeItem extends vscode.TreeItem {
class AgentMetadataTreeItem extends vscode.TreeItem {
constructor(metadataEvent: AgentMetadataEvent) {
const label =
metadataEvent.description.display_name.trim() + ": " + metadataEvent.result.value.replace(/\n/g, "").trim()

super(label, vscode.TreeItemCollapsibleState.None)
this.tooltip = "Collected at " + metadataEvent.result.collected_at
this.contextValue = "coderAgentMetadata"
}
}

export class OpenableTreeItem extends vscode.TreeItem {
constructor(
public readonly label: string,
public readonly tooltip: string,
label: string,
tooltip: string,
collapsibleState: vscode.TreeItemCollapsibleState,

public readonly workspaceOwner: string,
public readonly workspaceName: string,
public readonly workspaceAgent: string | undefined,
public readonly workspaceFolderPath: string | undefined,
public readonly agents: WorkspaceAgent[],

contextValue: CoderTreeItemType,
) {
super(
label,
contextValue === "coderWorkspaceMultipleAgents"
? vscode.TreeItemCollapsibleState.Collapsed
: vscode.TreeItemCollapsibleState.None,
)
super(label, collapsibleState)
this.contextValue = contextValue
this.tooltip = tooltip
}

iconPath = {
light: path.join(__filename, "..", "..", "media", "logo.svg"),
dark: path.join(__filename, "..", "..", "media", "logo.svg"),
}
}

class AgentTreeItem extends OpenableTreeItem {
constructor(public readonly agent: WorkspaceAgent, watchMetadata = false) {
const label = agent.name
const detail = `Status: ${agent.status}`
super(
label,
detail,
watchMetadata ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None,
"",
"",
agent.name,
agent.expanded_directory,
"coderAgent",
)
}
}

export class WorkspaceTreeItem extends OpenableTreeItem {
constructor(
public readonly workspace: Workspace,
public readonly showOwner: boolean,
public readonly watchMetadata = false,
) {
const status =
workspace.latest_build.status.substring(0, 1).toUpperCase() + workspace.latest_build.status.substring(1)

const label = showOwner ? `${workspace.owner_name} / ${workspace.name}` : workspace.name
const detail = `Template: ${workspace.template_display_name || workspace.template_name} • Status: ${status}`
const agents = extractAgents(workspace)
super(
label,
detail,
showOwner ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.Expanded,
workspace.owner_name,
workspace.name,
undefined,
agents[0]?.expanded_directory,
"coderWorkspaceMultipleAgents",
)
}
}
5 changes: 5 additions & 0 deletionsyarn.lock
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5761,3 +5761,8 @@ yocto-queue@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==

zod@^3.21.4:
version "3.21.4"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db"
integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==

[8]ページ先頭

©2009-2025 Movatter.jp