Compare commits
15 commits
alex/creat
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
8b286657b0 | ||
|
6a2fbb956b | ||
|
f9d42ad703 | ||
|
e76dbc9e89 | ||
|
883893aaab | ||
|
47c405a9f5 | ||
|
2e77f93759 | ||
|
98a132fdef | ||
|
704bd72420 | ||
|
60a510b646 | ||
|
6bcbf57143 | ||
|
ac466375e5 | ||
|
bdff542ef9 | ||
|
38273dac92 | ||
|
185e1a98f4 |
11 changed files with 227 additions and 45 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
|
||||
|
|
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -6,8 +6,20 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.1.3] - 2021-6-17
|
||||
## Added
|
||||
- You can now easily create function tags from multiple places in the extension.
|
||||
- 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
|
||||
|
||||
|
|
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,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"
|
||||
},
|
||||
|
@ -726,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
8
src/appwrite.d.ts
vendored
8
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 = {
|
||||
|
|
|
@ -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,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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue