This commit is contained in:
alexweininger 2021-04-22 00:23:32 -07:00
parent 045342f813
commit 799da899ae
9 changed files with 6944 additions and 6847 deletions

View file

@ -1,4 +1,6 @@
# vscode-appwrite # Appwrite for Visual Studio Code
Use the Appwrite extension to quickly monitor, manage, and interact with your Appwrite instance directly from VS Code.
## What is Appwrite? ## What is Appwrite?
@ -10,17 +12,20 @@ From [appwrite.io](https://appwrite.io)
## Features ## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace: For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\) ### Check the health of all the Appwrite services.
![Health feature](./media/features/health/scr1.png)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow. > Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements ## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them. This extension does not provide features for setting up or installing Appwrite. Only managing and interacting with Appwrite once it's running.
## Extension Settings ## Extension Settings
@ -43,15 +48,8 @@ Users appreciate release notes as you update your extension.
### 1.0.0 ### 1.0.0
Initial release of ... Initial release of the Appwrite extension for VS Code
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
----------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------
## Following extension guidelines ## Following extension guidelines

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

13
package-lock.json generated
View file

@ -7,6 +7,7 @@
"": { "": {
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"dayjs": "^1.10.4",
"fs-extra": "^9.1.0", "fs-extra": "^9.1.0",
"node-appwrite": "^2.1.0" "node-appwrite": "^2.1.0"
}, },
@ -1012,6 +1013,7 @@
"dependencies": { "dependencies": {
"anymatch": "~3.1.1", "anymatch": "~3.1.1",
"braces": "~3.0.2", "braces": "~3.0.2",
"fsevents": "~2.3.1",
"glob-parent": "~5.1.0", "glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0", "is-binary-path": "~2.1.0",
"is-glob": "~4.0.1", "is-glob": "~4.0.1",
@ -1126,6 +1128,11 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/dayjs": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz",
"integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw=="
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@ -2268,6 +2275,7 @@
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dependencies": { "dependencies": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0" "universalify": "^2.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
@ -4798,6 +4806,11 @@
"which": "^2.0.1" "which": "^2.0.1"
} }
}, },
"dayjs": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz",
"integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw=="
},
"debug": { "debug": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",

View file

@ -6,6 +6,9 @@
"engines": { "engines": {
"vscode": "^1.55.0" "vscode": "^1.55.0"
}, },
"repository": {
"url": "https://github.com/streamlux/vscode-appwrite"
},
"categories": [ "categories": [
"Other" "Other"
], ],
@ -78,7 +81,12 @@
"icon": "$(refresh)" "icon": "$(refresh)"
}, },
{ {
"command": "vscode-appwrite.OpenDocumentation", "command": "vscode-appwrite.OpenUsersDocumentation",
"title": "Open documentation",
"icon": "$(book)"
},
{
"command": "vscode-appwrite.OpenDatabaseDocumentation",
"title": "Open documentation", "title": "Open documentation",
"icon": "$(book)" "icon": "$(book)"
}, },
@ -136,6 +144,16 @@
"command": "vscode-appwrite.editPermission", "command": "vscode-appwrite.editPermission",
"title": "Edit permission", "title": "Edit permission",
"icon": "$(edit)" "icon": "$(edit)"
},
{
"command": "vscode-appwrite.refreshHealth",
"title": "Refresh health",
"icon": "$(refresh)"
},
{
"command": "vscode-appwrite.openHealthDocumentation",
"title": "Open health documentation",
"icon": "$(book)"
} }
], ],
"views": { "views": {
@ -171,10 +189,15 @@
"menus": { "menus": {
"view/title": [ "view/title": [
{ {
"command": "vscode-appwrite.OpenDocumentation", "command": "vscode-appwrite.OpenUsersDocumentation",
"when": "view == Users", "when": "view == Users",
"group": "navigation" "group": "navigation"
}, },
{
"command": "vscode-appwrite.OpenDatabaseDocumentation",
"when": "view == Database",
"group": "navigation"
},
{ {
"command": "vscode-appwrite.refreshUsersList", "command": "vscode-appwrite.refreshUsersList",
"when": "view == Users", "when": "view == Users",
@ -194,6 +217,16 @@
"command": "vscode-appwrite.createCollection", "command": "vscode-appwrite.createCollection",
"when": "view == Database", "when": "view == Database",
"group": "navigation" "group": "navigation"
},
{
"command": "vscode-appwrite.refreshHealth",
"when": "view == Health",
"group": "navigation"
},
{
"command": "vscode-appwrite.openHealthDocumentation",
"when": "view == Health",
"group": "navigation"
} }
], ],
"view/item/context": [ "view/item/context": [
@ -292,7 +325,7 @@
{ {
"id": "Appwrite", "id": "Appwrite",
"title": "Appwrite", "title": "Appwrite",
"icon": "resources/vscode-appwrite.svg" "icon": "./resources/vscode-appwrite.svg"
} }
] ]
}, },
@ -302,7 +335,7 @@
"appwrite.projects": { "appwrite.projects": {
"type": "array", "type": "array",
"default": [], "default": [],
"description": "List of Appwrite projects" "markdownDescription": "List of Appwrite project configurations. You can use the Connect command to set this up, or see [docs](https://github.com/streamlux/vscode-appwrite/) for more information."
} }
} }
} }
@ -336,6 +369,7 @@
"webpack-cli": "^4.4.0" "webpack-cli": "^4.4.0"
}, },
"dependencies": { "dependencies": {
"dayjs": "^1.10.4",
"fs-extra": "^9.1.0", "fs-extra": "^9.1.0",
"node-appwrite": "^2.1.0" "node-appwrite": "^2.1.0"
} }

View file

@ -1,3 +1,4 @@
import { MarkdownString } from 'vscode';
import { AppwriteHealth, Client, HealthClient, SDK } from "../appwrite"; import { AppwriteHealth, Client, HealthClient, SDK } from "../appwrite";
const sdk: SDK = require("node-appwrite"); const sdk: SDK = require("node-appwrite");
@ -28,3 +29,20 @@ export class Health {
}; };
} }
} }
export const healthTooltips: Record<keyof AppwriteHealth, string | MarkdownString | undefined> = {
HTTP: "Check the Appwrite HTTP server is up and responsive.",
DB: "Check the Appwrite in-memory cache server is up and connection is successful.",
Cache: "Check the Appwrite in-memory cache server is up and connection is successful.",
Time:
new MarkdownString("Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol (NTP)](https://en.wikipedia.org/wiki/Network_Time_Protocol) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP."),
QueueWebhooks: "The number of webhooks that are waiting to be processed in the Appwrite internal queue server.",
QueueTasks: "The number of tasks that are waiting to be processed in the Appwrite internal queue server.",
QueueLogs: "The number of logs that are waiting to be processed in the Appwrite internal queue server.",
QueueUsage: "The number of usage stats that are waiting to be processed in the Appwrite internal queue server.",
QueueCertificates:
new MarkdownString("The number of certificates that are waiting to be issued against [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue server."),
QueueFunctions: "The number of functions waiting to be executed.",
StorageLocal: "Check the Appwrite local storage device is up and connection is successful.",
AntiVirus: "Check the Appwrite Anti Virus server is up and connection is successful.",
};

View file

@ -1,7 +1,14 @@
import { openUrl } from '../utils/openUrl'; import { openUrl } from '../utils/openUrl';
const appwriteDocsUrl = 'https://appwrite.io/docs'; const documentationLinks = {
home: 'https://appwrite.io/docs',
users: 'https://appwrite.io/docs/server/users',
database: 'https://appwrite.io/docs/client/database',
health: 'https://appwrite.io/docs/server/health'
};
export async function openDocumentation(): Promise<void> { type DocsPage = keyof typeof documentationLinks;
await openUrl(appwriteDocsUrl);
export async function openDocumentation(page?: DocsPage): Promise<void> {
await openUrl(documentationLinks[page || 'home']);
} }

View file

@ -52,7 +52,8 @@ export function registerCommands(context: ExtensionContext): void {
registerCommand("CreateUser", createUser); registerCommand("CreateUser", createUser);
registerCommand("refreshUsersList", refreshUsersList); registerCommand("refreshUsersList", refreshUsersList);
registerCommand("DeleteUser", deleteUser); registerCommand("DeleteUser", deleteUser);
registerCommand("OpenDocumentation", openDocumentation); registerCommand("OpenUsersDocumentation", () => openDocumentation('users'));
registerCommand("OpenDatabaseDocumentation", () => openDocumentation('database'));
registerCommand("GetUserLogs", getUserLogs); registerCommand("GetUserLogs", getUserLogs);
registerCommand("viewDocumentAsJson", viewDocumentAsJson); registerCommand("viewDocumentAsJson", viewDocumentAsJson);
registerCommand("AddProject", addProject); registerCommand("AddProject", addProject);
@ -66,4 +67,6 @@ export function registerCommands(context: ExtensionContext): void {
registerCommand("createCollection", createCollection, 'database'); registerCommand("createCollection", createCollection, 'database');
registerCommand("createPermission", createPermission, 'database'); registerCommand("createPermission", createPermission, 'database');
registerCommand("deletePermission", deletePermission, 'database'); registerCommand("deletePermission", deletePermission, 'database');
registerCommand("refreshHealth", () => {}, 'health');
registerCommand("openHealthDocumentation", () => openDocumentation('health'));
} }

View file

@ -1,11 +1,15 @@
import * as vscode from "vscode"; import * as vscode from "vscode";
import { MarkdownString } from 'vscode';
export class HealthTreeItem extends vscode.TreeItem { export class HealthTreeItem extends vscode.TreeItem {
constructor(public readonly label: string, status: boolean) { constructor(public readonly label: string, status: any, tooltip?: string | MarkdownString | undefined) {
super(label); super(label);
console.log(status);
this.label = label; this.label = label;
this.iconPath = new vscode.ThemeIcon(status ? "check" : "error", new vscode.ThemeColor(status ? "#00ff00" : "list.errorForeground")); this.iconPath = new vscode.ThemeIcon(status ? "check" : "error", new vscode.ThemeColor(status ? "#00ff00" : "list.errorForeground"));
this.contextValue = `health.${label}`; this.contextValue = `health.${label}`;
this.description = "" + Object.values(status)[0];
this.tooltip = tooltip;
} }
contextValue = "health"; contextValue = "health";

View file

@ -1,12 +1,24 @@
import * as vscode from "vscode"; import * as vscode from "vscode";
import { healthClient } from "../../client"; import { healthClient } from "../../client";
import { ext } from "../../extensionVariables";
import { HealthTreeItem } from "./HealthTreeItem"; import { HealthTreeItem } from "./HealthTreeItem";
import * as dayjs from "dayjs";
import * as relativeTime from "dayjs/plugin/relativeTime";
import * as localizedFormat from "dayjs/plugin/localizedFormat";
import { healthTooltips } from "../../appwrite/Health";
import { AppwriteHealth } from "../../appwrite";
// dayjs.extend(relativeTime);
dayjs.extend(localizedFormat);
type PartialRecord<K extends string | number | symbol, T> = { [P in K]?: T };
export class HealthTreeItemProvider implements vscode.TreeDataProvider<vscode.TreeItem> { export class HealthTreeItemProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
private _onDidChangeTreeData: vscode.EventEmitter<HealthTreeItem | undefined | void> = new vscode.EventEmitter< private _onDidChangeTreeData: vscode.EventEmitter<HealthTreeItem | undefined | void> = new vscode.EventEmitter<
HealthTreeItem | undefined | void HealthTreeItem | undefined | void
>(); >();
private lastChecked: Date = new Date();
readonly onDidChangeTreeData: vscode.Event<HealthTreeItem | undefined | void> = this._onDidChangeTreeData.event; readonly onDidChangeTreeData: vscode.Event<HealthTreeItem | undefined | void> = this._onDidChangeTreeData.event;
constructor() {} constructor() {}
@ -23,9 +35,17 @@ export class HealthTreeItemProvider implements vscode.TreeDataProvider<vscode.Tr
// get children for root // get children for root
if (element === undefined) { if (element === undefined) {
const health = await healthClient.checkup(); const health = await healthClient.checkup();
return Object.entries(health).map(([service, status]) => { ext.outputChannel?.append(JSON.stringify(health, null, 4));
return new HealthTreeItem(service, status); const healthItems = Object.entries(health).map(([service, status]) => {
return new HealthTreeItem(service, status, healthTooltips[service as keyof AppwriteHealth]);
}); });
this.lastChecked = new Date();
return [
{
label: `Updated at ${dayjs(this.lastChecked).format("LTS")}`,
},
...healthItems,
];
} }
return []; return [];
} }