diff --git a/src/lib/components/floatingActionBar.svelte b/src/lib/components/floatingActionBar.svelte new file mode 100644 index 0000000000..5f25bad40a --- /dev/null +++ b/src/lib/components/floatingActionBar.svelte @@ -0,0 +1,37 @@ + + +{#if show} +
+ +
+{/if} + + diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts index 411e81f48e..581b391467 100644 --- a/src/lib/components/index.ts +++ b/src/lib/components/index.ts @@ -54,5 +54,5 @@ export { default as ClickableListItem } from './clickableListItem.svelte'; export { default as Id } from './id.svelte'; export { default as EyebrowHeading } from './eyebrowHeading.svelte'; export { default as SvgIcon } from './svgIcon.svelte'; - export { default as MigrationBox } from './migrationBox.svelte'; +export { default as FloatingActionBar } from './floatingActionBar.svelte'; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index ccdf6c6a09..e2bb2fb6f9 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -34,7 +34,8 @@ export enum Dependencies { DOMAINS = 'dependency:domains', WEBHOOK = 'dependency:webhook', WEBHOOKS = 'dependency:webhooks', - MIGRATIONS = 'dependency:migrations' + MIGRATIONS = 'dependency:migrations', + COLLECTIONS = 'dependency:collections' } export const scopes: { diff --git a/src/lib/elements/forms/inputCheckbox.svelte b/src/lib/elements/forms/inputCheckbox.svelte index b8c601635b..601607e594 100644 --- a/src/lib/elements/forms/inputCheckbox.svelte +++ b/src/lib/elements/forms/inputCheckbox.svelte @@ -1,11 +1,12 @@ - + {#if label} + + {/if}
+ on:invalid={handleInvalid} + on:click />
{#if error} {error} diff --git a/src/lib/elements/table/cellCheck.svelte b/src/lib/elements/table/cellCheck.svelte new file mode 100644 index 0000000000..3c55aa395e --- /dev/null +++ b/src/lib/elements/table/cellCheck.svelte @@ -0,0 +1,29 @@ + + + + { + // Prevent the link from being followed + e.preventDefault(); + const el = e.currentTarget; + if (!isHTMLInputElement(el)) return; + + selectedIds = toggle(selectedIds, id); + + // Hack to make sure the checkbox is checked, independent of the + // preventDefault() call above + window.setTimeout(() => { + el.checked = selectedIds.includes(id); + }); + }} /> + diff --git a/src/lib/elements/table/cellHeadCheck.svelte b/src/lib/elements/table/cellHeadCheck.svelte new file mode 100644 index 0000000000..9ef8a22d70 --- /dev/null +++ b/src/lib/elements/table/cellHeadCheck.svelte @@ -0,0 +1,33 @@ + + + + + diff --git a/src/lib/elements/table/index.ts b/src/lib/elements/table/index.ts index c702ca6450..ca4752e8af 100644 --- a/src/lib/elements/table/index.ts +++ b/src/lib/elements/table/index.ts @@ -9,6 +9,8 @@ export { default as TableRowLink } from './rowLink.svelte'; export { default as TableRowButton } from './rowButton.svelte'; export { default as TableCell } from './cell.svelte'; export { default as TableCellHead } from './cellHead.svelte'; +export { default as TableCellHeadCheck } from './cellHeadCheck.svelte'; export { default as TableCellLink } from './cellLink.svelte'; export { default as TableCellAvatar } from './cellAvatar.svelte'; export { default as TableCellText } from './cellText.svelte'; +export { default as TableCellCheck } from './cellCheck.svelte'; diff --git a/src/lib/elements/table/tableScroll.svelte b/src/lib/elements/table/tableScroll.svelte index 6d30f8aff8..01b4186a71 100644 --- a/src/lib/elements/table/tableScroll.svelte +++ b/src/lib/elements/table/tableScroll.svelte @@ -2,6 +2,7 @@ import type { Action } from 'svelte/action'; export let isSticky = false; + export let noMargin = false; let isOverflowing = false; const hasOverflow: Action = (node) => { @@ -37,8 +38,8 @@ }; -
-
+
+
(isOverflowing = v)}>
diff --git a/src/lib/helpers/array.ts b/src/lib/helpers/array.ts index a325e33f5c..6690dd1dfc 100644 --- a/src/lib/helpers/array.ts +++ b/src/lib/helpers/array.ts @@ -88,3 +88,11 @@ export function excludeArray( export function includesAll(arr1: T[], arr2: T[]): boolean { return arr2.every((elem) => arr1.includes(elem)); } + +export function toggle(arr: T[], elem: T): T[] { + if (arr.includes(elem)) { + return arr.filter((e) => e !== elem); + } + arr.push(elem); + return arr; +} diff --git a/src/lib/helpers/types.ts b/src/lib/helpers/types.ts index 344bc6af50..5c5ffec06d 100644 --- a/src/lib/helpers/types.ts +++ b/src/lib/helpers/types.ts @@ -1,6 +1,16 @@ import type { Writable } from 'svelte/store'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any export type DeepKeys> = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any [K in keyof T]: T[K] extends Record ? `${K}.${DeepKeys}` : K; }[keyof T]; export type WritableValue = T extends Writable ? U : never; + +export function isHTMLElement(el: unknown): el is HTMLElement { + return el instanceof HTMLElement; +} + +export function isHTMLInputElement(el: unknown): el is HTMLInputElement { + return el instanceof HTMLInputElement; +} diff --git a/src/routes/console/project-[project]/databases/+page.ts b/src/routes/console/project-[project]/databases/+page.ts index 2a9e3446a2..477e86419c 100644 --- a/src/routes/console/project-[project]/databases/+page.ts +++ b/src/routes/console/project-[project]/databases/+page.ts @@ -1,10 +1,11 @@ -import { CARD_LIMIT } from '$lib/constants'; +import { CARD_LIMIT, Dependencies } from '$lib/constants'; import { getLimit, getPage, getView, pageToOffset, View } from '$lib/helpers/load'; import { sdk } from '$lib/stores/sdk'; import { Query } from '@appwrite.io/console'; import type { PageLoad } from './$types'; -export const load: PageLoad = async ({ url, route }) => { +export const load: PageLoad = async ({ url, route, depends }) => { + depends(Dependencies.DATABASES); const page = getPage(url); const limit = getLimit(url, route, CARD_LIMIT); const view = getView(url, route, View.Grid); diff --git a/src/routes/console/project-[project]/databases/database-[database]/+page.ts b/src/routes/console/project-[project]/databases/database-[database]/+page.ts index 1a2e91a3b1..dff27da836 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/+page.ts +++ b/src/routes/console/project-[project]/databases/database-[database]/+page.ts @@ -2,9 +2,10 @@ import { Query } from '@appwrite.io/console'; import { sdk } from '$lib/stores/sdk'; import { getLimit, getPage, getView, pageToOffset, View } from '$lib/helpers/load'; import type { PageLoad } from './$types'; -import { CARD_LIMIT } from '$lib/constants'; +import { CARD_LIMIT, Dependencies } from '$lib/constants'; -export const load: PageLoad = async ({ params, url, route }) => { +export const load: PageLoad = async ({ params, url, route, depends }) => { + depends(Dependencies.COLLECTIONS); const page = getPage(url); const limit = getLimit(url, route, CARD_LIMIT); const view = getView(url, route, View.Grid); diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/table.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/table.svelte index 727be175c9..953a3d3924 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/table.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/table.svelte @@ -1,18 +1,27 @@ + d.$id)} /> Document ID {#each $columns.filter((n) => n.show) as column} {#if column.show} @@ -96,6 +153,8 @@ {#each data.documents.documents as document} + + {document.$id} @@ -165,3 +224,98 @@ + + 0}> +
+
+ {selectedDb.length} + + {selected.length > 1 ? 'documents' : 'document'} selected + +
+ +
+ + +
+
+
+ + + Delete Documents + +
+

+ Are you sure you want to delete {selectedDb.length} + {selectedDb.length > 1 ? 'documents' : 'document'}? +

+ + {#if relAttributes?.length} + + + Relation + Setting + + + + {#each relAttributes as attr} + + + + {#if attr.twoWay} + + {:else} + + {/if} + {attr.key} + + + + {attr.onDelete} + + + {Deletion[attr.onDelete]} + + + {/each} + + +
+ To change the selection edit the relationship settings. + + + Delete document from {$collection.name} + +
+ {:else} +

This action is irreversible.

+ {/if} +
+ + + + + +
+ + diff --git a/src/routes/console/project-[project]/databases/database-[database]/table.svelte b/src/routes/console/project-[project]/databases/database-[database]/table.svelte index 458baaa62b..22305fee2b 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/table.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/table.svelte @@ -1,27 +1,69 @@ + c.$id)} /> {#each $columns as column} {#if column.show} {column.title} @@ -32,6 +74,7 @@ {#each data.collections.collections as collection} + {#each $columns as column} {#if column.show} {#if column.id === '$id'} @@ -55,3 +98,52 @@ {/each} + + 0}> +
+
+ {selected.length} + + {selected.length > 1 ? 'collections' : 'collection'} selected + +
+ +
+ + +
+
+
+ + + Delete Collections +

+ Are you sure you want to delete {selected.length} + {selected.length > 1 ? 'collections' : 'collection'}? +

+ + + + +
+ + diff --git a/src/routes/console/project-[project]/databases/table.svelte b/src/routes/console/project-[project]/databases/table.svelte index ac63aa1848..0477187a4f 100644 --- a/src/routes/console/project-[project]/databases/table.svelte +++ b/src/routes/console/project-[project]/databases/table.svelte @@ -1,26 +1,66 @@ + c.$id)} /> {#each $columns as column} {#if column.show} {column.title} @@ -31,6 +71,7 @@ {#each data.databases.databases as database} + {#each $columns as column} {#if column.show} {#if column.id === '$id'} @@ -56,3 +97,52 @@ {/each} + + 0}> +
+
+ {selected.length} + + {selected.length > 1 ? 'databases' : 'database'} selected + +
+ +
+ + +
+
+
+ + + Delete Database +

+ Are you sure you want to delete {selected.length} + {selected.length > 1 ? 'databases' : 'database'}? +

+ + + + +
+ +