init workflows view

Signed-off-by: Sanjula Ganepola <sanjulagane@gmail.com>
This commit is contained in:
Sanjula Ganepola
2024-09-26 20:06:17 -04:00
parent 1b1af97923
commit 003d2c39b4
10 changed files with 179 additions and 43 deletions

View File

@@ -1,14 +1,22 @@
import * as vscode from 'vscode';
import { window } from 'vscode';
import ComponentsTreeDataProvider from './views/components/componentsTreeDataProvider';
import { DecorationProvider } from './views/decorationProvider';
import WorkflowsTreeDataProvider from './views/workflows/workflowsTreeDataProvider';
export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "github-local-actions" is now active!');
const decorationProvider = new DecorationProvider();
const componentsTreeDataProvider = new ComponentsTreeDataProvider(context);
const componentsTreeView = window.createTreeView(ComponentsTreeDataProvider.VIEW_ID, { treeDataProvider: componentsTreeDataProvider });
const workflowsTreeDataProvider = new WorkflowsTreeDataProvider(context);
const workflowsTreeView = window.createTreeView(WorkflowsTreeDataProvider.VIEW_ID, { treeDataProvider: workflowsTreeDataProvider });
context.subscriptions.push(
componentsTreeView
componentsTreeView,
workflowsTreeView,
window.registerFileDecorationProvider(decorationProvider)
);
}

View File

@@ -9,4 +9,11 @@ export enum Status {
Enabled = 'Enabled',
Warning = 'Warning',
Disabled = 'Disabled'
}
export interface Workflow {
name: string,
path: string,
content?: any,
error?: string
}

View File

@@ -7,9 +7,8 @@ export default class ComponentTreeItem extends TreeItem implements GithubLocalAc
component: Component;
constructor(component: Component) {
super(component.name, TreeItemCollapsibleState.Collapsed);
super(component.name, TreeItemCollapsibleState.None);
this.component = component;
this.collapsibleState = TreeItemCollapsibleState.None;
this.contextValue = ComponentTreeItem.contextValue;
this.iconPath = new ThemeIcon(component.icon);
this.resourceUri = Uri.parse(`${ComponentTreeItem.contextValue}:${component.name}?status=${component.status}`, true);

View File

@@ -1,6 +1,5 @@
import { CancellationToken, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem, window } from "vscode";
import { CancellationToken, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem } from "vscode";
import { ComponentManager } from "../componentManager";
import { DecorationProvider } from "../decorationProvider";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import ComponentTreeItem from "./component";
@@ -12,11 +11,6 @@ export default class ComponentsTreeDataProvider implements TreeDataProvider<Gith
constructor(context: ExtensionContext) {
this.componentManager = new ComponentManager();
const decorationProvider = new DecorationProvider();
context.subscriptions.push(
window.registerFileDecorationProvider(decorationProvider),
);
}
refresh(element?: GithubLocalActionsTreeItem) {

View File

@@ -1,12 +1,14 @@
import { CancellationToken, Event, FileDecoration, FileDecorationProvider, ProviderResult, ThemeColor, Uri } from "vscode";
import { Status } from "../types";
import ComponentTreeItem from "./components/component";
import WorkflowTreeItem from "./workflows/workflow";
export class DecorationProvider implements FileDecorationProvider {
onDidChangeFileDecorations?: Event<Uri | Uri[] | undefined> | undefined;
provideFileDecoration(uri: Uri, token: CancellationToken): ProviderResult<FileDecoration> {
const params = new URLSearchParams(uri.query);
if (uri.scheme === ComponentTreeItem.contextValue) {
const params = new URLSearchParams(uri.query);
if (params.get('status') === Status.Enabled) {
return {
badge: '✅',
@@ -23,6 +25,14 @@ export class DecorationProvider implements FileDecorationProvider {
color: new ThemeColor('GitHubLocalActions.disabled')
};
}
} else if (uri.scheme === WorkflowTreeItem.contextValue) {
// TODO: Fix color
if (params.get('error')) {
return {
badge: '❌',
color: new ThemeColor('GitHubLocalActions.disabled')
};
}
}
}
}

View File

@@ -0,0 +1,36 @@
import * as fs from "fs/promises";
import * as path from "path";
import { workspace } from "vscode";
import * as yaml from "yaml";
import { Workflow } from "../types";
export class WorkflowManager {
async getWorkflows(): Promise<Workflow[]> {
const workflows: Workflow[] = [];
const workspaceFolders = workspace.workspaceFolders;
if (workspaceFolders && workspaceFolders.length > 0) {
const workflowFiles = await workspace.findFiles(`.github/workflows/*.{yml,yaml}`);
for await (const workflowFile of workflowFiles) {
try {
const fileContent = await fs.readFile(workflowFile.fsPath, 'utf8');
workflows.push({
name: path.parse(workflowFile.fsPath).name,
path: workflowFile.fsPath,
content: yaml.parse(fileContent)
});
} catch (error) {
workflows.push({
name: path.parse(workflowFile.fsPath).name,
path: workflowFile.fsPath,
error: 'Failed to parse workflow file'
});
}
}
}
return workflows;
}
}

View File

@@ -0,0 +1,25 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode";
import { Workflow } from "../../types";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
export default class WorkflowTreeItem extends TreeItem implements GithubLocalActionsTreeItem {
static contextValue = 'workflow';
workflow: Workflow;
constructor(workflow: Workflow) {
super(workflow.content.name || workflow.name, workflow.error ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed);
this.workflow = workflow;
this.contextValue = WorkflowTreeItem.contextValue;
this.iconPath = new ThemeIcon('layers');
this.tooltip = `Name: ${workflow.name}\n` +
`Path: ${workflow.path}`;
if(workflow.error) {
this.resourceUri = Uri.parse(`${WorkflowTreeItem.contextValue}:${workflow.name}?error=${workflow.error}`, true);
}
}
async getChildren(): Promise<GithubLocalActionsTreeItem[]> {
return [];
}
}

View File

@@ -0,0 +1,40 @@
import { CancellationToken, EventEmitter, ExtensionContext, TreeDataProvider, TreeItem } from "vscode";
import { GithubLocalActionsTreeItem } from "../githubLocalActionsTreeItem";
import { WorkflowManager } from "../workflowManager";
import WorkflowTreeItem from "./workflow";
export default class WorkflowsTreeDataProvider implements TreeDataProvider<GithubLocalActionsTreeItem> {
private _onDidChangeTreeData = new EventEmitter<GithubLocalActionsTreeItem | undefined | null | void>();
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
public static VIEW_ID = 'workflows';
private workflowManager: WorkflowManager;
constructor(context: ExtensionContext) {
this.workflowManager = new WorkflowManager();
}
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 workflows = await this.workflowManager.getWorkflows();
return workflows.map(workflow => new WorkflowTreeItem(workflow));
}
}
}