From 2fd3a6dc48a591b7742f04b8c5792376e1ec9471 Mon Sep 17 00:00:00 2001 From: tglide <26071571+TGlide@users.noreply.github.com> Date: Mon, 12 Dec 2022 17:46:29 +0000 Subject: [PATCH 1/9] feat: empty arrays UI --- src/lib/elements/forms/inputTags.svelte | 3 +- src/lib/helpers/array.ts | 35 ++++++ .../createDocument.svelte | 5 +- .../document-[document]/attributeForm.svelte | 94 ++++++++++++++++ .../document-[document]/document.svelte | 105 +++--------------- .../wizard/step1.svelte | 84 +------------- .../collection-[collection]/wizard/store.ts | 23 +++- 7 files changed, 174 insertions(+), 175 deletions(-) create mode 100644 src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributeForm.svelte diff --git a/src/lib/elements/forms/inputTags.svelte b/src/lib/elements/forms/inputTags.svelte index 93d31f8ac2..d9150dc6fe 100644 --- a/src/lib/elements/forms/inputTags.svelte +++ b/src/lib/elements/forms/inputTags.svelte @@ -1,4 +1,5 @@ + +{#if attributes.length} + +{/if} diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/document.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/document.svelte index 56f36a8bfe..d18b264e91 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/document.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/document.svelte @@ -11,27 +11,27 @@ import type { Models } from '@aw-labs/appwrite-console'; import { Dependencies } from '$lib/constants'; import { invalidate } from '$app/navigation'; - import Attribute from './attribute.svelte'; import { trackEvent } from '$lib/actions/analytics'; + import AttributeForm from './attributeForm.svelte'; let disableUpdate = true; let currentDoc: string; const databaseId = $page.params.database; const collectionId = $page.params.collection; const documentId = $page.params.document; + const work = writable( Object.keys($doc) - .filter( - (key) => - ![ - '$id', - '$collection', - '$collectionId', - '$databaseId', - '$createdAt', - '$updatedAt' - ].includes(key) - ) + .filter((key) => { + return ![ + '$id', + '$collection', + '$collectionId', + '$databaseId', + '$createdAt', + '$updatedAt' + ].includes(key); + }) .reduce((obj, key) => { obj[key] = $doc[key]; return obj; @@ -42,7 +42,7 @@ currentDoc = JSON.stringify($work); }); - $: if (currentDoc && $work) { + $: { if (currentDoc !== JSON.stringify($work)) { disableUpdate = false; } else { @@ -77,90 +77,13 @@ }); } } - - function addArrayItem(key: string) { - work.update((n) => { - if (!Array.isArray(n[key])) { - n[key] = []; - } - n[key].push(null); - - return n; - }); - } - - function removeArrayItem(key: string, index: number) { - work.update((n) => { - n[key].splice(index, 1); - - return n; - }); - } Update Data

Update document data based on the attributes created earlier.

-
- {#each $collection.attributes.filter((a) => a.status === 'available') as attribute} - {#if attribute.array} -
    - {#each [...$work[attribute.key].keys()] as index} -
  • -
    - -
    -
    - -
    -
  • - {:else} -
  • -
    - -
    -
    - -
    -
  • - {/each} -
- - - {:else} -
    - -
- {/if} - {/each} -
+
diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/step1.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/step1.svelte index e9da370254..1df88ae0c0 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/step1.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/step1.svelte @@ -1,28 +1,7 @@ @@ -31,61 +10,8 @@ Provide document data based on attributes you created earlier. - {#if $createDocument.attributes.length} - - {#each $createDocument.attributes as attribute} - {@const label = attribute.required ? `${attribute.key}*` : attribute.key} - {#if attribute.array} - {#each [...$createDocument.document[attribute.key].keys()] as index} -
  • -
    - -
    -
    - -
    -
  • - {/each} - - {:else} - - - - {/if} - {/each} - {#if !showCustomId} -
    - (showCustomId = !showCustomId)}> - -
    - {:else} - - {/if} -
    - {/if} + diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/store.ts b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/store.ts index eea1073072..04cd8ed9f1 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/store.ts +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/wizard/store.ts @@ -1,14 +1,31 @@ import { writable } from 'svelte/store'; import type { Attributes } from '../store'; -export const createDocument = writable<{ +type CreateDocument = { id?: string; document: object; permissions: string[]; attributes: Attributes[]; -}>({ +}; + +const initialCreateDocument: CreateDocument = { id: null, document: {}, permissions: [], attributes: [] -}); +}; + +function createDocumentWritable() { + const store = writable({ ...initialCreateDocument }); + + const reset = () => { + store.set({ ...initialCreateDocument }); + }; + + return { + ...store, + reset + }; +} + +export const createDocument = createDocumentWritable(); From 7c784f78afef3dc9006109bd6c8c774070e151a1 Mon Sep 17 00:00:00 2001 From: tglide <26071571+TGlide@users.noreply.github.com> Date: Mon, 12 Dec 2022 17:49:26 +0000 Subject: [PATCH 2/9] chore: remove date on array jsdoc --- src/lib/helpers/array.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/helpers/array.ts b/src/lib/helpers/array.ts index 47bddeb771..57468b22dc 100644 --- a/src/lib/helpers/array.ts +++ b/src/lib/helpers/array.ts @@ -50,7 +50,6 @@ export function at(array: readonly T[] | [], index: number): T | undefined { /** * Get last item - * @date 12/12/2022 - 12:08:03 PM * * @export * @template T From f1b4205fe67d690ddee7627ba474029b07abcfd9 Mon Sep 17 00:00:00 2001 From: tglide <26071571+TGlide@users.noreply.github.com> Date: Mon, 12 Dec 2022 18:38:10 +0000 Subject: [PATCH 3/9] feat: add attribute types to input labels --- src/lib/elements/forms/inputCheckbox.svelte | 3 + src/lib/elements/forms/inputDateTime.svelte | 3 + src/lib/elements/forms/inputNumber.svelte | 3 + src/lib/elements/forms/inputSelect.svelte | 3 + src/lib/elements/forms/inputText.svelte | 7 +- src/lib/helpers/object.ts | 75 +++++++++++++++++++ src/lib/helpers/string.ts | 10 +++ .../document-[document]/attribute.svelte | 3 + .../document-[document]/attributeForm.svelte | 55 +++++++++----- .../attributes/boolean.svelte | 4 +- .../attributes/datetime.svelte | 9 ++- .../attributes/enum.svelte | 2 + .../attributes/integer.svelte | 2 + .../attributes/string.svelte | 2 + .../collection-[collection]/store.ts | 7 ++ tests/unit/helpers/object.test.ts | 74 ++++++++++++++++++ 16 files changed, 239 insertions(+), 23 deletions(-) create mode 100644 src/lib/helpers/object.ts create mode 100644 src/lib/helpers/string.ts create mode 100644 tests/unit/helpers/object.test.ts diff --git a/src/lib/elements/forms/inputCheckbox.svelte b/src/lib/elements/forms/inputCheckbox.svelte index cecc2a4419..62de5ec3ee 100644 --- a/src/lib/elements/forms/inputCheckbox.svelte +++ b/src/lib/elements/forms/inputCheckbox.svelte @@ -2,6 +2,7 @@ import { FormItem, Helper } from '.'; export let label: string; + export let optionalText: string | undefined = undefined; export let showLabel = true; export let id: string; export let value = false; @@ -27,6 +28,8 @@ + {optionalText} +
    + {optionalText} +
    + {optionalText} +
    + {optionalText} +
    (obj: T) { + return Object.entries(obj) as Array<[keyof T, T[keyof T]]>; +} + +type KeyTypesMap = Record | ((v: unknown) => boolean) | string>; +/** + * Checks if the given value is an object of type T, given a map of keys and + * their types/validators. + * + * @category Object + * + * @template T + * @param {unknown} object + * @param {KeyTypesMap} keyTypesMap + * @returns {value is T} + * + * @example + * ``` + * type ExampleType = { + * a: string; + * b: number; + * c: string | number; + * d: string[] + * e: { + * f: string; + * g: number; + * } + * } + * + * export const isExampleType = (value: unknown): value is ExampleType => { + * return isObjectType(value, { + * a: 'string', + * b: 'number', + * c: ['string', 'number'], + * d: (v) => Array.isArray(v) && v.every((v) => typeof v === 'string'), + * e: (v) => isObjectType(v, { + * f: 'string', + * g: 'number', + * }), + * }); + * }; + * ``` + */ +export const isObjectType = ( + object: unknown, + keyTypesMap: Partial> +): object is T => { + if (typeof object !== 'object' || object === null) { + return false; + } + + for (const [key, check] of objectEntries(keyTypesMap)) { + const value = (object as Record)[key]; + + if (typeof check === 'function') { + if (!check(value)) { + return false; + } + } else if (typeof check === 'string') { + if (typeof value !== check) { + return false; + } + } else if (!check.includes(typeof value)) { + return false; + } + } + + return true; +}; diff --git a/src/lib/helpers/string.ts b/src/lib/helpers/string.ts new file mode 100644 index 0000000000..e67be0e074 --- /dev/null +++ b/src/lib/helpers/string.ts @@ -0,0 +1,10 @@ +/** + * Capitalizes the first letter of a string + * + * @export + * @param {string} str + * @returns {string} + */ +export function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attribute.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attribute.svelte index 1a390b645c..80c66eb4bc 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attribute.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attribute.svelte @@ -9,6 +9,7 @@ export let id: string; export let label: string; export let value: string | number | boolean; + export let optionalText: string | undefined = undefined; export let attribute: | Models.AttributeBoolean | Models.AttributeEmail @@ -43,6 +44,7 @@ {id} {label} {attribute} + {optionalText} bind:value /> {:else} {/if} {/if} diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributeForm.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributeForm.svelte index 7cb95c5ab3..0cd78ae5d6 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributeForm.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/document-[document]/attributeForm.svelte @@ -3,7 +3,8 @@ import { FormList } from '$lib/elements/forms'; import Button from '$lib/elements/forms/button.svelte'; import Pill from '$lib/elements/pill.svelte'; - import type { Attributes } from '../store'; + import { capitalize } from '$lib/helpers/string'; + import { isAttributeEnum, type Attributes } from '../store'; import Attribute from './attribute.svelte'; export let attributes: Attributes[] = []; @@ -26,6 +27,11 @@ [key]: [...formValues[key], null] }; } + + function getAttributeType(attribute: Attributes) { + if (isAttributeEnum(attribute)) return 'Enum'; + return `${capitalize(attribute.type)}${attribute.array ? '[]' : ''}`; + } {#if attributes.length} @@ -35,7 +41,11 @@ {#if attribute.array} {#if formValues[attribute.key].length === 0}
    - {label} +
    + {label} + {getAttributeType(attribute)} +
    +
    {/if} - {#each [...formValues[attribute.key].keys()] as index} -
  • -
    - -
    -
    - -
    -
  • - {/each} - {#if formValues[attribute.key].length !== 0} +
      + {#each [...formValues[attribute.key].keys()] as index} +
    • +
      + +
      +
      + +
      +
    • + {/each} +