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…
	
	Add table
		
		Reference in a new issue