diff --git a/src/lib/actions/tooltip.ts b/src/lib/actions/tooltip.ts index 1636a14ecf..b4dc14a5f1 100644 --- a/src/lib/actions/tooltip.ts +++ b/src/lib/actions/tooltip.ts @@ -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> = (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(); 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} +
(array: readonly T[] | [], index: number): T | undefined { /** * Get last item - * @date 12/12/2022 - 12:08:03 PM * * @export * @template T diff --git a/src/lib/helpers/object.ts b/src/lib/helpers/object.ts new file mode 100644 index 0000000000..b22a35f2a3 --- /dev/null +++ b/src/lib/helpers/object.ts @@ -0,0 +1,75 @@ +/** + * Strict typed `Object.entries` + * Extracted from https://github.com/antfu/utils + * + * @category Object + */ +export function objectEntries(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]/[[page]]/+page.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/[[page]]/+page.svelte index 4aed513a9b..a5416a3231 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/[[page]]/+page.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/[[page]]/+page.svelte @@ -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; @@ -33,6 +34,44 @@ title: attribute.key })) ]; + + function formatArray(array: any[]) { + 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) { + 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 + }; + } @@ -70,8 +109,15 @@ {#each columns as column} + {@const formatted = formatColumn(document[column.key])} - {document[column.key] ?? 'n/a'} +
+ {formatted.value} +
{/each} 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..80ca275092 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} +