Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: empty arrays UI #216

Merged
merged 12 commits into from
Feb 9, 2023
3 changes: 2 additions & 1 deletion src/lib/elements/forms/inputTags.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { last } from '$lib/helpers/array';
import { onMount } from 'svelte';
import { FormItem, Helper } from '.';

Expand Down Expand Up @@ -34,7 +35,7 @@
}
if (['Backspace', 'Delete'].includes(e.key)) {
if (value.length === 0) {
removeValue(tags[tags.length - 1]);
removeValue(last(tags));
}
}
};
Expand Down
35 changes: 35 additions & 0 deletions src/lib/helpers/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,38 @@ export function remove<T>(arr: T[], index: number): T[] {
// Remove the element at the given index, return a new array
return [...arr.slice(0, index), ...arr.slice(index + 1)];
}

/**
* Get nth item of Array. Negative for backward
*
* @export
* @template T
* @param {(readonly T[] | [])} array
* @param {number} index
* @returns {(T | undefined)}
*/
export function at(array: readonly [], index: number): undefined;
export function at<T>(array: readonly T[], index: number): T;
export function at<T>(array: readonly T[] | [], index: number): T | undefined {
const len = array.length;
if (!len) return undefined;

if (index < 0) index += len;

return array[index];
}

/**
* Get last item
* @date 12/12/2022 - 12:08:03 PM
*
* @export
* @template T
* @param {readonly T[]} array
* @returns {(T | undefined)}
*/
export function last(array: readonly []): undefined;
export function last<T>(array: readonly T[]): T;
export function last<T>(array: readonly T[]): T | undefined {
return at(array, -1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
$createDocument.attributes = $attributes.filter((a) => a.status === 'available');
$attributes.forEach((attr) => {
if (attr.array) {
$createDocument.document[attr.key] = [null];
$createDocument.document[attr.key] = [];
} else {
$createDocument.document[attr.key] = null;
}
Expand All @@ -39,12 +39,15 @@
$createDocument.document,
$createDocument.permissions
);

addNotification({
message: 'Document has been created',
type: 'success'
});
trackEvent('submit_document_create');
invalidate(Dependencies.DOCUMENTS);

createDocument.reset();
wizard.hide();
} catch (error) {
addNotification({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<script lang="ts">
import CustomId from '$lib/components/customId.svelte';
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 Attribute from './attribute.svelte';

export let attributes: Attributes[] = [];
export let formValues: object = {};
export let customId: string | null | undefined = undefined;
export let gap: '16' | '32' = '32';

let showCustomId = false;

function removeArrayItem(key: string, index: number) {
formValues = {
...formValues,
[key]: formValues[key].filter((_, i) => i !== index)
};
}

function addArrayItem(key: string) {
formValues = {
...formValues,
[key]: [...formValues[key], null]
};
}
</script>

{#if attributes.length}
<ul class={`form-list u-gap-${gap}`}>
{#each attributes as attribute}
{@const label = attribute.required ? `${attribute.key}*` : attribute.key}
{#if attribute.array}
{#if formValues[attribute.key].length === 0}
<div class="u-flex u-cross-center u-main-space-between">
<span class="label u-margin-0">{label}</span>
<Button text noMargin on:click={() => addArrayItem(attribute.key)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text"> Add item</span>
</Button>
</div>
{/if}

{#each [...formValues[attribute.key].keys()] as index}
<li class="form-item is-multiple">
<div class="form-item-part u-stretch">
<Attribute
{attribute}
id={`${attribute.key}-${index}`}
label={index === 0 ? label : ''}
bind:value={formValues[attribute.key][index]} />
</div>
<div class="form-item-part u-cross-child-end">
<Button text on:click={() => removeArrayItem(attribute.key, index)}>
<span class="icon-x" aria-hidden="true" />
</Button>
</div>
</li>
{/each}

{#if formValues[attribute.key].length !== 0}
<Button text noMargin on:click={() => addArrayItem(attribute.key)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text"> Add item</span>
</Button>
{/if}
{:else}
<FormList>
<Attribute
{attribute}
{label}
id={attribute.key}
bind:value={formValues[attribute.key]} />
</FormList>
{/if}
{/each}

{#if customId !== undefined}
{#if !showCustomId}
<div>
<Pill button on:click={() => (showCustomId = !showCustomId)}>
<span class="icon-pencil" aria-hidden="true" /><span class="text">
Document ID
</span>
</Pill>
</div>
{:else}
<CustomId bind:show={showCustomId} name="Document" bind:id={customId} />
{/if}
{/if}
</ul>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -42,7 +42,7 @@
currentDoc = JSON.stringify($work);
});

$: if (currentDoc && $work) {
$: {
if (currentDoc !== JSON.stringify($work)) {
disableUpdate = false;
} else {
Expand Down Expand Up @@ -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;
});
}
</script>

<CardGrid>
<Heading tag="h6" size="7">Update Data</Heading>
<p>Update document data based on the attributes created earlier.</p>
<svelte:fragment slot="aside">
<form class="form u-grid u-gap-16">
{#each $collection.attributes.filter((a) => a.status === 'available') as attribute}
{#if attribute.array}
<ul class="form-list">
{#each [...$work[attribute.key].keys()] as index}
<li class="form-item is-multiple">
<div class="form-item-part u-stretch">
<Attribute
{attribute}
id={`${attribute.key}-${index}`}
label={index === 0 ? attribute.key : ''}
bind:value={$work[attribute.key][index]} />
</div>
<div class="form-item-part u-cross-child-end">
<Button
text
disabled={$work[attribute.key].length === 1}
on:click={() => removeArrayItem(attribute.key, index)}>
<span class="icon-x" aria-hidden="true" />
</Button>
</div>
</li>
{:else}
<li class="form-item is-multiple">
<div class="form-item-part u-stretch">
<Attribute
{attribute}
id={`${attribute.key}-0`}
label={attribute.key}
bind:value={$work[attribute.key][0]} />
</div>
<div class="form-item-part u-cross-child-end">
<Button text disabled>
<span class="icon-x" aria-hidden="true" />
</Button>
</div>
</li>
{/each}
</ul>

<Button
text
noMargin
disabled={$work[attribute.key][$work[attribute.key].length - 1] === null}
on:click={() => addArrayItem(attribute.key)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Add item</span>
</Button>
{:else}
<ul class="form-list">
<Attribute
{attribute}
id={attribute.key}
label={attribute.key}
bind:value={$work[attribute.key]} />
</ul>
{/if}
{/each}
</form>
<AttributeForm attributes={$collection.attributes} bind:formValues={$work} gap="16" />
</svelte:fragment>

<svelte:fragment slot="actions">
Expand Down
Loading