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
11 changes: 9 additions & 2 deletions src/lib/actions/tooltip.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import type { Action } from 'svelte/action';
import type { Props } from 'tippy.js';
import type { Props as TippyProps } from 'tippy.js';
import tippy from 'tippy.js';

type Props = TippyProps & {
disabled?: boolean;
};

export const tooltip: Action<HTMLElement, Partial<Props>> = (node, config) => {
const instance = tippy(node, config);
if (config.disabled) instance.disable();

return {
update({ content }) {
update({ content, disabled }) {
if (content !== instance.props.content) {
instance.setProps({
content
});
}

disabled ? instance.disable() : instance.enable();
},
destroy() {
instance.destroy();
Expand Down
9 changes: 8 additions & 1 deletion src/lib/elements/forms/inputCheckbox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,7 +27,13 @@
</script>

<FormItem>
<label class:u-hide={!showLabel} class="label" for={id}>{label}</label>
<label class:u-hide={!showLabel} class="label" for={id}>
{label}
<span class:u-hide={!showLabel || !optionalText} class="optional">
{optionalText}
</span>
</label>

<div class="input-text-wrapper">
<input
{id}
Expand Down
9 changes: 8 additions & 1 deletion src/lib/elements/forms/inputDateTime.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

export let label: string;
export let showLabel = true;
export let optionalText: string | undefined = undefined;
export let id: string;
export let value = '';
export let required = false;
Expand Down Expand Up @@ -38,7 +39,13 @@
</script>

<FormItem>
<label class:u-hide={!showLabel} class="label" for={id}>{label}</label>
<label class:u-hide={!showLabel} class="label" for={id}>
{label}
<span class:u-hide={!showLabel || !optionalText} class="optional">
{optionalText}
</span>
</label>

<div class="input-text-wrapper">
<input
{id}
Expand Down
9 changes: 8 additions & 1 deletion src/lib/elements/forms/inputNumber.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,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: number = null;
Expand Down Expand Up @@ -51,7 +52,13 @@
</script>

<FormItem>
<label class:u-hide={!showLabel} class="label" for={id}>{label}</label>
<label class:u-hide={!showLabel} class="label" for={id}>
{label}
<span class:u-hide={!showLabel || !optionalText} class="optional">
{optionalText}
</span>
</label>

<div class="input-text-wrapper">
<input
{id}
Expand Down
9 changes: 8 additions & 1 deletion src/lib/elements/forms/inputSelect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

export let id: string;
export let label: string;
export let optionalText: string | undefined = undefined;
export let showLabel = true;
export let value: string | number | boolean;
export let placeholder = '';
Expand Down Expand Up @@ -32,7 +33,13 @@
</script>

<FormItem>
<label class:u-hide={!showLabel} class="label" for={id}>{label}</label>
<label class:u-hide={!showLabel} class="label" for={id}>
{label}
<span class:u-hide={!showLabel || !optionalText} class="optional">
{optionalText}
</span>
</label>

<div class="select">
<select
{id}
Expand Down
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 @@ -36,7 +37,7 @@
}
if (['Backspace', 'Delete'].includes(e.key)) {
if (value.length === 0) {
removeValue(tags[tags.length - 1]);
removeValue(last(tags));
}
}
};
Expand Down
7 changes: 5 additions & 2 deletions src/lib/elements/forms/inputText.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,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 = '';
Expand Down Expand Up @@ -42,8 +43,8 @@
</script>

<FormItem>
<label class:u-hide={!showLabel} class="label" for={id}
>{label}
<label class:u-hide={!showLabel} class="label" for={id}>
{label}
{#if tooltip}
<span
class="icon-info"
Expand All @@ -52,7 +53,9 @@
content: tooltip
}} />
{/if}
<span class:u-hide={!showLabel || !optionalText} class="optional">{optionalText}</span>
</label>

<div class="input-text-wrapper">
<input
{id}
Expand Down
34 changes: 34 additions & 0 deletions src/lib/helpers/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,37 @@ 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
*
* @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);
}
75 changes: 75 additions & 0 deletions src/lib/helpers/object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Strict typed `Object.entries`
* Extracted from https://github.com/antfu/utils
*
* @category Object
*/
export function objectEntries<T extends object>(obj: T) {
return Object.entries(obj) as Array<[keyof T, T[keyof T]]>;
}

type KeyTypesMap<T> = Record<keyof T, Array<string> | ((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 = <T>(
object: unknown,
keyTypesMap: Partial<KeyTypesMap<T>>
): object is T => {
if (typeof object !== 'object' || object === null) {
return false;
}

for (const [key, check] of objectEntries(keyTypesMap)) {
const value = (object as Record<keyof T, unknown>)[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;
};
10 changes: 10 additions & 0 deletions src/lib/helpers/string.ts
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import { page } from '$app/stores';
import { PAGE_LIMIT } from '$lib/constants';
import CreateAttribute from '../createAttribute.svelte';
import { tooltip } from '$lib/actions/tooltip';

export let data: PageData;
let showCreateAttribute = false;
Expand All @@ -33,6 +34,44 @@
title: attribute.key
}))
];

function formatArray(array: any[]) {
TGlide marked this conversation as resolved.
Show resolved Hide resolved
if (array.length === 0) return '[ ]';

let formattedFields: string[] = [];
for (const item of array) {
if (typeof item === 'string') {
formattedFields.push(`"${item}"`);
} else {
formattedFields.push(`${item}`);
}
}

return `[${formattedFields.join(', ')}]`;
}

function formatColumn(column: any) {
TGlide marked this conversation as resolved.
Show resolved Hide resolved
let formattedColumn: string;

if (typeof column === 'string') {
formattedColumn = column;
} else if (Array.isArray(column)) {
formattedColumn = formatArray(column);
} else if (!column) {
formattedColumn = 'n/a';
} else {
formattedColumn = `${column}`;
}

return {
value:
formattedColumn.length > 20
? `${formattedColumn.slice(0, 20)}...`
: formattedColumn,
truncated: formattedColumn.length > 20,
whole: formattedColumn
};
}
</script>

<Container>
Expand Down Expand Up @@ -70,8 +109,15 @@
</Copy>
</TableCell>
{#each columns as column}
{@const formatted = formatColumn(document[column.key])}
<TableCell>
{document[column.key] ?? 'n/a'}
<div
use:tooltip={{
content: formatted.whole,
disabled: !formatted.truncated
}}>
{formatted.value}
</div>
</TableCell>
{/each}
</TableRowLink>
Expand Down
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
Loading