mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
@@ -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());
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:window on:click={onBlur} />
|
||||
<svelte:window on:click={onBlur} on:keydown={onKeyDown} />
|
||||
|
||||
<div class:drop-wrapper={!noStyle} class:u-cross-child-start={childStart} bind:this={element}>
|
||||
<slot />
|
||||
|
||||
@@ -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" />
|
||||
<span class="text is-only-desktop">Columns</span>
|
||||
<span class="text {showColsTextMobile ? '' : 'is-only-desktop'}">Columns</span>
|
||||
<span class="inline-tag">{selectedColumnsNumber}</span>
|
||||
</Button>
|
||||
<svelte:fragment slot="list">
|
||||
|
||||
@@ -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 @@
|
||||
</script>
|
||||
|
||||
<FormItem>
|
||||
<Label {required} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}
|
||||
</Label>
|
||||
{#if label}
|
||||
<Label {required} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}
|
||||
</Label>
|
||||
{/if}
|
||||
|
||||
<div class="input-text-wrapper">
|
||||
<input
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { FormItem, Helper, Label } from '.';
|
||||
|
||||
export let id: string;
|
||||
export let label: string;
|
||||
export let label: string | undefined = undefined;
|
||||
export let optionalText: string | undefined = undefined;
|
||||
export let showLabel = true;
|
||||
export let value: string | number | boolean;
|
||||
@@ -45,9 +45,11 @@
|
||||
</script>
|
||||
|
||||
<FormItem>
|
||||
<Label {required} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}
|
||||
</Label>
|
||||
{#if label}
|
||||
<Label {required} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}
|
||||
</Label>
|
||||
{/if}
|
||||
|
||||
<div class="select">
|
||||
<select
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import NullCheckbox from './nullCheckbox.svelte';
|
||||
import TextCounter from './textCounter.svelte';
|
||||
|
||||
export let label: string;
|
||||
export let label: string = undefined;
|
||||
export let optionalText: string | undefined = undefined;
|
||||
export let showLabel = true;
|
||||
export let id: string;
|
||||
@@ -67,9 +67,11 @@
|
||||
</script>
|
||||
|
||||
<FormItem>
|
||||
<Label {required} {tooltip} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}
|
||||
</Label>
|
||||
{#if label}
|
||||
<Label {required} {tooltip} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}
|
||||
</Label>
|
||||
{/if}
|
||||
|
||||
<div class="input-text-wrapper">
|
||||
<input
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import Header from '$lib/layout/header.svelte';
|
||||
import SideNavigation from '$lib/layout/navigation.svelte';
|
||||
import Shell from '$lib/layout/shell.svelte';
|
||||
import { feedback } from '$lib/stores/feedback';
|
||||
import { app, feedback } from '$lib/stores/app';
|
||||
import { log } from '$lib/stores/logs';
|
||||
import { newOrgModal } from '$lib/stores/organization';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
@@ -21,6 +21,7 @@
|
||||
import { AIPanel, OrganizationsPanel, ProjectsPanel } from '$lib/commandCenter/panels';
|
||||
import { orgSearcher, projectsSearcher } from '$lib/commandCenter/searchers';
|
||||
import { addSubPanel } from '$lib/commandCenter/subPanels';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { openMigrationWizard } from './(migration-wizard)';
|
||||
|
||||
$: $registerCommands([
|
||||
@@ -105,6 +106,25 @@
|
||||
},
|
||||
group: 'help',
|
||||
icon: 'discord'
|
||||
},
|
||||
{
|
||||
label: 'Toggle theme',
|
||||
callback: () => {
|
||||
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;
|
||||
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
<script lang="ts">
|
||||
import { Button, InputNumber } from '$lib/elements/forms';
|
||||
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
|
||||
import InputText from '$lib/elements/forms/inputText.svelte';
|
||||
import { Query } from '@appwrite.io/console';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { columns } from '../store';
|
||||
import { tags, type Column, type Operator, queries } from './store';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
clear: void;
|
||||
apply: { applied: number };
|
||||
}>();
|
||||
|
||||
let columnId: string | null = null;
|
||||
$: column = $columns.find((c) => c.id === columnId) as Column;
|
||||
|
||||
dispatch('apply', { applied: $tags.length });
|
||||
|
||||
const operators: Record<string, Operator> = {
|
||||
'starts with': {
|
||||
toQuery: Query.startsWith,
|
||||
toTag: (attribute, input) => `**${attribute}** starts with **${input}**`,
|
||||
types: ['string']
|
||||
},
|
||||
'ends with': {
|
||||
toQuery: Query.endsWith,
|
||||
toTag: (attribute, input) => `**${attribute}** ends with **${input}**`,
|
||||
types: ['string']
|
||||
},
|
||||
'greater than': {
|
||||
toQuery: (attr, input) => Query.greaterThan(attr, Number(input)),
|
||||
toTag: (attribute, input) => `**${attribute}** greater than **${input}**`,
|
||||
types: ['integer', 'double']
|
||||
},
|
||||
'greater than or equal to': {
|
||||
toQuery: (attr, input) => Query.greaterThanEqual(attr, Number(input)),
|
||||
toTag: (attribute, input) => `**${attribute}** greater than or equal to **${input}**`,
|
||||
types: ['integer', 'double']
|
||||
},
|
||||
'less than': {
|
||||
toQuery: Query.lessThan,
|
||||
toTag: (attribute, input) => `**${attribute}** less than **${input}**`,
|
||||
types: ['integer', 'double']
|
||||
},
|
||||
'less than or equal to': {
|
||||
toQuery: Query.lessThanEqual,
|
||||
toTag: (attribute, input) => `**${attribute}** less than or equal to **${input}**`,
|
||||
types: ['integer', 'double']
|
||||
},
|
||||
equal: {
|
||||
toQuery: Query.equal,
|
||||
toTag: (attribute, input) => `**${attribute}** equal to **${input}**`,
|
||||
types: ['string', 'integer', 'double']
|
||||
},
|
||||
'not null': {
|
||||
toQuery: Query.isNotNull,
|
||||
toTag: (attribute) => `**${attribute}** is not null`,
|
||||
types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'],
|
||||
hideInput: true
|
||||
},
|
||||
null: {
|
||||
toQuery: Query.isNull,
|
||||
toTag: (attribute) => `**${attribute}** is null`,
|
||||
types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'],
|
||||
hideInput: true
|
||||
}
|
||||
};
|
||||
|
||||
$: operatorsForColumn = Object.entries(operators)
|
||||
.filter(([_, v]) => v.types.includes(column?.type))
|
||||
.map(([k]) => ({
|
||||
label: k,
|
||||
value: k
|
||||
}));
|
||||
|
||||
let operatorKey: string | null = null;
|
||||
$: operator = operatorKey ? operators[operatorKey] : null;
|
||||
$: {
|
||||
columnId;
|
||||
operatorKey = null;
|
||||
}
|
||||
|
||||
// We cast to any to not cause type errors in the input components
|
||||
let value: any = null;
|
||||
|
||||
$: {
|
||||
columnId;
|
||||
value = null;
|
||||
}
|
||||
|
||||
// This Map is keyed by tags, and has a query as the value
|
||||
function addFilter() {
|
||||
if (column && operator) {
|
||||
queries.addFilter({ column, operator, value });
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
|
||||
function tagFormat(node: HTMLElement) {
|
||||
node.innerHTML = node.innerHTML.replace(/\*\*(.*?)\*\*/g, '<b>$1</b>');
|
||||
}
|
||||
|
||||
$: isDisabled = (function getDisabled() {
|
||||
return !operator || (!operator?.hideInput && !value);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<form on:submit|preventDefault={addFilter}>
|
||||
<div class="selects u-flex u-gap-12 u-margin-block-start-16">
|
||||
<InputSelect
|
||||
id="column"
|
||||
options={$columns.map((c) => ({
|
||||
label: c.title,
|
||||
value: c.id
|
||||
}))}
|
||||
placeholder="Select column"
|
||||
bind:value={columnId} />
|
||||
<InputSelect
|
||||
id="operator"
|
||||
disabled={!column}
|
||||
options={operatorsForColumn}
|
||||
placeholder="Select operator"
|
||||
bind:value={operatorKey} />
|
||||
</div>
|
||||
{#if column && operator && !operator?.hideInput}
|
||||
<div class="u-margin-block-start-16">
|
||||
{#if column.type === 'integer' || column.type === 'double'}
|
||||
<InputNumber id="value" bind:value placeholder="Enter value" />
|
||||
{:else}
|
||||
<InputText id="value" bind:value placeholder="Enter value" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<Button text disabled={isDisabled} class="u-margin-block-start-12" submit>
|
||||
<i class="icon-plus" />
|
||||
Add filter
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
<ul class="u-flex u-flex-wrap u-cross-center u-gap-8 u-margin-block-start-16 tags">
|
||||
{#each $tags as tag (tag)}
|
||||
<button
|
||||
class="tag"
|
||||
on:click={() => {
|
||||
queries.removeFilter(tag);
|
||||
}}>
|
||||
<span class="text" use:tagFormat>
|
||||
{tag}
|
||||
</span>
|
||||
<i class="icon-x" />
|
||||
</button>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.dropped {
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0px 16px 32px 0px rgba(55, 59, 77, 0.04);
|
||||
|
||||
padding: 1rem;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
width: 37.5rem;
|
||||
}
|
||||
|
||||
.selects {
|
||||
:global(> *) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tags {
|
||||
:global(b) {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
width: calc(100% + 2rem);
|
||||
background-color: hsl(var(--color-border));
|
||||
|
||||
margin-block-start: 1rem;
|
||||
margin-inline: -1rem;
|
||||
}
|
||||
</style>
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<script lang="ts">
|
||||
import { Drop, Modal } from '$lib/components';
|
||||
import Content from './content.svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { queries, tags } from './store';
|
||||
|
||||
// We need to separate them so we don't trigger Drop's handlers
|
||||
let showFiltersDesktop = false;
|
||||
let showFiltersMobile = false;
|
||||
|
||||
let applied = $tags.length;
|
||||
|
||||
function apply() {
|
||||
queries.apply();
|
||||
applied = $tags.length;
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
queries.clearAll();
|
||||
queries.apply();
|
||||
applied = 0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="is-not-mobile">
|
||||
<Drop bind:show={showFiltersDesktop} noArrow>
|
||||
<Button secondary on:click={() => (showFiltersDesktop = !showFiltersDesktop)}>
|
||||
<i class="icon-filter u-opacity-50" />
|
||||
Filters
|
||||
{#if applied > 0}
|
||||
<span class="inline-tag">
|
||||
{applied}
|
||||
</span>
|
||||
{/if}
|
||||
</Button>
|
||||
<svelte:fragment slot="list">
|
||||
<div class="dropped card">
|
||||
<p>Apply filter rules to refine the table view</p>
|
||||
<Content
|
||||
on:apply={(e) => (applied = e.detail.applied)}
|
||||
on:clear={() => (applied = 0)} />
|
||||
<hr />
|
||||
<div class="u-flex u-margin-block-start-16 u-main-end u-gap-8">
|
||||
<Button text on:click={clearAll}>Clear all</Button>
|
||||
<Button on:click={apply}>Apply</Button>
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Drop>
|
||||
</div>
|
||||
|
||||
<div class="is-only-mobile">
|
||||
<Button secondary on:click={() => (showFiltersMobile = !showFiltersMobile)}>
|
||||
<i class="icon-filter u-opacity-50" />
|
||||
Filters
|
||||
{#if applied > 0}
|
||||
<span class="inline-tag">
|
||||
{applied}
|
||||
</span>
|
||||
{/if}
|
||||
</Button>
|
||||
|
||||
<Modal bind:show={showFiltersMobile} size="big">
|
||||
<svelte:fragment slot="header">Filters</svelte:fragment>
|
||||
<Content on:apply={(e) => (applied = e.detail.applied)} on:clear={() => (applied = 0)} />
|
||||
<svelte:fragment slot="footer">
|
||||
<Button text on:click={clearAll}>Clear all</Button>
|
||||
<Button on:click={apply}>Apply</Button></svelte:fragment>
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.dropped {
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0px 16px 32px 0px rgba(55, 59, 77, 0.04);
|
||||
|
||||
padding: 1rem;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
width: 37.5rem;
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
width: calc(100% + 2rem);
|
||||
background-color: hsl(var(--color-border));
|
||||
|
||||
margin-block-start: 1rem;
|
||||
margin-inline: -1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+74
@@ -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> = Store extends Writable<infer T> ? T : never;
|
||||
export type Column = Omit<StoreValues<typeof columns>[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<string, string>) {
|
||||
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<string, string>()) {
|
||||
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()));
|
||||
+59
-25
@@ -1,17 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { Empty, Heading, PaginationWithLimit } from '$lib/components';
|
||||
import { Container, GridHeader } from '$lib/layout';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import Create from './createDocument.svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { collection, columns } from './store';
|
||||
import CreateAttribute from './createAttribute.svelte';
|
||||
import Table from './table.svelte';
|
||||
import { preferences } from '$lib/stores/preferences';
|
||||
import { page } from '$app/stores';
|
||||
import { Empty, Heading, PaginationWithLimit } from '$lib/components';
|
||||
import ViewSelector from '$lib/components/viewSelector.svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Container } from '$lib/layout';
|
||||
import { preferences } from '$lib/stores/preferences';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import type { PageData } from './$types';
|
||||
import CreateAttributeDropdown from './attributes/createAttributeDropdown.svelte';
|
||||
import type { Option } from './attributes/store';
|
||||
import CreateAttribute from './createAttribute.svelte';
|
||||
import Create from './createDocument.svelte';
|
||||
import Filters from './(filters)/filters.svelte';
|
||||
import { collection, columns } from './store';
|
||||
import Table from './table.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
@@ -39,21 +41,39 @@
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<GridHeader
|
||||
title="Documents"
|
||||
{columns}
|
||||
view={data.view}
|
||||
hideView
|
||||
isCustomCollection
|
||||
allowNoColumns>
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
event="create_document">
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Create document</span>
|
||||
</Button>
|
||||
</GridHeader>
|
||||
<div class="heading-grid u-main-justify-between u-cross-center">
|
||||
<Heading tag="h2" size="5">Documents</Heading>
|
||||
<div class="u-flex u-main-end is-only-mobile">
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
event="create_document">
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Create document</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Filters />
|
||||
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<ViewSelector
|
||||
view={data.view}
|
||||
{columns}
|
||||
isCustomCollection
|
||||
hideView
|
||||
allowNoColumns
|
||||
showColsTextMobile />
|
||||
<div class="is-not-mobile">
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
event="create_document">
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Create document</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if hasAttributes && hasValidAttributes}
|
||||
{#if data.documents.total}
|
||||
@@ -105,3 +125,17 @@
|
||||
</Container>
|
||||
|
||||
<CreateAttribute bind:showCreate={showCreateAttribute} selectedOption={selectedAttribute} />
|
||||
|
||||
<style lang="scss">
|
||||
.heading-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:global(h2) {
|
||||
grid-column: span 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+12
-1
@@ -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()
|
||||
]
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -135,9 +135,10 @@
|
||||
}))} />
|
||||
</FormList>
|
||||
<p class="u-text-center u-margin-block-start-24">
|
||||
Signed in as test@test.com <button
|
||||
class="u-bold"
|
||||
on:click|preventDefault={deauthorizeGoogle}>Sign Out?</button>
|
||||
Signed in
|
||||
<button class="u-bold" on:click|preventDefault={deauthorizeGoogle}>
|
||||
Sign Out?
|
||||
</button>
|
||||
</p>
|
||||
{/if}
|
||||
{:else if $provider.provider === 'supabase'}
|
||||
|
||||
Reference in New Issue
Block a user