Compare commits
16 commits
alex/fixDe
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
8b286657b0 | ||
|
6a2fbb956b | ||
|
f9d42ad703 | ||
|
e76dbc9e89 | ||
|
883893aaab | ||
|
47c405a9f5 | ||
|
2e77f93759 | ||
|
98a132fdef | ||
|
704bd72420 | ||
|
60a510b646 | ||
|
6bcbf57143 | ||
|
ac466375e5 | ||
|
bdff542ef9 | ||
|
38273dac92 | ||
|
185e1a98f4 | ||
|
9da0e1ff61 |
46 changed files with 786 additions and 188 deletions
48
.github/ISSUE_TEMPLATE/bug.yaml
vendored
Normal file
48
.github/ISSUE_TEMPLATE/bug.yaml
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug] "
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: "How do you trigger this bug? Please walk us through it step by step."
|
||||
value: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
...
|
||||
render: bash
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of VS Code are you using?
|
||||
options:
|
||||
- Stable (Default)
|
||||
- Insiders
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- All
|
||||
- Windows
|
||||
- macOS
|
||||
- Linux
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
1
.github/workflows/ciBuild.yml
vendored
1
.github/workflows/ciBuild.yml
vendored
|
@ -26,7 +26,6 @@ jobs:
|
|||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm ci
|
||||
- run: npm run package
|
||||
- run: npx vsce package
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -6,6 +6,21 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.1.3] - 2021-6-17
|
||||
## Added
|
||||
- New feature! JSON strings inside documents will now be automatically formatted as JSON when viewing documents. You can turn this feature off via the `appwrite.formatJsonStrings` setting.
|
||||
|
||||
## [0.1.2] - 2021-6-03
|
||||
## Added
|
||||
- Ability to set the `list`, `default` and `array` properties when creating a new collection. | [Issue #20](https://github.com/streamlux/vscode-appwrite/issues/20) | [PR #21](https://github.com/streamlux/vscode-appwrite/pull/21) | Thanks [@Maatteogekko](https://github.com/Maatteogekko)!
|
||||
|
||||
## [0.1.1] - 2021-5-31
|
||||
## Added
|
||||
- You can now easily create function tags from multiple places in the extension. [PR #19](https://github.com/streamlux/vscode-appwrite/pull/19)
|
||||
|
||||
## Fixed
|
||||
- Fixed an error when deleting a user. [Issue #17](https://github.com/streamlux/vscode-appwrite/issues/17) [PR #18](https://github.com/streamlux/vscode-appwrite/pull/18) Thanks [@aadarshadhakalg](https://github.com/aadarshadhakalg)!
|
||||
|
||||
## [0.1.0] - 2021-5-29
|
||||
|
||||
## Functions!
|
||||
|
|
10
README.md
10
README.md
|
@ -18,7 +18,15 @@ From [appwrite.io](https://appwrite.io)
|
|||
|
||||
### Connect to multiple Appwrite projects
|
||||
|
||||
![Mutliple projects](media/features/projects/projectsView1.gif)
|
||||
<img src="media/features/projects/projectsView1.gif" height="600">
|
||||
|
||||
### Creating function tags with ease!
|
||||
|
||||
![Functions feature](media/features/functions/CreateTag.gif)
|
||||
|
||||
### Create and manage Appwrite cloud functions, upload tags, and view function output
|
||||
|
||||
<img src="media/features/functions/functionsOverview.png" height="500">
|
||||
|
||||
### View database documents right inside VS Code.
|
||||
|
||||
|
|
BIN
media/features/functions/CreateTag.gif
Normal file
BIN
media/features/functions/CreateTag.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
BIN
media/features/functions/functionsOverview.png
Normal file
BIN
media/features/functions/functionsOverview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 470 KiB |
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vscode-appwrite",
|
||||
"version": "0.1.0",
|
||||
"version": "0.0.9",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
168
package.json
168
package.json
|
@ -2,7 +2,7 @@
|
|||
"name": "vscode-appwrite",
|
||||
"displayName": "Appwrite",
|
||||
"description": "Manage your Appwrite resources right from VS Code!",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.3",
|
||||
"engines": {
|
||||
"vscode": "^1.55.0"
|
||||
},
|
||||
|
@ -40,151 +40,187 @@
|
|||
{
|
||||
"command": "vscode-appwrite.Connect",
|
||||
"title": "Connect to Appwrite",
|
||||
"category": ""
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.CreateUser",
|
||||
"title": "Create user",
|
||||
"icon": "$(add)"
|
||||
"icon": "$(add)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.DeleteUser",
|
||||
"title": "Delete user",
|
||||
"icon": "$(trash)"
|
||||
"icon": "$(trash)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.GetUserLogs",
|
||||
"title": "Get user logs",
|
||||
"icon": "$(output)"
|
||||
"icon": "$(output)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.openUserInConsole",
|
||||
"title": "View user in Appwrite console",
|
||||
"icon": "$(link-external)"
|
||||
"icon": "$(link-external)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.viewUserPrefs",
|
||||
"title": "View user preferences",
|
||||
"icon": "$(json)"
|
||||
"icon": "$(json)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshEntry",
|
||||
"title": "Refresh",
|
||||
"icon": "$(refresh)"
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.copyUserId",
|
||||
"title": "Copy user ID",
|
||||
"icon": "$(clippy)"
|
||||
"icon": "$(clippy)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.copyUserEmail",
|
||||
"title": "Copy user email",
|
||||
"icon": "$(clippy)"
|
||||
"icon": "$(clippy)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshUsersList",
|
||||
"title": "Refresh users list",
|
||||
"icon": "$(refresh)"
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.OpenUsersDocumentation",
|
||||
"title": "Open documentation",
|
||||
"icon": "$(book)"
|
||||
"icon": "$(book)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.OpenDatabaseDocumentation",
|
||||
"title": "Open documentation",
|
||||
"icon": "$(book)"
|
||||
"icon": "$(book)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.viewDocumentAsJson",
|
||||
"title": "View as JSON"
|
||||
"title": "View as JSON",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.viewCollectionAsJson",
|
||||
"title": "View collection as JSON"
|
||||
"title": "View collection as JSON",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshCollection",
|
||||
"title": "Refresh",
|
||||
"icon": "$(refresh)"
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.createRule",
|
||||
"title": "Create collection rule",
|
||||
"icon": "$(add)"
|
||||
"icon": "$(add)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.removeRule",
|
||||
"title": "Remove collection rule"
|
||||
"title": "Remove collection rule",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.deleteDocument",
|
||||
"title": "Delete document"
|
||||
"title": "Delete document",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.deleteCollection",
|
||||
"title": "Delete collection"
|
||||
"title": "Delete collection",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshCollectionsList",
|
||||
"title": "Refresh",
|
||||
"icon": "$(refresh)"
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.createCollection",
|
||||
"title": "Create collection",
|
||||
"icon": "$(add)"
|
||||
"icon": "$(add)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.createPermission",
|
||||
"title": "Create permission",
|
||||
"icon": "$(add)"
|
||||
"icon": "$(add)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.deletePermission",
|
||||
"title": "Delete permission",
|
||||
"icon": "$(trash)"
|
||||
"icon": "$(trash)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.editPermission",
|
||||
"title": "Edit permission",
|
||||
"icon": "$(edit)"
|
||||
"icon": "$(edit)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshHealth",
|
||||
"title": "Refresh health",
|
||||
"icon": "$(refresh)"
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.openHealthDocumentation",
|
||||
"title": "Open health documentation",
|
||||
"icon": "$(book)"
|
||||
"icon": "$(book)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshStorage",
|
||||
"title": "Refresh storage",
|
||||
"icon": "$(refresh)"
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.openStorageDocumentation",
|
||||
"title": "Open storage documentation",
|
||||
"icon": "$(book)"
|
||||
"icon": "$(book)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.addProject",
|
||||
"title": "Add Appwrite project",
|
||||
"icon": "$(plus)"
|
||||
"icon": "$(plus)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.setActiveProject",
|
||||
"title": "Set as active"
|
||||
"title": "Set as active",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshProjects",
|
||||
"title": "Refresh projects",
|
||||
"icon": "$(refresh)"
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshFunctions",
|
||||
"title": "Refresh functions",
|
||||
"icon": "$(refresh)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.refreshFunctions",
|
||||
|
@ -194,91 +230,115 @@
|
|||
{
|
||||
"command": "vscode-appwrite.removeProject",
|
||||
"title": "Remove project",
|
||||
"icon": "$(trash)"
|
||||
"icon": "$(trash)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.CreateTag",
|
||||
"title": "Create function tag",
|
||||
"icon": "$(cloud-upload)"
|
||||
"icon": "$(cloud-upload)",
|
||||
"shortTitle": "Create function tag",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.deleteTag",
|
||||
"title": "Delete tag",
|
||||
"icon": "$(trash)"
|
||||
"icon": "$(trash)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.CreateExecution",
|
||||
"title": "Execute"
|
||||
"title": "Execute",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.activateTag",
|
||||
"title": "Activate"
|
||||
"title": "Activate",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.editValue",
|
||||
"title": "Edit",
|
||||
"icon": "$(edit)"
|
||||
"icon": "$(edit)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.deleteFunction",
|
||||
"title": "Delete",
|
||||
"icon": "$(trash)"
|
||||
"icon": "$(trash)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.openFunctionsDocumentation",
|
||||
"title": "Open functions documentation",
|
||||
"icon": "$(book)"
|
||||
"icon": "$(book)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.createFunction",
|
||||
"title": "Create function",
|
||||
"icon": "$(add)"
|
||||
"icon": "$(add)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.createFunctionVar",
|
||||
"title": "Create variable",
|
||||
"icon": "$(add)"
|
||||
"icon": "$(add)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.deleteFunctionVar",
|
||||
"title": "Delete variable",
|
||||
"icon": "$(trash)"
|
||||
"icon": "$(trash)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.viewExecutionOutput",
|
||||
"title": "View execution stdout",
|
||||
"enablement": "viewItem =~ /^((execution|execution_outputOnly))$/"
|
||||
"enablement": "viewItem =~ /^((execution|execution_outputOnly))$/",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.viewExecutionErrors",
|
||||
"title": "View execution stderr",
|
||||
"enablement": "viewItem =~ /^((execution|execution_errorOnly))$/"
|
||||
"enablement": "viewItem =~ /^((execution|execution_errorOnly))$/",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.copyExecutionOutput",
|
||||
"title": "Copy execution stdout",
|
||||
"enablement": "viewItem =~ /^((execution|execution_outputOnly))$/"
|
||||
"enablement": "viewItem =~ /^((execution|execution_outputOnly))$/",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.copyExecutionErrors",
|
||||
"title": "Copy execution stderr",
|
||||
"enablement": "viewItem =~ /^((execution|execution_errorOnly))$/"
|
||||
"enablement": "viewItem =~ /^((execution|execution_errorOnly))$/",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.openExecutionsInBrowser",
|
||||
"title": "View executions in browser",
|
||||
"enablement": "viewItem =~ /^(executions)$/",
|
||||
"icon": "$(link-external)"
|
||||
"icon": "$(link-external)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.openFunctionTagsInBrowser",
|
||||
"title": "Open function tags in browser",
|
||||
"icon": "$(link-external)"
|
||||
"icon": "$(link-external)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.openFunctionSettingsInBrowser",
|
||||
"title": "Open function settings in browser",
|
||||
"icon": "$(link-external)"
|
||||
"icon": "$(link-external)",
|
||||
"category": "Appwrite"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.viewMore",
|
||||
"title": "View more",
|
||||
"category": "Appwrite"
|
||||
}
|
||||
],
|
||||
"views": {
|
||||
|
@ -570,6 +630,9 @@
|
|||
}
|
||||
],
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "vscode-appwrite.CreateTag"
|
||||
},
|
||||
{
|
||||
"command": "vscode-appwrite.Connect"
|
||||
},
|
||||
|
@ -663,6 +726,11 @@
|
|||
"type": "string",
|
||||
"default": "",
|
||||
"markdownDescription": "Project id of the active project, see [docs](https://github.com/streamlux/vscode-appwrite/) for more information."
|
||||
},
|
||||
"appwrite.formatJsonStrings": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"markdownDescription": "Format JSON strings when viewing documents"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
10
src/appwrite.d.ts
vendored
10
src/appwrite.d.ts
vendored
|
@ -276,7 +276,7 @@ export type CollectionsList = {
|
|||
collections: Collection[];
|
||||
};
|
||||
|
||||
export type CreatedRule = Omit<Rule, "$id" | "$collection" | "default" | "list">;
|
||||
export type CreatedRule = Omit<Rule, "$id" | "$collection">;
|
||||
|
||||
export type Rule = {
|
||||
$id: string;
|
||||
|
@ -284,10 +284,10 @@ export type Rule = {
|
|||
type: string;
|
||||
key: string;
|
||||
label: string;
|
||||
default: string;
|
||||
array: boolean;
|
||||
default?: any;
|
||||
required: boolean;
|
||||
list: string[];
|
||||
array: boolean;
|
||||
list?: string[];
|
||||
};
|
||||
|
||||
export type Permissions = {
|
||||
|
@ -305,7 +305,7 @@ export type Client = {
|
|||
setSelfSigned: (value: boolean) => void;
|
||||
};
|
||||
export type UsersClient = {
|
||||
deleteUser: (id: string) => Promise<any>;
|
||||
delete: (id: string) => Promise<any>;
|
||||
deleteSessions: (id: string) => Promise<any>;
|
||||
create: (email: string, password: string, name?: string) => Promise<any>;
|
||||
getLogs: (id: string) => Promise<Log[]>;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Client, Execution, ExecutionList, FunctionsClient, TagList, Vars } from "../appwrite";
|
||||
import { Client, Execution, ExecutionList, FunctionsClient, FunctionsList, Tag, 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;
|
||||
public readonly functions: FunctionsClient;
|
||||
|
||||
constructor(client: Client) {
|
||||
this.functions = new AppwriteSDK.Functions(client);
|
||||
|
@ -13,7 +13,7 @@ export class Functions {
|
|||
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> {
|
||||
public async list(search?: string, offset?: number, limit?: number, orderType?: 'ASC' | 'DESC'): Promise<FunctionsList | undefined> {
|
||||
return await AppwriteCall(this.functions.list(search, offset, limit, orderType));
|
||||
}
|
||||
public async get(functionId: string): Promise<any> {
|
||||
|
@ -28,7 +28,7 @@ export class Functions {
|
|||
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> {
|
||||
public async createTag(functionId: string, command: string, code: ReadStream): Promise<Tag | undefined> {
|
||||
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> {
|
||||
|
@ -40,11 +40,11 @@ export class Functions {
|
|||
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> {
|
||||
public async createExecution(functionId: string, data?: string): Promise<Execution | undefined> {
|
||||
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));
|
||||
return await AppwriteCall(this.functions.listExecutions(functionId, search, limit, offset, orderType));
|
||||
}
|
||||
public async getExecution(functionId: string, executionId: string): Promise<Execution | undefined> {
|
||||
return await AppwriteCall(this.functions.getExecution(functionId, executionId));
|
||||
|
|
|
@ -16,7 +16,7 @@ export class Users {
|
|||
}
|
||||
|
||||
public async delete(userId: string): Promise<void> {
|
||||
await AppwriteCall(this.users.deleteUser(userId), () => {
|
||||
await AppwriteCall(this.users.delete(userId), () => {
|
||||
window.showInformationMessage(`Deleted user with id: ${userId}.`);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { EditableTreeItem } from '../../tree/common/SimpleEditableTreeItem';
|
||||
import { EditableTreeItem } from '../../tree/common/editable/SimpleEditableTreeItem';
|
||||
|
||||
export async function editValue(treeItem: EditableTreeItem): Promise<void> {
|
||||
if (treeItem === undefined) {
|
||||
|
|
5
src/commands/common/viewMore.ts
Normal file
5
src/commands/common/viewMore.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { AppwriteTreeItemBase } from '../../ui/AppwriteTreeItemBase';
|
||||
|
||||
export async function viewMore(treeItem: AppwriteTreeItemBase<any>): Promise<void> {
|
||||
await treeItem.viewMore();
|
||||
}
|
|
@ -10,15 +10,13 @@ export async function createRule(rulesTreeItem: RulesTreeItem): Promise<void> {
|
|||
return;
|
||||
}
|
||||
|
||||
const ruleContext = await createRuleWizard();
|
||||
const collection = rulesTreeItem.parent.collection;
|
||||
const ruleContext = await createRuleWizard(collection);
|
||||
|
||||
if (ruleContext) {
|
||||
const newRule: CreatedRule = {
|
||||
...ruleContext,
|
||||
type: ruleContext.type,
|
||||
required: true,
|
||||
array: false,
|
||||
};
|
||||
|
||||
databaseClient.createRule(collection, newRule);
|
||||
|
|
|
@ -1,8 +1,30 @@
|
|||
import { workspace } from "vscode";
|
||||
import { DocumentTreeItem } from "../../tree/database/DocumentTreeItem";
|
||||
import { openReadOnlyJson } from "../../ui/openReadonlyContent";
|
||||
|
||||
function parseJSONString(str: string): { valid: boolean; value: any } {
|
||||
try {
|
||||
return { value: JSON.parse(str), valid: true };
|
||||
} catch (e) {
|
||||
return { value: str, valid: false };
|
||||
}
|
||||
}
|
||||
|
||||
export async function viewDocumentAsJson(documentTreeItem: DocumentTreeItem): Promise<void> {
|
||||
const documentId = documentTreeItem.document["$id"];
|
||||
const document = documentTreeItem.document;
|
||||
const documentId = document["$id"];
|
||||
|
||||
const formatJsonStrings = workspace.getConfiguration("appwrite").get<Boolean>("formatJsonStrings");
|
||||
|
||||
if (formatJsonStrings) {
|
||||
Object.entries(document).forEach(([key, value]) => {
|
||||
if (typeof value === "string") {
|
||||
const result = parseJSONString(value);
|
||||
document[key] = result.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await openReadOnlyJson(
|
||||
{
|
||||
label: documentId,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Tag } from '../../appwrite';
|
||||
import { functionsClient } from '../../client';
|
||||
import { TagTreeItem } from '../../tree/functions/tags/TagTreeItem';
|
||||
|
||||
export async function activateTag(tagItem: TagTreeItem): Promise<void> {
|
||||
const tag = tagItem.tag;
|
||||
export async function activateTag(tagItem: TagTreeItem | Tag): Promise<void> {
|
||||
const tag = tagItem instanceof TagTreeItem ? tagItem.tag : tagItem;
|
||||
await functionsClient?.updateTag(tag.functionId, tag.$id);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,57 @@
|
|||
import { window } from 'vscode';
|
||||
import { Execution } from '../../appwrite';
|
||||
import { functionsClient } from '../../client';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { FunctionTreeItem } from '../../tree/functions/FunctionTreeItem';
|
||||
import { sleep } from '../../utils/sleep';
|
||||
import { viewExecutionErrors } from './viewExecutionErrors';
|
||||
import { viewExecutionOutput } from './viewExecutionOutput';
|
||||
|
||||
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);
|
||||
await executeFunction(func.$id);
|
||||
}
|
||||
|
||||
export async function executeFunction(functionId: string): Promise<void> {
|
||||
ext.outputChannel.appendLog(`Creating execution for function with ID: ${functionId}`);
|
||||
let execution = await functionsClient?.createExecution(functionId);
|
||||
ext.outputChannel.appendLog(JSON.stringify(execution, null, 2));
|
||||
await ext.tree?.functions?.refresh();
|
||||
|
||||
if (execution === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
execution = await waitForExecution(execution);
|
||||
ext.tree?.functions?.refresh();
|
||||
|
||||
if (execution === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const failed = execution.status === "failed";
|
||||
const item = !failed ? "View output" : "View errors";
|
||||
const action = await window.showInformationMessage(`Execution ${failed ? "failed" : "completed"} in ${execution.time.toFixed(2)}s.`, item);
|
||||
if (action === item) {
|
||||
if (item === "View output") {
|
||||
await viewExecutionOutput(execution);
|
||||
return;
|
||||
}
|
||||
await viewExecutionErrors(execution);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForExecution(execution: Execution | undefined): Promise<Execution | undefined> {
|
||||
if (execution === undefined) {
|
||||
return;
|
||||
}
|
||||
if (execution.status === "processing" || execution.status === "waiting") {
|
||||
await sleep(5000);
|
||||
|
||||
ext.outputChannel.appendLog("Execution still ...");
|
||||
return await waitForExecution(await functionsClient?.getExecution(execution.functionId, execution.$id));
|
||||
}
|
||||
|
||||
return execution;
|
||||
}
|
||||
|
|
|
@ -1,41 +1,164 @@
|
|||
import { ProgressLocation, Uri, window } from "vscode";
|
||||
import { functionsClient, storageClient } from "../../client";
|
||||
import { ProgressLocation, QuickPickItem, Uri, window, workspace } from "vscode";
|
||||
import { functionsClient } from "../../client";
|
||||
import { getTarReadStream } from "../../utils/tar";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import * as fs from "fs";
|
||||
import { TagsTreeItem } from "../../tree/functions/tags/TagsTreeItem";
|
||||
import { selectWorkspaceFolder } from "../../utils/workspace";
|
||||
export async function createTag(item: TagsTreeItem | Uri): Promise<void> {
|
||||
import { ProgressMessage } from "../../utils/types";
|
||||
import { Tag } from "../../appwrite";
|
||||
import { activateTag } from "./activateTag";
|
||||
|
||||
export async function createTag(item?: TagsTreeItem | Uri): Promise<void> {
|
||||
if (item instanceof Uri) {
|
||||
window.withProgress({ location: ProgressLocation.Notification, title: "Creating tag..." }, async (_progress, _token) => {
|
||||
await createTagFromUri(item);
|
||||
});
|
||||
const functions = await functionsClient?.list();
|
||||
if (functions === undefined) {
|
||||
return;
|
||||
}
|
||||
const pick = await window.showQuickPick(
|
||||
functions.functions.map<QuickPickItem>(
|
||||
(func): QuickPickItem => ({ label: func.name, description: func.env, detail: func.$id })
|
||||
),
|
||||
{ placeHolder: "Select a function to create tag" }
|
||||
);
|
||||
if (pick === undefined || pick.detail === undefined) {
|
||||
return;
|
||||
}
|
||||
const tags = await functionsClient?.listTags(pick.detail);
|
||||
let value;
|
||||
if (tags && tags.tags.length > 0) {
|
||||
value = tags.tags[tags.tags.length - 1].command;
|
||||
}
|
||||
const command = await window.showInputBox({ value, prompt: "Command to run your code" });
|
||||
if (command === undefined) {
|
||||
return;
|
||||
}
|
||||
const tag = await window.withProgress(
|
||||
{ location: ProgressLocation.Notification, title: "Creating tag..." },
|
||||
async (progress, _token) => {
|
||||
if (pick.detail === undefined) {
|
||||
return;
|
||||
}
|
||||
return await createTagFromUri(pick.detail, command, item, progress);
|
||||
}
|
||||
);
|
||||
if (tag) {
|
||||
await tagNotification(tag);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (item instanceof TagsTreeItem) {
|
||||
const func = item.parent.func;
|
||||
const folder = await selectWorkspaceFolder("Select folder of your function code.");
|
||||
console.log(folder);
|
||||
window.withProgress({ location: ProgressLocation.Notification, title: "Creating tag..." }, async (_progress, _token) => {
|
||||
await createTagFromUri(Uri.parse(folder));
|
||||
});
|
||||
if (folder === undefined || folder === "") {
|
||||
return;
|
||||
}
|
||||
const tags = await functionsClient?.listTags(func.$id);
|
||||
let value;
|
||||
if (tags && tags.tags.length > 0) {
|
||||
value = tags.tags[tags.tags.length - 1].command;
|
||||
}
|
||||
const command = await window.showInputBox({ value, prompt: "Command to run your code" });
|
||||
if (command === undefined) {
|
||||
return;
|
||||
}
|
||||
const tag = await window.withProgress(
|
||||
{ location: ProgressLocation.Notification, title: "Creating tag..." },
|
||||
async (progress, _token) => {
|
||||
return await createTagFromUri(func.$id, command, Uri.parse(folder), progress);
|
||||
}
|
||||
);
|
||||
|
||||
if (tag) {
|
||||
await tagNotification(tag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (item === undefined) {
|
||||
const functions = await functionsClient?.list();
|
||||
if (functions === undefined) {
|
||||
return;
|
||||
}
|
||||
const pick = await window.showQuickPick(
|
||||
functions.functions.map<QuickPickItem>(
|
||||
(func): QuickPickItem => ({ label: func.name, description: func.env, detail: func.$id })
|
||||
),
|
||||
{ placeHolder: "Select a function to create tag" }
|
||||
);
|
||||
if (pick === undefined || pick.detail === undefined) {
|
||||
return;
|
||||
}
|
||||
const funcId = pick.detail;
|
||||
const folder = await selectWorkspaceFolder("Select folder of your function code.");
|
||||
const tags = await functionsClient?.listTags(funcId);
|
||||
let value;
|
||||
if (tags && tags.tags.length > 0) {
|
||||
value = tags.tags[tags.tags.length - 1].command;
|
||||
}
|
||||
const command = await window.showInputBox({ value, prompt: "Command to run your code" });
|
||||
if (command === undefined) {
|
||||
return;
|
||||
}
|
||||
const tag = await window.withProgress(
|
||||
{ location: ProgressLocation.Notification, title: "Creating tag..." },
|
||||
async (progress, _token) => {
|
||||
return await createTagFromUri(funcId, command, Uri.parse(folder), progress);
|
||||
}
|
||||
);
|
||||
|
||||
if (tag) {
|
||||
await tagNotification(tag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createTagFromUri(uri: Uri): Promise<void> {
|
||||
const tarFilePath = await getTarReadStream(uri);
|
||||
async function createTagFromUri(functionId: string, command: string, uri: Uri, progress: ProgressMessage): Promise<Tag | undefined> {
|
||||
progress.report({ message: "Creating tarball", increment: 10 });
|
||||
|
||||
if (functionsClient === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tarFilePath === undefined) {
|
||||
ext.outputChannel.appendLog("Error creating tar file.");
|
||||
let tarFilePath;
|
||||
try {
|
||||
tarFilePath = await getTarReadStream(uri);
|
||||
} catch (e) {
|
||||
window.showErrorMessage("Error creating tar file.\n" + e);
|
||||
return;
|
||||
}
|
||||
if (tarFilePath === undefined) {
|
||||
window.showErrorMessage("Failed to create tar file.");
|
||||
ext.outputChannel.appendLog("Failed to create tar file.");
|
||||
return;
|
||||
}
|
||||
// somehow makes the upload work
|
||||
await workspace.fs.readFile(Uri.file(tarFilePath));
|
||||
progress.report({ message: "Uploading tag", increment: 60 });
|
||||
try {
|
||||
await functionsClient.createTag("60b1836a8e5d9", "python ./hello.py", fs.createReadStream(tarFilePath));
|
||||
await storageClient?.createFile(fs.createReadStream(tarFilePath));
|
||||
return await functionsClient.createTag(functionId, command, fs.createReadStream(tarFilePath));
|
||||
} catch (e) {
|
||||
ext.outputChannel.appendLog("Creating tag error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
async function tagNotification(tag: Tag): Promise<void> {
|
||||
ext.tree?.functions?.refresh();
|
||||
if (tag) {
|
||||
const action = await window.showInformationMessage(
|
||||
`Successfully created tag with size ${tag.size}B.`,
|
||||
"Activate tag",
|
||||
"View in console"
|
||||
);
|
||||
if (action === "Activate tag") {
|
||||
await activateTag(tag);
|
||||
}
|
||||
if (action === "View in console") {
|
||||
//
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import { Execution } from '../../appwrite';
|
||||
import { ExecutionTreeItem } from "../../tree/functions/executions/ExecutionTreeItem";
|
||||
import { openReadOnlyContent } from "../../ui/openReadonlyContent";
|
||||
|
||||
export async function viewExecutionErrors(executionItem: ExecutionTreeItem): Promise<void> {
|
||||
export async function viewExecutionErrors(executionItem: ExecutionTreeItem | Execution): Promise<void> {
|
||||
if (executionItem === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const execution = executionItem.execution;
|
||||
await openReadOnlyContent({ label: `${executionItem.parent.parent.func.name} execution stderr`, fullId: `${execution.$id}-errors.txt` }, execution.stderr, '.txt');
|
||||
let execution = executionItem as Execution;
|
||||
|
||||
if (executionItem instanceof ExecutionTreeItem) {
|
||||
execution = executionItem.execution;
|
||||
}
|
||||
await openReadOnlyContent({ label: `Execution stderr`, fullId: `${execution.$id}-errors.txt` }, execution.stderr, '.txt');
|
||||
}
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
import { Execution } from '../../appwrite';
|
||||
import { ExecutionTreeItem } from "../../tree/functions/executions/ExecutionTreeItem";
|
||||
import { openReadOnlyContent } from "../../ui/openReadonlyContent";
|
||||
|
||||
export async function viewExecutionOutput(executionItem: ExecutionTreeItem): Promise<void> {
|
||||
export async function viewExecutionOutput(executionItem: ExecutionTreeItem | Execution): Promise<void> {
|
||||
if (executionItem === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const execution = executionItem.execution;
|
||||
await openReadOnlyContent({ label: `${executionItem.parent.parent.func.name} execution stdout`, fullId: `${execution.$id}-output.txt` }, execution.stdout, '.txt');
|
||||
|
||||
let execution = executionItem as Execution;
|
||||
|
||||
if (executionItem instanceof ExecutionTreeItem) {
|
||||
execution = executionItem.execution;
|
||||
}
|
||||
console.log(execution.dateCreated);
|
||||
|
||||
await openReadOnlyContent({ label: `Execution stdout`, fullId: `${execution.$id}-output.txt` }, execution.stdout, '.txt');
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ import { openExecutionsInBrowser } from './functions/openExecutionsInBrowser';
|
|||
import { openFunctionSettingsInBrowser } from './functions/openFunctionSettingsInBrowser';
|
||||
import { openFunctionTagsInBrowser } from './functions/openFunctionTagsInBrowser';
|
||||
|
||||
import { viewMore } from './common/viewMore';
|
||||
|
||||
class CommandRegistrar {
|
||||
constructor(private readonly context: ExtensionContext) {}
|
||||
|
||||
|
@ -74,6 +76,7 @@ export function registerCommands(context: ExtensionContext): void {
|
|||
|
||||
/** Common **/
|
||||
registerCommand("editValue", editValue);
|
||||
registerCommand("viewMore", viewMore);
|
||||
|
||||
/** General **/
|
||||
registerCommand("Connect", connectAppwrite, "all");
|
||||
|
|
|
@ -20,7 +20,7 @@ export async function deleteUser(userTreeItem: UserTreeItem): Promise<void> {
|
|||
);
|
||||
|
||||
if (shouldDeleteUser === DialogResponses.yes) {
|
||||
await usersClient.delete(userId);
|
||||
await usersClient.delete(userId);
|
||||
refreshTree("users");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export type AppwriteTree = {
|
|||
};
|
||||
|
||||
export type Ext = {
|
||||
context?: ExtensionContext;
|
||||
context: ExtensionContext;
|
||||
outputChannel: AppwriteOutputChannel;
|
||||
tree?: AppwriteTree;
|
||||
};
|
||||
|
|
13
src/tree/common/editable/EditableTreeItemBase.ts
Normal file
13
src/tree/common/editable/EditableTreeItemBase.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { TreeItem } from "vscode";
|
||||
|
||||
export abstract class EditableTreeItemBase<T> extends TreeItem {
|
||||
public abstract setValue(value: T): Promise<void>;
|
||||
|
||||
constructor(contextValuePrefix: string, public readonly value: T, description?: string) {
|
||||
super(typeof value === "string" ? value : "No label");
|
||||
this.contextValue = `editable_${contextValuePrefix}`;
|
||||
this.description = description ?? contextValuePrefix;
|
||||
}
|
||||
|
||||
public abstract prompt(): Promise<void>;
|
||||
}
|
38
src/tree/common/editable/EnumEditableTreeItem.ts
Normal file
38
src/tree/common/editable/EnumEditableTreeItem.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { QuickPickItem, QuickPickOptions, window } from "vscode";
|
||||
import { EditableTreeItemBase } from "./EditableTreeItemBase";
|
||||
|
||||
export abstract class EnumEditableTreeItemBase extends EditableTreeItemBase<string[]> {
|
||||
public abstract options: string[] | QuickPickItem[];
|
||||
|
||||
public quickPickOptions: QuickPickOptions;
|
||||
|
||||
constructor(contextValuePrefix: string, public readonly value: string[], description?: string) {
|
||||
super(contextValuePrefix, value, description);
|
||||
this.quickPickOptions = {};
|
||||
}
|
||||
|
||||
public async prompt(): Promise<void> {
|
||||
|
||||
const value = await window.showQuickPick(
|
||||
this.options.map<QuickPickItem>((option: QuickPickItem | string): QuickPickItem => {
|
||||
if (typeof option === "string") {
|
||||
return { label: option, picked: this.value.includes(option) };
|
||||
}
|
||||
const picked = this.value.includes(option.label);
|
||||
return { ...option, picked, alwaysShow: picked };
|
||||
}).sort((a, b) => {
|
||||
if (a.picked) {
|
||||
return -1;
|
||||
}
|
||||
if (b.picked) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}),
|
||||
{ ...this.quickPickOptions, canPickMany: true }
|
||||
);
|
||||
if (value !== undefined) {
|
||||
this.setValue(value.map((item) => item.label));
|
||||
}
|
||||
}
|
||||
}
|
18
src/tree/common/editable/SimpleEditableTreeItem.ts
Normal file
18
src/tree/common/editable/SimpleEditableTreeItem.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { TreeItem, window } from "vscode";
|
||||
|
||||
export class EditableTreeItem extends TreeItem {
|
||||
public readonly setValue: (value: string) => Promise<void>;
|
||||
|
||||
constructor(label: string, contextValuePrefix: string, public readonly value: string, setValue: (value: string) => Promise<void>) {
|
||||
super(label);
|
||||
this.setValue = setValue;
|
||||
this.contextValue = `editable_${contextValuePrefix}`;
|
||||
}
|
||||
|
||||
public async prompt(): Promise<void> {
|
||||
const value = await window.showInputBox({ value: this.value });
|
||||
if (value !== undefined) {
|
||||
this.setValue(value);
|
||||
}
|
||||
}
|
||||
}
|
22
src/tree/common/editable/StringEditableTreeItem.ts
Normal file
22
src/tree/common/editable/StringEditableTreeItem.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { InputBoxOptions, window } from "vscode";
|
||||
import { EditableTreeItemBase } from "./EditableTreeItemBase";
|
||||
|
||||
export abstract class StringEditableTreeItemBase extends EditableTreeItemBase<string> {
|
||||
public abstract setValue(value: string): Promise<void>;
|
||||
public inputBoxOptions: InputBoxOptions;
|
||||
|
||||
constructor(contextValuePrefix: string, public readonly value: string, description?: string) {
|
||||
super(contextValuePrefix, value, description);
|
||||
|
||||
this.inputBoxOptions = {
|
||||
prompt: description,
|
||||
};
|
||||
}
|
||||
|
||||
public async prompt(): Promise<void> {
|
||||
const value = await window.showInputBox({ value: this.value, ...this.inputBoxOptions });
|
||||
if (value !== undefined) {
|
||||
this.setValue(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,8 +4,8 @@ import AppwriteCall from "../../utils/AppwriteCall";
|
|||
import { Collection, CollectionsList } from "../../appwrite";
|
||||
import { CollectionTreeItem } from "./CollectionTreeItem";
|
||||
import { AppwriteSDK } from "../../constants";
|
||||
import { AppwriteTreeItemBase } from "../../ui/AppwriteTreeItemBase";
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { AppwriteTreeItemBase } from '../../ui/AppwriteTreeItemBase';
|
||||
|
||||
export class DatabaseTreeItemProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<vscode.TreeItem | undefined | void> = new vscode.EventEmitter<
|
||||
|
@ -34,7 +34,7 @@ export class DatabaseTreeItemProvider implements vscode.TreeDataProvider<vscode.
|
|||
}
|
||||
|
||||
if (parent instanceof AppwriteTreeItemBase) {
|
||||
return parent.getChildren?.() ?? [];
|
||||
return await parent.getChildren?.() ?? [];
|
||||
}
|
||||
|
||||
const databaseSdk = new AppwriteSDK.Database(client);
|
||||
|
|
|
@ -44,7 +44,7 @@ export class FunctionsTreeItemProvider implements vscode.TreeDataProvider<vscode
|
|||
}
|
||||
|
||||
if (parent instanceof AppwriteTreeItemBase) {
|
||||
return parent.getChildren?.() ?? [];
|
||||
return await parent.getChildren?.() ?? [];
|
||||
}
|
||||
|
||||
return [];
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { MarkdownString, ThemeColor, ThemeIcon, TreeItem } from "vscode";
|
||||
import { Execution, ExecutionStatus } from "../../../appwrite";
|
||||
import { functionsClient } from "../../../client";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { msToDate } from "../../../utils/date";
|
||||
import { ExecutionsTreeItem } from "./ExecutionsTreeItem";
|
||||
|
||||
|
@ -12,17 +10,11 @@ const executionStatusIcons: Record<ExecutionStatus, ThemeIcon> = {
|
|||
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, public readonly execution: Execution) {
|
||||
constructor(public readonly parent: ExecutionsTreeItem, public execution: Execution) {
|
||||
super(execution.$id);
|
||||
this.label = this.getLabel(execution);
|
||||
this.iconPath = executionStatusIcons[execution.status];
|
||||
|
@ -31,40 +23,45 @@ export class ExecutionTreeItem extends TreeItem {
|
|||
this.description = execution.trigger;
|
||||
this.contextValue = this.getContextValue(execution);
|
||||
this.isAutoRefreshing = execution.status === "processing" || execution.status === "waiting";
|
||||
this.autoRefresh();
|
||||
// if (this.isAutoRefreshing) {
|
||||
// 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);
|
||||
// async autoRefresh(): Promise<void> {
|
||||
// if (!this.isAutoRefreshing && this.refreshCount < 5) {
|
||||
// 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.contextValue = this.getContextValue(execution);
|
||||
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();
|
||||
}
|
||||
// if (!execution) {
|
||||
// ext.outputChannel.appendLog("Execution is undefined");
|
||||
// this.isAutoRefreshing = false;
|
||||
// return;
|
||||
// }
|
||||
// this.execution = execution;
|
||||
// this.contextValue = this.getContextValue(execution);
|
||||
// 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" || execution.status === "failed") {
|
||||
return `${this.getCreated(execution)} (${execution.time.toPrecision(2)}s)`;
|
||||
return `${this.getCreated(execution)} (${this.getExecutionTime(execution)}s)`;
|
||||
}
|
||||
return `${this.getCreated(execution)} (${execution.status})`;
|
||||
}
|
||||
|
||||
getExecutionTime(execution: Execution): string {
|
||||
return execution.time.toPrecision(2);
|
||||
}
|
||||
|
||||
getContextValue(execution: Execution): string {
|
||||
if (execution.status === "completed" || execution.status === "failed") {
|
||||
if (execution.stderr === "" && execution.stdout === "") {
|
||||
|
|
|
@ -1,21 +1,47 @@
|
|||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { Execution, ExecutionList } from '../../../appwrite';
|
||||
import { Execution, ExecutionList } from "../../../appwrite";
|
||||
import { functionsClient } from "../../../client";
|
||||
import { AppwriteTreeItemBase } from '../../../ui/AppwriteTreeItemBase';
|
||||
import { ExecutionTreeItem } from './ExecutionTreeItem';
|
||||
import { FunctionTreeItem } from '../FunctionTreeItem';
|
||||
import { ExecutionTreeItem } from "./ExecutionTreeItem";
|
||||
import { FunctionTreeItem } from "../FunctionTreeItem";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { AppwriteTreeItemBase } from "../../../ui/AppwriteTreeItemBase";
|
||||
|
||||
export class ExecutionsTreeItem extends AppwriteTreeItemBase<FunctionTreeItem> {
|
||||
constructor(public readonly parent: FunctionTreeItem) {
|
||||
super(parent, "Executions");
|
||||
}
|
||||
|
||||
private executionsToShow = 10;
|
||||
|
||||
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.')];
|
||||
const executions: ExecutionList | undefined = await functionsClient.listExecutions(
|
||||
this.parent.func.$id,
|
||||
undefined,
|
||||
this.executionsToShow,
|
||||
undefined,
|
||||
"DESC"
|
||||
);
|
||||
const children = executions?.executions.map((execution: Execution) => new ExecutionTreeItem(this, execution)) ?? [
|
||||
new TreeItem("No executions."),
|
||||
];
|
||||
if (children.length === 0) {
|
||||
children.push(new TreeItem("No executions."));
|
||||
}
|
||||
ext.outputChannel.appendLog(`Found ${executions?.sum} executions`);
|
||||
if (executions?.sum ?? (0 > this.executionsToShow && this.executionsToShow !== 100)) {
|
||||
const viewMoreItem: TreeItem = {
|
||||
command: {
|
||||
command: "vscode-appwrite.viewMore",
|
||||
arguments: [this],
|
||||
title: "View more",
|
||||
},
|
||||
label: "View more...",
|
||||
};
|
||||
children.push(viewMoreItem);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
|
@ -24,4 +50,12 @@ export class ExecutionsTreeItem extends AppwriteTreeItemBase<FunctionTreeItem> {
|
|||
contextValue = "executions";
|
||||
|
||||
iconPath = new ThemeIcon("history");
|
||||
|
||||
async viewMore(): Promise<void> {
|
||||
this.executionsToShow += 10;
|
||||
if (this.executionsToShow > 100) {
|
||||
this.executionsToShow = 100;
|
||||
}
|
||||
ext.tree?.functions?.refreshChild(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Function } from "../../../appwrite";
|
|||
import { functionsClient } from "../../../client";
|
||||
import { appwriteSystemEvents } from "../../../constants";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { EnumEditableTreeItemBase } from "../../common/EnumEditableTreeItem";
|
||||
import { EnumEditableTreeItemBase } from "../../common/editable/EnumEditableTreeItem";
|
||||
import { FunctionSettingsTreeItem } from "./FunctionSettingsTreeItem";
|
||||
|
||||
export class EventsTreeItem extends EnumEditableTreeItemBase {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { Function } from "../../../appwrite";
|
||||
import { functionsClient } from "../../../client";
|
||||
import { AppwriteTreeItemBase } from "../../../ui/AppwriteTreeItemBase";
|
||||
import { AppwriteTreeItemBase } from '../../../ui/AppwriteTreeItemBase';
|
||||
import { ChildTreeItem } from "../../ChildTreeItem";
|
||||
import { FunctionTreeItem } from "../FunctionTreeItem";
|
||||
import { EventsTreeItem } from "./EventsTreeItem";
|
||||
|
|
|
@ -2,7 +2,7 @@ import { InputBoxOptions, MarkdownString } from "vscode";
|
|||
import { Function } from "../../../appwrite";
|
||||
import { functionsClient } from "../../../client";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { StringEditableTreeItemBase } from '../../common/StringEditableTreeItem';
|
||||
import { StringEditableTreeItemBase } from '../../common/editable/StringEditableTreeItem';
|
||||
import { FunctionSettingsTreeItem } from "./FunctionSettingsTreeItem";
|
||||
|
||||
const tooltip = "Function name";
|
||||
|
|
|
@ -5,7 +5,7 @@ import { ext } from "../../../extensionVariables";
|
|||
import cron from "cron-validate";
|
||||
import { FunctionSettingsTreeItem } from "./FunctionSettingsTreeItem";
|
||||
import cronstrue from "cronstrue";
|
||||
import { StringEditableTreeItemBase } from '../../common/StringEditableTreeItem';
|
||||
import { StringEditableTreeItemBase } from '../../common/editable/StringEditableTreeItem';
|
||||
|
||||
export class ScheduleTreeItem extends StringEditableTreeItemBase {
|
||||
private readonly func: Function;
|
||||
|
|
|
@ -2,7 +2,7 @@ import { InputBoxOptions, MarkdownString } from "vscode";
|
|||
import { Function } from "../../../appwrite";
|
||||
import { functionsClient } from "../../../client";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { StringEditableTreeItemBase } from "../../common/StringEditableTreeItem";
|
||||
import { StringEditableTreeItemBase } from "../../common/editable/StringEditableTreeItem";
|
||||
|
||||
function isNumeric(str: string) {
|
||||
console.log("here");
|
||||
|
|
|
@ -2,7 +2,7 @@ import { InputBoxOptions, MarkdownString, window } from "vscode";
|
|||
import { Function } from "../../../appwrite";
|
||||
import { functionsClient } from "../../../client";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { StringEditableTreeItemBase } from "../../common/StringEditableTreeItem";
|
||||
import { StringEditableTreeItemBase } from "../../common/editable/StringEditableTreeItem";
|
||||
import { VarsTreeItem } from "./VarsTreeItem";
|
||||
|
||||
const tooltip = "Environment var";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { TreeItem, TreeItemCollapsibleState } from "vscode";
|
||||
import { Vars } from "../../../appwrite";
|
||||
import { AppwriteTreeItemBase } from "../../../ui/AppwriteTreeItemBase";
|
||||
import { AppwriteTreeItemBase } from '../../../ui/AppwriteTreeItemBase';
|
||||
import { FunctionSettingsTreeItem } from "./FunctionSettingsTreeItem";
|
||||
import { VarTreeItem } from "./VarTreeItem";
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ export class TagTreeItem extends TreeItem {
|
|||
const active = func.tag === tag.$id;
|
||||
this.label = `${msToDate(tag.dateCreated)}${active ? ' (Active)' : ''}`;
|
||||
this.description = tag.$id;
|
||||
this.iconPath = new ThemeIcon(active ? 'circle-filled' : 'circle-outline');
|
||||
this.iconPath = new ThemeIcon(active ? 'circle-large-filled' : 'circle-large-outline');
|
||||
this.contextValue = `tag${active ? '_active' : ''}`;
|
||||
this.tooltip = new MarkdownString(`ID: ${tag.$id} \nCreated: ${msToDate(tag.dateCreated)} \nCommand: ${tag.command} \nSize: ${tag.size}B`);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,22 @@ export class TagsTreeItem extends AppwriteTreeItemBase<FunctionTreeItem> {
|
|||
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.')];
|
||||
const children = tags?.tags.sort((a, b) => b.dateCreated - a.dateCreated).map((tag) => new TagTreeItem(this, tag)) ?? [new TreeItem('No tags.')];
|
||||
|
||||
if (children.length === 0) {
|
||||
const noTagsItem: TreeItem = {
|
||||
command: {
|
||||
command: "vscode-appwrite.CreateTag",
|
||||
title: "Create tag",
|
||||
arguments: [this],
|
||||
tooltip: "Create a tag"
|
||||
},
|
||||
label: "Create a tag",
|
||||
iconPath: new ThemeIcon("cloud-upload"),
|
||||
};
|
||||
children.push(noTagsItem);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
collapsibleState = TreeItemCollapsibleState.Collapsed;
|
||||
|
|
|
@ -7,4 +7,7 @@ export abstract class AppwriteTreeItemBase<Parent = void> extends TreeItem {
|
|||
|
||||
abstract getChildren?(): Promise<TreeItem[]>;
|
||||
|
||||
viewMore(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,19 @@
|
|||
import { QuickPickItem, window } from "vscode";
|
||||
import { Collection, CollectionsList } from "../appwrite";
|
||||
import { client } from "../client";
|
||||
import { AppwriteSDK } from "../constants";
|
||||
import AppwriteCall from "../utils/AppwriteCall";
|
||||
|
||||
export type CreateRuleWizardContext = {
|
||||
label: string;
|
||||
key: string;
|
||||
type: keyof typeof ruleTypes;
|
||||
default: any;
|
||||
required: boolean;
|
||||
array: boolean;
|
||||
list?: string[];
|
||||
};
|
||||
|
||||
export async function createRuleWizard(): Promise<CreateRuleWizardContext | undefined> {
|
||||
const label = await window.showInputBox({
|
||||
placeHolder: "Label",
|
||||
prompt: "Attribute internal display name",
|
||||
});
|
||||
if (label === undefined) {
|
||||
return;
|
||||
}
|
||||
const key = await window.showInputBox({
|
||||
placeHolder: "Key",
|
||||
prompt: "Attribute key name. Used as the document JSON key in the Database API.",
|
||||
});
|
||||
if (key === undefined) {
|
||||
return;
|
||||
}
|
||||
const ruleTypeItems: QuickPickItem[] = Object.entries(ruleTypes).map(([label, description]) => ({
|
||||
label,
|
||||
description,
|
||||
}));
|
||||
|
||||
const type = await window.showQuickPick(ruleTypeItems);
|
||||
|
||||
if (type === undefined) {
|
||||
return;
|
||||
}
|
||||
if (label && key && type) {
|
||||
return { label, key, type: (type.label as unknown) as keyof typeof ruleTypes };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const ruleTypes = {
|
||||
text: "Any string value.",
|
||||
numeric: "Any integer or float value.",
|
||||
|
@ -45,6 +22,119 @@ const ruleTypes = {
|
|||
url: "Any valid URL.",
|
||||
email: "Any valid email address.",
|
||||
ip: "Any valid IP v4 or v6 address.",
|
||||
document:
|
||||
"Accept a valid child document. When using this type you are also required to pass the 'list' parameter with an array of the collections UID values of the document types you want to accept.",
|
||||
document: "Accept a valid child document from specified collection(s).",
|
||||
};
|
||||
|
||||
type RuleType = keyof typeof ruleTypes;
|
||||
|
||||
export async function createRuleWizard(collection: Collection): Promise<CreateRuleWizardContext | undefined> {
|
||||
const label = await window.showInputBox({
|
||||
placeHolder: "Attribute label",
|
||||
prompt: "Attribute internal display name",
|
||||
validateInput: (value) => {
|
||||
if (value === "") {
|
||||
return "Label cannot be empty.";
|
||||
}
|
||||
},
|
||||
});
|
||||
if (label === undefined) {
|
||||
return;
|
||||
}
|
||||
const key = await window.showInputBox({
|
||||
placeHolder: "Attribute key name",
|
||||
prompt: "Attribute key name. Used as the document JSON key in the Database API.",
|
||||
ignoreFocusOut: true,
|
||||
validateInput: (value) => {
|
||||
if (value === "") {
|
||||
return "Key name cannot be empty.";
|
||||
}
|
||||
},
|
||||
});
|
||||
if (key === undefined) {
|
||||
return;
|
||||
}
|
||||
const ruleTypeItems: QuickPickItem[] = Object.entries(ruleTypes).map(([label, description]) => ({
|
||||
label,
|
||||
detail: description,
|
||||
}));
|
||||
|
||||
const typeItem = await window.showQuickPick(ruleTypeItems, { placeHolder: "Rule value type." });
|
||||
const type: RuleType | undefined = (typeItem?.label as RuleType) ?? undefined;
|
||||
|
||||
if (typeItem === undefined || type === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let list: string[] | undefined = undefined;
|
||||
|
||||
if (type === "document") {
|
||||
const databaseSdk = new AppwriteSDK.Database(client);
|
||||
const collectionsList = await AppwriteCall<CollectionsList, CollectionsList>(databaseSdk.listCollections());
|
||||
|
||||
if (collectionsList === undefined) {
|
||||
window.showErrorMessage("Could not get collections list.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (collectionsList) {
|
||||
const collections = collectionsList.collections.filter((c) => c.$id !== collection.$id);
|
||||
const qpItems: QuickPickItem[] = collections.map((collection) => ({
|
||||
label: collection.name,
|
||||
description: collection.$id,
|
||||
}));
|
||||
|
||||
const listInput = await window.showQuickPick(qpItems, {
|
||||
canPickMany: true,
|
||||
placeHolder: "Collections which contain valid child documents for this document attribute.",
|
||||
ignoreFocusOut: true,
|
||||
});
|
||||
list = listInput?.map((item) => item.description as string) ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
if (label === "document" && list === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const array = await window.showQuickPick(["Primitive", "Array"], {
|
||||
placeHolder: "Decide if this rule is a primitive or an array of values.",
|
||||
ignoreFocusOut: true,
|
||||
});
|
||||
|
||||
if (array === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const required = await window.showQuickPick(["Required", "Optional"], {
|
||||
placeHolder: "Decide if this rule value is required in order to pass document validation.",
|
||||
ignoreFocusOut: true,
|
||||
});
|
||||
|
||||
if (required === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const defaultValue = await window.showInputBox({
|
||||
placeHolder: "Default value (press Enter to skip)",
|
||||
prompt: "Default value for this rule type. Make sure that the default value is able to pass validation in order to avoid errors when skipping optional values.",
|
||||
ignoreFocusOut: true,
|
||||
});
|
||||
|
||||
if (defaultValue === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (label && key && type) {
|
||||
return {
|
||||
label,
|
||||
key,
|
||||
type,
|
||||
default: defaultValue,
|
||||
array: array === "Array",
|
||||
required: required === "Required",
|
||||
list,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import dayjs = require('dayjs');
|
||||
import dayjs = require("dayjs");
|
||||
import utc = require("dayjs/plugin/utc");
|
||||
import timezone = require("dayjs/plugin/timezone"); // dependent on utc plugin
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
export function msToDate(ms: number): string {
|
||||
return dayjs(ms).format("LTS");
|
||||
return dayjs(ms * 1000).tz(dayjs.tz.guess()).format("LTS");
|
||||
}
|
||||
|
|
5
src/utils/sleep.ts
Normal file
5
src/utils/sleep.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
|
@ -2,8 +2,8 @@ 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 { sleep } from './sleep';
|
||||
|
||||
export async function getTarReadStream(folder: Uri): Promise<string | undefined> {
|
||||
try {
|
||||
|
@ -15,11 +15,14 @@ export async function getTarReadStream(folder: Uri): Promise<string | undefined>
|
|||
window.showErrorMessage("No workspace open.");
|
||||
return;
|
||||
}
|
||||
|
||||
ext.outputChannel.appendLog(`Creating '${tarName}' in '${workspace.workspaceFolders?.[0].uri.fsPath}'...`);
|
||||
const tarFilePath = path.join(ext.context?.globalStorageUri.fsPath ?? '', tarName);
|
||||
await workspace.fs.createDirectory(ext.context.globalStorageUri);
|
||||
|
||||
const tarFilePath = path.join(os.tmpdir(), tarName);
|
||||
tar.create({ gzip: true, cwd: cwd, mode: 1777 }, [path.relative(cwd, folder.fsPath)]).pipe(fs.createWriteStream(tarFilePath));
|
||||
|
||||
tar.create({ gzip: true, cwd: cwd }, [path.relative(cwd, folder.fsPath)]).pipe(fs.createWriteStream(tarFilePath));
|
||||
await sleep(500);
|
||||
|
||||
ext.outputChannel.appendLog(`Created ${tarFilePath}`);
|
||||
|
||||
|
|
6
src/utils/types.d.ts
vendored
Normal file
6
src/utils/types.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { Progress } from 'vscode';
|
||||
|
||||
export type ProgressMessage = Progress<{
|
||||
message?: string | undefined;
|
||||
increment?: number | undefined;
|
||||
}>;
|
Loading…
Reference in a new issue