Add history view, rework to use history status, remove old classes

Signed-off-by: Sanjula Ganepola <sanjulagane@gmail.com>
This commit is contained in:
Sanjula Ganepola
2024-10-17 19:38:47 -04:00
parent 05caeafbb2
commit 0e6baaaad1
13 changed files with 368 additions and 218 deletions

View File

@@ -0,0 +1,46 @@
import { ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
import { History, HistoryStatus } from "../../act";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class HistoryTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.history';
history: History;
constructor(history: History) {
super(history.name, TreeItemCollapsibleState.None);
this.history = history;
let totalDuration: string | undefined;
if (history.start) {
const start = new Date(history.start).getTime();
const end = history.end ? new Date(history.end).getTime() : new Date().getTime();
totalDuration = `${((end - start) / 1000).toFixed(0).toString()}s`;
this.description = totalDuration;
}
this.contextValue = `${HistoryTreeItem.contextValue}_${history.status}`;
switch (history.status) {
case HistoryStatus.Running:
this.iconPath = new ThemeIcon('loading~spin');
break;
case HistoryStatus.Success:
this.iconPath = new ThemeIcon('pass', new ThemeColor('GitHubLocalActions.green'));
break;
case HistoryStatus.Failed:
this.iconPath = new ThemeIcon('error', new ThemeColor('GitHubLocalActions.red'));
break;
case HistoryStatus.Cancelled:
this.iconPath = new ThemeIcon('circle-slash', new ThemeColor('GitHubLocalActions.yellow'));
break;
}
this.tooltip = `Name: ${history.name}\n` +
`Status: ${history.status}\n` +
`Started: ${history.start ? history.start : 'N/A'}\n` +
`Ended: ${history.end ? history.end : 'N/A'}\n` +
(totalDuration ? `Total Duration: ${totalDuration}\n` : ``);
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
return [];
}
}

View File

@@ -0,0 +1,59 @@
import { CancellationToken, commands, EventEmitter, ExtensionContext, extensions, TreeDataProvider, TreeItem, workspace } from "vscode";
import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import HistoryTreeItem from "./history";
export default class HistoryTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> {
private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>();
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
static VIEW_ID = 'history';
constructor(context: ExtensionContext) {
extensions.onDidChange(e => {
this.refresh();
});
context.subscriptions.push(
commands.registerCommand('githubLocalActions.refreshHistory', async () => {
this.refresh();
})
);
}
refresh(element?: GithubLocalActionsTreeItem) {
this._onDidChangeTreeData.fire(element);
}
getTreeItem(element: GithubLocalActionsTreeItem): GithubLocalActionsTreeItem | Thenable<GithubLocalActionsTreeItem> {
return element;
}
async resolveTreeItem(item: TreeItem, element: GithubLocalActionsTreeItem, token: CancellationToken): Promise<GithubLocalActionsTreeItem> {
if (element.getToolTip) {
element.tooltip = await element.getToolTip();
}
return element;
}
async getChildren(element?: GithubLocalActionsTreeItem): Promise<GithubLocalActionsTreeItem[]> {
if (element) {
return element.getChildren();
} else {
const items: GithubLocalActionsTreeItem[] = [];
const workspaceFolders = workspace.workspaceFolders;
if (workspaceFolders && workspaceFolders.length > 0) {
const workspaceHistory = act.workspaceHistory[workspaceFolders[0].uri.fsPath]; //TODO: Fix for multi workspace support
if (workspaceHistory) {
for (const history of workspaceHistory) {
items.push(new HistoryTreeItem(history));
}
}
}
await commands.executeCommand('setContext', 'githubLocalActions:noHistory', items.length == 0);
return items;
}
}
}

View File

@@ -1,4 +1,5 @@
import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem } from "vscode";
import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import ContainerEnginesTreeItem from "./containerEngines";
import EnvironmentsTreeItem from "./environments";
@@ -40,14 +41,22 @@ export default class SettingsTreeDataProvider implements TreeDataProvider<Github
if (element) {
return element.getChildren();
} else {
return [
new EnvironmentsTreeItem(),
new SecretsTreeItem(),
new VariablesTreeItem(),
new InputsTreeItem(),
new RunnersTreeItem(),
new ContainerEnginesTreeItem()
];
const items: GithubLocalActionsTreeItem[] = [];
const workflows = await act.workflowsManager.getWorkflows();
if (workflows.length > 0) {
items.push(...[
new EnvironmentsTreeItem(),
new SecretsTreeItem(),
new VariablesTreeItem(),
new InputsTreeItem(),
new RunnersTreeItem(),
new ContainerEnginesTreeItem()
]);
}
await commands.executeCommand('setContext', 'githubLocalActions:noSettings', items.length == 0);
return items;
}
}
}

View File

@@ -0,0 +1,23 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
import { Job, Workflow } from "../../workflowsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class JobTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.job';
job: Job;
workflow: Workflow;
constructor(workflow: Workflow, job: Job) {
super(job.name, TreeItemCollapsibleState.None);
this.workflow = workflow;
this.job = job;
this.contextValue = JobTreeItem.contextValue;
this.iconPath = new ThemeIcon('rocket');
this.tooltip = `Name: ${job.name}` +
`ID: ${job.id}`;
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
return [];
}
}

View File

@@ -1,30 +0,0 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
import { JobLog } from "../../act";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import StepTreeItem from "./stepLog";
export default class JobLogTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.jobLog';
jobLog: JobLog;
constructor(jobLog: JobLog) {
super(jobLog.name, TreeItemCollapsibleState.Collapsed);
this.jobLog = jobLog;
this.contextValue = JobLogTreeItem.contextValue;
this.iconPath = new ThemeIcon('pass-filled');
// this.tooltip = `Name: ${workflow.name}\n` +
// `Path: ${workflow.uri.fsPath}\n` +
// (workflow.error ? `Error: ${workflow.error}` : ``);
// TODO: Add tooltip and resourceUri
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const stepLogs = this.jobLog.stepLogs;
if (stepLogs) {
return this.jobLog.stepLogs.map(step => new StepTreeItem(step));
} else {
return [];
}
}
}

View File

@@ -1,24 +0,0 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
import { StepLog } from "../../act";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class StepLogTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.stepLog';
stepLog: StepLog;
constructor(stepLog: StepLog) {
super(stepLog.name, TreeItemCollapsibleState.None);
this.stepLog = stepLog;
this.contextValue = StepLogTreeItem.contextValue;
this.iconPath = new ThemeIcon('pass-filled');
// this.tooltip = `Name: ${workflow.name}\n` +
// `Path: ${workflow.uri.fsPath}\n` +
// (workflow.error ? `Error: ${workflow.error}` : ``);
// TODO: Add tooltip and resourceUri
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
return [];
}
}

View File

@@ -1,8 +1,7 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode";
import { act } from "../../extension";
import { Workflow } from "../../workflowsManager";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import WorkflowLogTreeItem from "./workflowLog";
import JobTreeItem from "./job";
export default class WorkflowTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.workflow';
@@ -23,11 +22,15 @@ export default class WorkflowTreeItem extends TreeItem implements GithubLocalAct
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
const workflowLogs = act.workflowLogs[this.workflow.uri.fsPath];
if (workflowLogs) {
return workflowLogs.map(workflowLog => new WorkflowLogTreeItem(workflowLog));
} else {
return [];
const items: GithubLocalActionsTreeItem[] = [];
const jobs = this.workflow.yaml.jobs;
if (jobs) {
for (const [key, value] of Object.entries<any>(jobs)) {
items.push(new JobTreeItem(this.workflow, { name: value.name ? value.name : key, id: key }));
}
}
return items;
}
}

View File

@@ -1,25 +0,0 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
import { WorkflowLog } from "../../act";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import JobLogTreeItem from "./jobLog";
export default class WorkflowLogTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'githubLocalActions.workflowLog';
workflowLog: WorkflowLog;
constructor(workflowLog: WorkflowLog) {
super(workflowLog.name, TreeItemCollapsibleState.Collapsed);
this.workflowLog = workflowLog;
this.contextValue = WorkflowLogTreeItem.contextValue;
this.iconPath = new ThemeIcon('pass-filled');
// this.tooltip = `Name: ${workflow.name}\n` +
// `Path: ${workflow.uri.fsPath}\n` +
// (workflow.error ? `Error: ${workflow.error}` : ``);
// TODO: Add tooltip and resourceUri
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
return this.workflowLog.jobLogs.map(jobLog => new JobLogTreeItem(jobLog));
}
}

View File

@@ -1,5 +1,5 @@
import { CancellationToken, commands, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem, window, workspace } from "vscode";
import { EventTrigger } from "../../act";
import { Event } from "../../act";
import { act } from "../../extension";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import WorkflowTreeItem from "./workflow";
@@ -15,13 +15,14 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider<Githu
await act.runAllWorkflows();
}),
commands.registerCommand('githubLocalActions.runEvent', async () => {
const event = await window.showQuickPick(Object.values(EventTrigger), {
const event = await window.showQuickPick(Object.values(Event), {
title: 'Select the event to run',
placeHolder: 'Event'
});
if(event) {
await act.runEvent(event as EventTrigger);
if (event) {
// TODO: Implement running event
// await act.runEvent(event as Event);
}
}),
commands.registerCommand('githubLocalActions.refreshWorkflows', async () => {
@@ -33,6 +34,10 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider<Githu
}),
commands.registerCommand('githubLocalActions.runWorkflow', async (workflowTreeItem: WorkflowTreeItem) => {
await act.runWorkflow(workflowTreeItem.workflow);
}),
commands.registerCommand('githubLocalActions.runJob', async (workflowTreeItem: WorkflowTreeItem) => {
// TODO: Implement running job
// await act.runJob()
})
);
}
@@ -57,8 +62,15 @@ export default class WorkflowsTreeDataProvider implements TreeDataProvider<Githu
if (element) {
return element.getChildren();
} else {
const items: GithubLocalActionsTreeItem[] = [];
const workflows = await act.workflowsManager.getWorkflows();
return workflows.map(workflow => new WorkflowTreeItem(workflow));
for (const workflow of workflows) {
items.push(new WorkflowTreeItem(workflow));
}
await commands.executeCommand('setContext', 'githubLocalActions:noWorkflows', items.length == 0);
return items;
}
}
}