diff --git a/src/lib/commandCenter/commands.ts b/src/lib/commandCenter/commands.ts index b174bc6ec0..64d3ea0c9f 100644 --- a/src/lib/commandCenter/commands.ts +++ b/src/lib/commandCenter/commands.ts @@ -29,7 +29,8 @@ const groups = [ 'teams', 'security', 'buckets', - 'files' + 'files', + 'misc' ] as const; export type CommandGroup = (typeof groups)[number]; @@ -278,8 +279,9 @@ export const commandGroupRanks = derived(groupRanksMap, ($groupRankTransformatio databases: 3, users: 2, teams: 1, - navigation: -1, - help: -2 + navigation: -10, + help: -20, + misc: -30 } as CommandGroupRanks; const transformations = Array.from($groupRankTransformations.values()); diff --git a/src/lib/components/drop.svelte b/src/lib/components/drop.svelte index 600700a36a..ca65fb4e33 100644 --- a/src/lib/components/drop.svelte +++ b/src/lib/components/drop.svelte @@ -77,16 +77,26 @@ event.target === element || element.contains(event.target as Node) || event.target === tooltip || - tooltip.contains(event.target as Node) + tooltip.contains(event.target as Node) || + // Avoid deleted elements triggering blur + !document.body.contains(event.target as Node) ) ) { show = false; dispatch('blur'); } }; + + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape' && show) { + event.preventDefault(); + show = false; + dispatch('blur'); + } + }; - +
diff --git a/src/lib/components/viewSelector.svelte b/src/lib/components/viewSelector.svelte index 82d7d499b8..5daf070eb1 100644 --- a/src/lib/components/viewSelector.svelte +++ b/src/lib/components/viewSelector.svelte @@ -23,6 +23,7 @@ export let hideView = false; export let hideColumns = false; export let allowNoColumns = false; + export let showColsTextMobile = false; let showSelectColumns = false; @@ -84,7 +85,7 @@ class="icon-view-boards u-opacity-50" aria-hidden="true" aria-label="columns" /> - Columns + Columns {selectedColumnsNumber} diff --git a/src/lib/elements/forms/inputNumber.svelte b/src/lib/elements/forms/inputNumber.svelte index 5110e4eea7..7baf0ecb9d 100644 --- a/src/lib/elements/forms/inputNumber.svelte +++ b/src/lib/elements/forms/inputNumber.svelte @@ -3,7 +3,7 @@ import { FormItem, Helper, Label } from '.'; import NullCheckbox from './nullCheckbox.svelte'; - export let label: string; + export let label: string | undefined = undefined; export let optionalText: string | undefined = undefined; export let showLabel = true; export let id: string; @@ -65,9 +65,11 @@ - + {#if label} + + {/if}
- + {#if label} + + {/if}
{ + if ($app.theme === 'auto') { + $app.theme = 'light'; + } else if ($app.theme === 'light') { + $app.theme = 'dark'; + } else { + $app.theme = 'auto'; + } + addNotification({ + title: 'Theme changed', + message: `Theme changed to ${$app.theme}`, + type: 'success' + }); + }, + group: 'misc', + icon: 'switch-horizontal' } ]); let isOpen = false; diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/content.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/content.svelte new file mode 100644 index 0000000000..488dcaf228 --- /dev/null +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/content.svelte @@ -0,0 +1,189 @@ + + +
+
+
+ ({ + label: c.title, + value: c.id + }))} + placeholder="Select column" + bind:value={columnId} /> + +
+ {#if column && operator && !operator?.hideInput} +
+ {#if column.type === 'integer' || column.type === 'double'} + + {:else} + + {/if} +
+ {/if} + + + +
    + {#each $tags as tag (tag)} + + {/each} +
+
+ + diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/filters.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/filters.svelte new file mode 100644 index 0000000000..5e4611cce8 --- /dev/null +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/filters.svelte @@ -0,0 +1,91 @@ + + +
+ + + +
+

Apply filter rules to refine the table view

+ (applied = e.detail.applied)} + on:clear={() => (applied = 0)} /> +
+
+ + +
+
+
+
+
+ +
+ + + + Filters + (applied = e.detail.applied)} on:clear={() => (applied = 0)} /> + + + + +
+ + diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/store.ts b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/store.ts new file mode 100644 index 0000000000..9c9d7bff9f --- /dev/null +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/(filters)/store.ts @@ -0,0 +1,74 @@ +import { goto } from '$app/navigation'; + +import { derived, get, writable, type Writable } from 'svelte/store'; +import type { columns } from '../store'; + +const columnTypes = ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'] as const; +type ColumnType = (typeof columnTypes)[number]; + +type StoreValues = Store extends Writable ? T : never; +export type Column = Omit[number], 'type'> & { + type: ColumnType; +}; + +export type Operator = { + toTag: (attribute: string, input?: string | number) => string; + toQuery: (attribute: string, input?: string | number) => string; + types: ColumnType[]; + hideInput?: boolean; +}; + +export function mapToQueryParams(map: Map) { + return encodeURIComponent(JSON.stringify(Array.from(map.entries()))); +} + +export function queryParamToMap(queryParam: string) { + const decodedQueryParam = decodeURIComponent(queryParam); + const queries = JSON.parse(decodedQueryParam) as [string, string][]; + return new Map(queries); +} + +function initQueries(initialValue = new Map()) { + const queries = writable(initialValue); + + type AddFilterArgs = { + operator: Operator; + column: Column; + value: string | number; + }; + + function addFilter({ column, operator, value }: AddFilterArgs) { + queries.update((map) => { + map.set(operator.toTag(column.id, value), operator.toQuery(column.id, value)); + return map; + }); + } + + function removeFilter(tag: string) { + queries.update((map) => { + map.delete(tag); + return map; + }); + } + + function clearAll() { + queries.set(new Map()); + } + + function apply() { + const queryParam = mapToQueryParams(get(queries)); + const currentLocation = window.location.pathname; + goto(`${currentLocation}?query=${queryParam}`); + } + + return { + ...queries, + addFilter, + removeFilter, + clearAll, + apply + }; +} + +export const queries = initQueries(); +export const tags = derived(queries, ($queries) => Array.from($queries.keys())); diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.svelte b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.svelte index 127eca328e..39b72fc66f 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.svelte +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.svelte @@ -1,17 +1,19 @@ - - - +
+ Documents +
+ +
+ + + +
+ +
+ +
+
+
{#if hasAttributes && hasValidAttributes} {#if data.documents.total} @@ -105,3 +125,17 @@
+ + diff --git a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.ts b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.ts index ef7a3de276..9161f4f22d 100644 --- a/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.ts +++ b/src/routes/console/project-[project]/databases/database-[database]/collection-[collection]/+page.ts @@ -4,6 +4,8 @@ import { sdk } from '$lib/stores/sdk'; import { Query } from '@appwrite.io/console'; import type { PageLoad } from './$types'; +import { queries, queryParamToMap } from './(filters)/store'; + export const load: PageLoad = async ({ params, depends, url, route }) => { depends(Dependencies.DOCUMENTS); const page = getPage(url); @@ -11,6 +13,10 @@ export const load: PageLoad = async ({ params, depends, url, route }) => { const view = getView(url, route, View.Grid); const offset = pageToOffset(page, limit); + const paramQueries = url.searchParams.get('query'); + const parsedQueries = queryParamToMap(paramQueries || '[]'); + queries.set(parsedQueries); + return { offset, limit, @@ -18,7 +24,12 @@ export const load: PageLoad = async ({ params, depends, url, route }) => { documents: await sdk.forProject.databases.listDocuments( params.database, params.collection, - [Query.limit(limit), Query.offset(offset), Query.orderDesc('$createdAt')] + [ + Query.limit(limit), + Query.offset(offset), + Query.orderDesc(''), + ...parsedQueries.values() + ] ) }; }; diff --git a/src/routes/console/project-[project]/settings/migrations/(import)/step1.svelte b/src/routes/console/project-[project]/settings/migrations/(import)/step1.svelte index 2e14a416d4..2800ff2498 100644 --- a/src/routes/console/project-[project]/settings/migrations/(import)/step1.svelte +++ b/src/routes/console/project-[project]/settings/migrations/(import)/step1.svelte @@ -135,9 +135,10 @@ }))} />

- Signed in as test@test.com + Signed in +

{/if} {:else if $provider.provider === 'supabase'}