Basic functions create tag and create execution feature
This commit is contained in:
parent
b4e5fdcd20
commit
d57c1e9696
19 changed files with 564 additions and 4557 deletions
4636
package-lock.json
generated
4636
package-lock.json
generated
File diff suppressed because it is too large
Load diff
34
package.json
34
package.json
|
@ -30,7 +30,9 @@
|
|||
"onView:Users",
|
||||
"onView:Database",
|
||||
"onView:Health",
|
||||
"onCommand:vscode-appwrite.AddProject"
|
||||
"onView:Functions",
|
||||
"onCommand:vscode-appwrite.AddProject",
|
||||
"onCommand:vscode-appwrite.CreateTag"
|
||||
],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
|
@ -188,6 +190,16 @@
|
|||
"command": "vscode-appwrite.removeProject",
|
||||
"title": "Remove project",
|
||||
"icon": "$(trash)"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.CreateTag",
|
||||
"title": "Create function tag",
|
||||
"icon": "$(cloud-upload)"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.CreateExecution",
|
||||
"title": "Execute function",
|
||||
"icon": "$(play)"
|
||||
}
|
||||
],
|
||||
"views": {
|
||||
|
@ -211,6 +223,10 @@
|
|||
{
|
||||
"id": "Projects",
|
||||
"name": "Projects"
|
||||
},
|
||||
{
|
||||
"id": "Functions",
|
||||
"name": "Functions"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -383,6 +399,18 @@
|
|||
{
|
||||
"command": "vscode-appwrite.removeProject",
|
||||
"when": "viewItem =~ /(appwriteProject)/"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.CreateExecution",
|
||||
"when": "viewItem =~ /(function)/",
|
||||
"group": "inline"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
{
|
||||
"command": "vscode-appwrite.CreateTag",
|
||||
"when": "explorerResourceIsFolder == true",
|
||||
"group": "appwrite@1"
|
||||
}
|
||||
],
|
||||
"commandPalette": [
|
||||
|
@ -499,6 +527,7 @@
|
|||
"@types/glob": "^7.1.3",
|
||||
"@types/mocha": "^8.0.4",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/tar": "^4.0.4",
|
||||
"@types/vscode": "^1.55.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.14.1",
|
||||
"@typescript-eslint/parser": "^4.14.1",
|
||||
|
@ -515,6 +544,7 @@
|
|||
"dependencies": {
|
||||
"dayjs": "^1.10.4",
|
||||
"fs-extra": "^9.1.0",
|
||||
"node-appwrite": "^2.2.1"
|
||||
"node-appwrite": "^2.2.1",
|
||||
"tar": "^6.1.0"
|
||||
}
|
||||
}
|
||||
|
|
88
src/appwrite.d.ts
vendored
88
src/appwrite.d.ts
vendored
|
@ -1,3 +1,6 @@
|
|||
import { ReadStream } from 'fs';
|
||||
import { Stream } from 'node:stream';
|
||||
|
||||
export type Token = {
|
||||
/**
|
||||
* Token ID.
|
||||
|
@ -287,7 +290,7 @@ export type Rule = {
|
|||
list: string[];
|
||||
};
|
||||
|
||||
interface Permissions {
|
||||
export type Permissions = {
|
||||
read: string[];
|
||||
write: string[];
|
||||
}
|
||||
|
@ -361,6 +364,88 @@ export type StorageClient = {
|
|||
getFile: (fileId: string) => Promise<any>;
|
||||
};
|
||||
|
||||
type Vars = Record<string, any>;
|
||||
|
||||
export type Function = {
|
||||
'$id': string;
|
||||
'$permissions': Permissions;
|
||||
name: string;
|
||||
dateCreated: number;
|
||||
dateUpdated: number;
|
||||
status: string;
|
||||
env: string;
|
||||
tag: string;
|
||||
vars: Vars;
|
||||
events: string[];
|
||||
schedule: string;
|
||||
scheduleNext: number;
|
||||
schedulePrevious: number;
|
||||
timeout: number;
|
||||
}
|
||||
|
||||
export type FunctionsList = {
|
||||
sum: number;
|
||||
functions: Function[];
|
||||
}
|
||||
|
||||
export type Tag = {
|
||||
'$id': string;
|
||||
functionId: string;
|
||||
dateCreated: number;
|
||||
command: string;
|
||||
size: string;
|
||||
};
|
||||
|
||||
export type TagList = {
|
||||
sum: number;
|
||||
tags: Tag[];
|
||||
}
|
||||
|
||||
export type ExecutionStatus = "waiting" | "processing" | "completed" | "failed";
|
||||
|
||||
export type Execution = {
|
||||
'$id': string;
|
||||
functionId: string;
|
||||
dateCreated: number;
|
||||
trigger: string;
|
||||
status: ExecutionStatus;
|
||||
exitCode: number;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
time: number;
|
||||
};
|
||||
|
||||
export type ExecutionList = {
|
||||
sum: number;
|
||||
executions: Execution[];
|
||||
};
|
||||
|
||||
export type Search = {
|
||||
search?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
orderType?: 'ASC' | 'DESC';
|
||||
};
|
||||
|
||||
export type FunctionsClient = {
|
||||
create: (name: string, execute: string[], env: string, vars?: Vars, events?: string[], schedule?: string, timeout?: number) => Promise<any>;
|
||||
list: (search?: string, offset?: number, limit?: number, orderType?: 'ASC' | 'DESC') => Promise<any>;
|
||||
get: (functionId: string) => Promise<any>;
|
||||
update: (functionId: string, name: string, execute: string, vars: Vars, events: string[], schedule?: string, timeout?: number) => Promise<any>;
|
||||
updateTag: (functionId: string, tagId: string) => Promise<any>;
|
||||
delete: (functionId: string) => Promise<any>;
|
||||
createTag: (id: string, command: string, code: ReadStream) => Promise<any>;
|
||||
listTags: (id: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC') => Promise<any>;
|
||||
getTag: (functionId: string, tagId: string) => Promise<any>;
|
||||
deleteTag: (functionId: string, tagId: string) => Promise<any>;
|
||||
createExecution: (functionId: string, data?: string) => Promise<any>;
|
||||
listExecutions: (functionId: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC') => Promise<any>;
|
||||
getExecution: (functionId: string, executionId: string) => Promise<any>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export type SDK = {
|
||||
Client: new () => Client;
|
||||
|
||||
|
@ -368,4 +453,5 @@ export type SDK = {
|
|||
Health: new (client: Client) => HealthClient;
|
||||
Database: new (client: Client) => DatabaseClient;
|
||||
Storage: new (client: Client) => StorageClient;
|
||||
Functions: new (client: Client) => FunctionsClient;
|
||||
};
|
||||
|
|
52
src/appwrite/Functions.ts
Normal file
52
src/appwrite/Functions.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import { Client, Execution, ExecutionList, FunctionsClient, TagList, Vars } from "../appwrite";
|
||||
import { AppwriteSDK } from '../constants';
|
||||
import AppwriteCall from '../utils/AppwriteCall';
|
||||
import { ReadStream } from 'node:fs';
|
||||
|
||||
export class Functions {
|
||||
private readonly functions: FunctionsClient;
|
||||
|
||||
constructor(client: Client) {
|
||||
this.functions = new AppwriteSDK.Functions(client);
|
||||
}
|
||||
|
||||
public async create(name: string, execute: string[], env: string, vars?: Vars, events?: string[], schedule?: string, timeout?: number): Promise<any> {
|
||||
return await AppwriteCall(this.functions.create(name, execute, env, vars, events, schedule, timeout));
|
||||
}
|
||||
public async list(search?: string, offset?: number, limit?: number, orderType?: 'ASC' | 'DESC'): Promise<any> {
|
||||
return await AppwriteCall(this.functions.list(search, offset, limit, orderType));
|
||||
}
|
||||
public async get(functionId: string): Promise<any> {
|
||||
return await AppwriteCall(this.functions.get(functionId));
|
||||
}
|
||||
public async update(functionId: string, name: string, execute: string, vars: Vars, events: string[], schedule?: string, timeout?: number): Promise<any> {
|
||||
return await AppwriteCall(this.functions.update(functionId, name, execute, vars, events, schedule, timeout));
|
||||
}
|
||||
public async updateTag(functionId: string, tagId: string): Promise<any> {
|
||||
return await AppwriteCall(this.functions.updateTag(functionId, tagId));
|
||||
}
|
||||
public async delete(functionId: string): Promise<void> {
|
||||
return await AppwriteCall(this.functions.delete(functionId));
|
||||
}
|
||||
public async createTag(functionId: string, command: string, code: ReadStream): Promise<any> {
|
||||
return await AppwriteCall(this.functions.createTag(functionId, command, code));
|
||||
}
|
||||
public async listTags(id: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC'): Promise<TagList | undefined> {
|
||||
return await AppwriteCall<TagList>(this.functions.listTags(id, search, offset, limit, orderType));
|
||||
}
|
||||
public async getTag(functionId: string, tagId: string): Promise<any> {
|
||||
return await AppwriteCall(this.functions.getTag(functionId, tagId));
|
||||
}
|
||||
public async deleteTag(functionId: string, tagId: string): Promise<void> {
|
||||
return await AppwriteCall(this.functions.deleteTag(functionId, tagId));
|
||||
}
|
||||
public async createExecution(functionId: string, data?: string): Promise<any> {
|
||||
return await AppwriteCall(this.functions.createExecution(functionId, data));
|
||||
}
|
||||
public async listExecutions(functionId: string, search?: string, limit?: number, offset?: number, orderType?: 'ASC' | 'DESC'): Promise<ExecutionList | undefined> {
|
||||
return await AppwriteCall(this.functions.listExecutions(functionId, search, offset, limit, orderType));
|
||||
}
|
||||
public async getExecution(functionId: string, executionId: string): Promise<Execution | undefined> {
|
||||
return await AppwriteCall(this.functions.getExecution(functionId, executionId));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import { Client } from "./appwrite";
|
||||
import { Database } from "./appwrite/Database";
|
||||
import { Functions } from './appwrite/Functions';
|
||||
import { Health } from "./appwrite/Health";
|
||||
import { Storage } from "./appwrite/Storage";
|
||||
import { Users } from "./appwrite/Users";
|
||||
|
@ -12,6 +13,8 @@ export let usersClient: Users | undefined;
|
|||
export let healthClient: Health | undefined;
|
||||
export let databaseClient: Database | undefined;
|
||||
export let storageClient: Storage | undefined;
|
||||
export let functionsClient: Functions | undefined;
|
||||
|
||||
|
||||
function initAppwriteClient({ endpoint, projectId, secret, selfSigned }: AppwriteProjectConfiguration) {
|
||||
client = new AppwriteSDK.Client();
|
||||
|
@ -22,6 +25,7 @@ function initAppwriteClient({ endpoint, projectId, secret, selfSigned }: Appwrit
|
|||
healthClient = new Health(client);
|
||||
databaseClient = new Database(client);
|
||||
storageClient = new Storage(client);
|
||||
functionsClient = new Functions(client);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
@ -36,4 +40,5 @@ export function createAppwriteClient(config?: AppwriteProjectConfiguration): voi
|
|||
healthClient = undefined;
|
||||
databaseClient = undefined;
|
||||
storageClient = undefined;
|
||||
functionsClient = undefined;
|
||||
}
|
||||
|
|
10
src/commands/functions/createExecution.ts
Normal file
10
src/commands/functions/createExecution.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { functionsClient } from '../../client';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { FunctionTreeItem } from '../../tree/functions/FunctionTreeItem';
|
||||
|
||||
export async function createExecution(functionTreeItem: FunctionTreeItem): Promise<void> {
|
||||
const func = functionTreeItem.func;
|
||||
ext.outputChannel.appendLog(`Creating execution for function ${func.name}`);
|
||||
|
||||
await functionsClient?.createExecution(func.$id);
|
||||
}
|
14
src/commands/functions/createTag.ts
Normal file
14
src/commands/functions/createTag.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Uri } from 'vscode';
|
||||
import { functionsClient } from '../../client';
|
||||
import { getTarReadStream } from '../../utils/tar';
|
||||
import { ext } from '../../extensionVariables';
|
||||
export async function createTag(folder: Uri): Promise<void> {
|
||||
const buffer = await getTarReadStream(folder);
|
||||
if (buffer !== undefined) {
|
||||
try {
|
||||
await functionsClient?.createTag('60b1836a8e5d9', "python hello.py", buffer);
|
||||
} catch (e) {
|
||||
ext.outputChannel.appendLog("Creating tag error: " + e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ import { viewUserPrefs } from "./users/viewUserPrefs";
|
|||
import { editPermission } from "./database/permissions/editPermission";
|
||||
import { setActiveProject } from "./project/setActiveProject";
|
||||
import { removeProject } from "./project/removeProject";
|
||||
import { createTag } from './functions/createTag';
|
||||
import { createExecution } from './functions/createExecution';
|
||||
|
||||
class CommandRegistrar {
|
||||
constructor(private readonly context: ExtensionContext) {}
|
||||
|
@ -98,4 +100,8 @@ export function registerCommands(context: ExtensionContext): void {
|
|||
registerCommand("setActiveProject", setActiveProject, "all");
|
||||
registerCommand("refreshProjects", undefined, "projects");
|
||||
registerCommand("removeProject", removeProject, "all");
|
||||
|
||||
/** Functions **/
|
||||
registerCommand("CreateTag", createTag, "functions");
|
||||
registerCommand("CreateExecution", createExecution, "functions");
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { registerCommands } from "./commands/registerCommands";
|
|||
import { ext } from "./extensionVariables";
|
||||
import { getActiveProjectConfiguration } from "./settings";
|
||||
import { DatabaseTreeItemProvider } from "./tree/database/DatabaseTreeItemProvider";
|
||||
import { FunctionsTreeItemProvider } from './tree/functions/FunctionsTreeItemProvider';
|
||||
import { HealthTreeItemProvider } from "./tree/health/HealthTreeItemProvider";
|
||||
import { ProjectsTreeItemProvider } from "./tree/projects/ProjectsTreeItemProvider";
|
||||
import { StorageTreeItemProvider } from "./tree/storage/StorageTreeItemProvider";
|
||||
|
@ -16,12 +17,14 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
|||
const databaseTreeItemProvider = new DatabaseTreeItemProvider();
|
||||
const storageTreeItemProvider = new StorageTreeItemProvider();
|
||||
const projectsTreeItemProvider = new ProjectsTreeItemProvider();
|
||||
const functionsTreeItemProvider = new FunctionsTreeItemProvider();
|
||||
|
||||
vscode.window.registerTreeDataProvider("Users", userTreeItemProvider);
|
||||
vscode.window.registerTreeDataProvider("Health", healthTreeItemProvider);
|
||||
vscode.window.registerTreeDataProvider("Database", databaseTreeItemProvider);
|
||||
vscode.window.registerTreeDataProvider("Storage", storageTreeItemProvider);
|
||||
vscode.window.registerTreeDataProvider("Projects", projectsTreeItemProvider);
|
||||
vscode.window.registerTreeDataProvider("Functions", functionsTreeItemProvider);
|
||||
|
||||
const activeProject = await getActiveProjectConfiguration();
|
||||
createAppwriteClient(activeProject);
|
||||
|
@ -35,6 +38,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
|||
database: databaseTreeItemProvider,
|
||||
storage: storageTreeItemProvider,
|
||||
projects: projectsTreeItemProvider,
|
||||
functions: functionsTreeItemProvider
|
||||
};
|
||||
|
||||
registerCommands(context);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ExtensionContext } from "vscode";
|
||||
import { DatabaseTreeItemProvider } from './tree/database/DatabaseTreeItemProvider';
|
||||
import { FunctionsTreeItemProvider } from './tree/functions/FunctionsTreeItemProvider';
|
||||
import { HealthTreeItemProvider } from './tree/health/HealthTreeItemProvider';
|
||||
import { ProjectsTreeItemProvider } from './tree/projects/ProjectsTreeItemProvider';
|
||||
import { StorageTreeItemProvider } from './tree/storage/StorageTreeItemProvider';
|
||||
|
@ -12,12 +13,13 @@ export type AppwriteTree = {
|
|||
database?: DatabaseTreeItemProvider;
|
||||
storage?: StorageTreeItemProvider;
|
||||
projects?: ProjectsTreeItemProvider;
|
||||
functions?: FunctionsTreeItemProvider;
|
||||
};
|
||||
|
||||
export type Ext = {
|
||||
context?: ExtensionContext;
|
||||
outputChannel?: AppwriteOutputChannel;
|
||||
outputChannel: AppwriteOutputChannel;
|
||||
tree?: AppwriteTree;
|
||||
};
|
||||
|
||||
export const ext: Ext = {};
|
||||
export const ext: Ext = {} as Ext;
|
||||
|
|
|
@ -41,11 +41,11 @@ export class DatabaseTreeItemProvider implements vscode.TreeDataProvider<vscode.
|
|||
|
||||
const collectionsList = await AppwriteCall<CollectionsList, CollectionsList>(databaseSdk.listCollections());
|
||||
if (collectionsList) {
|
||||
const userTreeItems = collectionsList.collections.map((collection: Collection) => new CollectionTreeItem(collection, this)) ?? [];
|
||||
const collectionTreeItems = collectionsList.collections.map((collection: Collection) => new CollectionTreeItem(collection, this)) ?? [];
|
||||
const headerItem: vscode.TreeItem = {
|
||||
label: `Total collections: ${collectionsList.sum}`,
|
||||
};
|
||||
return [headerItem, ...userTreeItems];
|
||||
return [headerItem, ...collectionTreeItems];
|
||||
}
|
||||
|
||||
return [{ label: "No collections found" }];
|
||||
|
|
73
src/tree/functions/ExecutionTreeItem.ts
Normal file
73
src/tree/functions/ExecutionTreeItem.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
import dayjs = require('dayjs');
|
||||
import { MarkdownString, ThemeColor, ThemeIcon, TreeItem } from "vscode";
|
||||
import { Execution, ExecutionStatus } from "../../appwrite";
|
||||
import { functionsClient } from "../../client";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { ExecutionsTreeItem } from "./ExecutionsTreeItem";
|
||||
|
||||
const executionStatusIcons: Record<ExecutionStatus, ThemeIcon> = {
|
||||
processing: new ThemeIcon("loading"),
|
||||
waiting: new ThemeIcon("circle-outline"),
|
||||
completed: new ThemeIcon("circle-filled", new ThemeColor("testing.iconPassed")),
|
||||
failed: new ThemeIcon("circle-filled", new ThemeColor("testing.iconFailed")),
|
||||
};
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
export class ExecutionTreeItem extends TreeItem {
|
||||
public isAutoRefreshing: boolean = false;
|
||||
private refreshCount: number = 0;
|
||||
|
||||
constructor(public readonly parent: ExecutionsTreeItem, private readonly execution: Execution) {
|
||||
super(execution.$id);
|
||||
this.label = this.getLabel(execution);
|
||||
this.iconPath = executionStatusIcons[execution.status];
|
||||
const md = `Id: ${execution.$id} \nCreated: ${this.getCreated(execution)} \nTrigger: ${execution.trigger}`;
|
||||
this.tooltip = new MarkdownString(md);
|
||||
this.description = execution.trigger;
|
||||
this.isAutoRefreshing = execution.status === "processing" || execution.status === "waiting";
|
||||
this.autoRefresh();
|
||||
}
|
||||
|
||||
async autoRefresh(): Promise<void> {
|
||||
if (!this.isAutoRefreshing) {
|
||||
return;
|
||||
}
|
||||
this.refreshCount++;
|
||||
ext.outputChannel.appendLog("Refreshing execution.");
|
||||
const execution = await functionsClient?.getExecution(this.parent.parent.func.$id, this.execution.$id);
|
||||
|
||||
if (!execution) {
|
||||
ext.outputChannel.appendLog("Execution is undefined");
|
||||
this.isAutoRefreshing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.iconPath = executionStatusIcons[execution.status];
|
||||
this.label = this.getLabel(execution);
|
||||
this.isAutoRefreshing = execution.status === "processing" || execution.status === "waiting";
|
||||
|
||||
ext.tree?.functions?.refreshChild(this);
|
||||
await sleep(1000);
|
||||
this.autoRefresh();
|
||||
}
|
||||
|
||||
getLabel(execution: Execution): string {
|
||||
if (execution.status === "completed") {
|
||||
return `${this.getCreated(execution)} (${execution.time.toPrecision(2)}s)`;
|
||||
}
|
||||
return `${this.getCreated(execution)} (${execution.status})`;
|
||||
}
|
||||
|
||||
getCreated(execution: Execution): string {
|
||||
return dayjs(execution.dateCreated).format("LTS");
|
||||
}
|
||||
|
||||
|
||||
|
||||
contextValue = "tag";
|
||||
}
|
27
src/tree/functions/ExecutionsTreeItem.ts
Normal file
27
src/tree/functions/ExecutionsTreeItem.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { Execution, ExecutionList } from '../../appwrite';
|
||||
import { functionsClient } from "../../client";
|
||||
import { AppwriteTreeItemBase } from '../../ui/AppwriteTreeItemBase';
|
||||
import { ExecutionTreeItem } from './ExecutionTreeItem';
|
||||
import { FunctionTreeItem } from './FunctionTreeItem';
|
||||
|
||||
export class ExecutionsTreeItem extends AppwriteTreeItemBase<FunctionTreeItem> {
|
||||
constructor(public readonly parent: FunctionTreeItem) {
|
||||
super(parent, "Executions");
|
||||
}
|
||||
|
||||
public async getChildren(): Promise<TreeItem[]> {
|
||||
if (!functionsClient) {
|
||||
return [];
|
||||
}
|
||||
const executions: ExecutionList | undefined = await functionsClient.listExecutions(this.parent.func.$id, undefined, undefined, undefined, 'DESC');
|
||||
const children = executions?.executions.map((execution: Execution) => new ExecutionTreeItem(this, execution)) ?? [new TreeItem('No exeuctions.')];
|
||||
return children;
|
||||
}
|
||||
|
||||
collapsibleState = TreeItemCollapsibleState.Collapsed;
|
||||
|
||||
contextValue = "executions";
|
||||
|
||||
iconPath = new ThemeIcon("history");
|
||||
}
|
26
src/tree/functions/FunctionTreeItem.ts
Normal file
26
src/tree/functions/FunctionTreeItem.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { Function } from "../../appwrite";
|
||||
import { AppwriteTreeItemBase } from "../../ui/AppwriteTreeItemBase";
|
||||
import { ExecutionsTreeItem } from './ExecutionsTreeItem';
|
||||
import { FunctionsTreeItemProvider } from './FunctionsTreeItemProvider';
|
||||
import { TagsTreeItem } from './TagsTreeItem';
|
||||
|
||||
export class FunctionTreeItem extends AppwriteTreeItemBase {
|
||||
constructor(public func: Function, public readonly provider: FunctionsTreeItemProvider) {
|
||||
super(undefined, func.name);
|
||||
}
|
||||
|
||||
public async getChildren(): Promise<TreeItem[]> {
|
||||
return [new TagsTreeItem(this), new ExecutionsTreeItem(this)];
|
||||
}
|
||||
|
||||
public async refresh(): Promise<void> {
|
||||
this.provider.refreshChild(this);
|
||||
}
|
||||
|
||||
collapsibleState = TreeItemCollapsibleState.Collapsed;
|
||||
|
||||
contextValue = "function";
|
||||
|
||||
iconPath = new ThemeIcon("symbol-event");
|
||||
}
|
55
src/tree/functions/FunctionsTreeItemProvider.ts
Normal file
55
src/tree/functions/FunctionsTreeItemProvider.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import * as vscode from "vscode";
|
||||
import { client } from "../../client";
|
||||
import { Function, FunctionsList } from "../../appwrite";
|
||||
import { AppwriteSDK } from "../../constants";
|
||||
import { AppwriteTreeItemBase } from "../../ui/AppwriteTreeItemBase";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { EventEmitter, TreeItem } from "vscode";
|
||||
import { FunctionTreeItem } from "./FunctionTreeItem";
|
||||
|
||||
export class FunctionsTreeItemProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
|
||||
private _onDidChangeTreeData: EventEmitter<TreeItem | undefined | void> = new EventEmitter<TreeItem | undefined | void>();
|
||||
|
||||
readonly onDidChangeTreeData: vscode.Event<vscode.TreeItem | undefined | void> = this._onDidChangeTreeData.event;
|
||||
|
||||
refresh(): void {
|
||||
ext.outputChannel?.appendLine("Refreshing functions tree provider...");
|
||||
this._onDidChangeTreeData.fire();
|
||||
}
|
||||
|
||||
refreshChild(child: vscode.TreeItem): void {
|
||||
this._onDidChangeTreeData.fire(child);
|
||||
}
|
||||
|
||||
getTreeItem(element: vscode.TreeItem): vscode.TreeItem {
|
||||
return element;
|
||||
}
|
||||
|
||||
async getChildren(parent?: AppwriteTreeItemBase | TreeItem): Promise<vscode.TreeItem[]> {
|
||||
if (client === undefined) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
if (parent === undefined) {
|
||||
const functionsSdk = new AppwriteSDK.Functions(client);
|
||||
|
||||
const list: FunctionsList = await functionsSdk.list();
|
||||
|
||||
if (list) {
|
||||
const functionTreeItems = list.functions.map((func: Function) => new FunctionTreeItem(func, this)) ?? [];
|
||||
const headerItem: vscode.TreeItem = {
|
||||
label: `Total functions: ${list.sum}`,
|
||||
};
|
||||
return [headerItem, ...functionTreeItems];
|
||||
}
|
||||
|
||||
return [{ label: "No functions found" }];
|
||||
}
|
||||
|
||||
if (parent instanceof AppwriteTreeItemBase) {
|
||||
return parent.getChildren?.() ?? [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
16
src/tree/functions/TagTreeItem.ts
Normal file
16
src/tree/functions/TagTreeItem.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { ThemeIcon, TreeItem } from "vscode";
|
||||
import { Tag } from '../../appwrite';
|
||||
import { TagsTreeItem } from './TagsTreeItem';
|
||||
|
||||
export class TagTreeItem extends TreeItem {
|
||||
|
||||
constructor(public readonly parent: TagsTreeItem, tag: Tag) {
|
||||
super(tag.$id);
|
||||
const func = parent.parent.func;
|
||||
const active = func.tag === tag.$id;
|
||||
this.label = `${tag.$id}${active ? ' (Active)' : ''}`;
|
||||
this.iconPath = new ThemeIcon(active ? 'circle-filled' : 'circle-outline');
|
||||
}
|
||||
|
||||
contextValue = "tag";
|
||||
}
|
25
src/tree/functions/TagsTreeItem.ts
Normal file
25
src/tree/functions/TagsTreeItem.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { functionsClient } from "../../client";
|
||||
import { AppwriteTreeItemBase } from '../../ui/AppwriteTreeItemBase';
|
||||
import { FunctionTreeItem } from './FunctionTreeItem';
|
||||
import { TagTreeItem } from './TagTreeItem';
|
||||
|
||||
export class TagsTreeItem extends AppwriteTreeItemBase<FunctionTreeItem> {
|
||||
constructor(public readonly parent: FunctionTreeItem) {
|
||||
super(parent, "Tags");
|
||||
}
|
||||
|
||||
public async getChildren(): Promise<TreeItem[]> {
|
||||
if (!functionsClient) {
|
||||
return [];
|
||||
}
|
||||
const tags = await functionsClient.listTags(this.parent.func.$id);
|
||||
return tags?.tags.sort((a, b) => b.dateCreated - a.dateCreated).map((tag) => new TagTreeItem(this, tag)) ?? [new TreeItem('No tags.')];
|
||||
}
|
||||
|
||||
collapsibleState = TreeItemCollapsibleState.Collapsed;
|
||||
|
||||
contextValue = "tags";
|
||||
|
||||
iconPath = new ThemeIcon("tag");
|
||||
}
|
|
@ -10,7 +10,7 @@ export default function AppwriteCall<T, R = T>(
|
|||
): Promise<R | undefined> {
|
||||
return promise.then(
|
||||
(successResp) => {
|
||||
ext.outputChannel?.appendLog("Appwrite call success");
|
||||
ext.outputChannel?.appendLog(`Appwrite call success:`);
|
||||
if (onSuccess) {
|
||||
return onSuccess((successResp as unknown) as T);
|
||||
}
|
||||
|
|
38
src/utils/tar.ts
Normal file
38
src/utils/tar.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import tar = require("tar");
|
||||
import { Uri, window, workspace } from "vscode";
|
||||
import { ext } from "../extensionVariables";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
import * as fs from "fs";
|
||||
import { ReadStream } from 'node:fs';
|
||||
|
||||
export async function getTarReadStream(folder: Uri): Promise<ReadStream | undefined> {
|
||||
try {
|
||||
const folderName = path.basename(folder.path);
|
||||
|
||||
const tarName = `${folderName}.tar.gz`;
|
||||
const cwd = folder.fsPath;
|
||||
if (cwd === undefined) {
|
||||
window.showErrorMessage("No workspace open.");
|
||||
return;
|
||||
}
|
||||
ext.outputChannel.appendLog(`Creating '${tarName}' in '${workspace.workspaceFolders?.[0].uri.fsPath}'...`);
|
||||
|
||||
const tarFilePath = path.join(os.tmpdir(), tarName);
|
||||
|
||||
tar.create({ gzip: true, cwd: cwd }, [path.relative(cwd, folder.fsPath)]).pipe(fs.createWriteStream(tarFilePath, { emitClose: true}));
|
||||
|
||||
const stream = fs.createReadStream(tarFilePath);
|
||||
stream.on('close', () => {
|
||||
try {
|
||||
fs.unlinkSync(tarFilePath);
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
});
|
||||
return stream;
|
||||
|
||||
} catch (e) {
|
||||
ext.outputChannel?.appendLog("Error creating tar.gz: " + e);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue