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: improved @/pocketbase/query module #48

Merged
merged 7 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{
"tailwindCSS.classAttributes": ["class", "className", "contentClass"],
"tailwindCSS.classAttributes": [
"class",
"className",
"contentClass",
"containerClass"
],
"editor.quickSuggestions": {
"strings": "on"
},
Expand Down
Binary file modified webapp/bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"@types/eslint": "^9.6.0",
"@types/lodash": "^4.17.13",
"autoprefixer": "^10.4.20",
"bits-ui": "^1.2.0",
"bits-ui": "^1.3.1",
"clsx": "^2.1.1",
"dotenv": "^16.4.5",
"eslint": "^9.7.0",
Expand All @@ -63,7 +63,7 @@
"json-to-ts": "^2.1.0",
"lucide-svelte": "^0.475.0",
"mode-watcher": "^0.5.1",
"paneforge": "^1.0.0-next.3",
"paneforge": "^1.0.0-next.4",
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.5",
Expand Down
15 changes: 9 additions & 6 deletions webapp/src/modules/collections-components/collectionField.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<script module lang="ts">
import type { GenericRecord } from '@/utils/types';
import type { CollectionName } from '@/pocketbase/collections-models';
import type { ExpandQueryOption, QueryResponse } from '@/pocketbase/query';
import type { PocketbaseQueryExpandOption, PocketbaseQueryResponse } from '@/pocketbase/query';

export type CollectionFieldModeProp = { mode?: 'search' | 'select' };

export type CollectionFieldOptions<
C extends CollectionName,
Expand extends ExpandQueryOption<C>
Expand extends PocketbaseQueryExpandOption<C>
> = {
multiple?: boolean;
} & CollectionFieldModeProp &
Expand All @@ -17,7 +17,7 @@

<script
lang="ts"
generics="Data extends GenericRecord, C extends CollectionName, Expand extends ExpandQueryOption<C> = never"
generics="Data extends GenericRecord, C extends CollectionName, E extends PocketbaseQueryExpandOption<C> = never"
>
import { m } from '@/i18n';
import { ensureArray, maybeArrayIsValue } from '@/utils/other';
Expand All @@ -43,7 +43,7 @@
form: SuperForm<Data>;
name: FormPath<Data>;
collection: C;
options?: CollectionFieldOptions<C, Expand>;
options?: CollectionFieldOptions<C, E>;
}

const { form, name, collection, options = {} }: Props = $props();
Expand All @@ -62,7 +62,7 @@

const valueProxy = $derived(fieldProxy(form, name)) as Writable<string | string[] | undefined>;

function fetchRecord(collection: C, id: string): Promise<QueryResponse<C, Expand>> {
function fetchRecord(collection: C, id: string): Promise<PocketbaseQueryResponse<C, E>> {
return pb.collection(collection).getOne(id, { requestKey: null });
}

Expand All @@ -85,7 +85,10 @@
{#snippet children({ props })}
<Component
{collection}
queryOptions={{ ...queryOptions, exclude: [...exclude, ...ensureArray($valueProxy)] }}
queryOptions={{
...queryOptions,
exclude: [...exclude, ...ensureArray($valueProxy)]
}}
displayFn={presenter}
displayFields={options.displayFields}
onSelect={(record) => {
Expand Down
22 changes: 16 additions & 6 deletions webapp/src/modules/collections-components/collectionSearch.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<script lang="ts" generics="C extends CollectionName, Expand extends ExpandQueryOption<C> = never">
import { type ExpandQueryOption, type QueryResponse, PocketbaseQuery } from '@/pocketbase/query';
<script
lang="ts"
generics="C extends CollectionName, E extends PocketbaseQueryExpandOption<C> = never"
>
import {
type PocketbaseQueryResponse,
type PocketbaseQueryExpandOption,
type PocketbaseQueryOptions,
createPocketbaseQueryAgent
} from '@/pocketbase/query';
import type { CollectionName } from '@/pocketbase/collections-models';
import { createRecordDisplay } from './utils';
import Search from '@/components/ui-custom/search.svelte';
Expand All @@ -8,7 +16,7 @@

//

type Props = CollectionInputProps<C, Expand>;
type Props = CollectionInputProps<C, E>;

let {
collection,
Expand All @@ -24,11 +32,13 @@

//

type SearchFn = SearchFunction<QueryResponse<C, Expand>>;
type SearchFn = SearchFunction<PocketbaseQueryResponse<C, E>>;

const searchFunction: SearchFn = $derived(async function (text: string | undefined) {
const query = new PocketbaseQuery(collection, { ...queryOptions, search: text });
const records = await query.getFullList();
const query: PocketbaseQueryOptions<C, E> = { ...queryOptions, search: text };

const runners = createPocketbaseQueryAgent({ collection, ...query }, { requestKey: null });
const records = await runners.getFullList();

return records.map((item) => ({
value: item,
Expand Down
21 changes: 15 additions & 6 deletions webapp/src/modules/collections-components/collectionSelect.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
<script lang="ts" generics="C extends CollectionName, Expand extends ExpandQueryOption<C> = never">
import { type ExpandQueryOption, PocketbaseQuery, type QueryResponse } from '@/pocketbase/query';
<script
lang="ts"
generics="C extends CollectionName, E extends PocketbaseQueryExpandOption<C> = never"
>
import {
type PocketbaseQueryResponse,
type PocketbaseQueryExpandOption,
type PocketbaseQueryOptions,
createPocketbaseQueryAgent
} from '@/pocketbase/query';

import type { CollectionName } from '@/pocketbase/collections-models';
import { setupComponentPocketbaseSubscriptions } from '@/pocketbase/subscriptions';
import type { RecordIdString } from '@/pocketbase/types';
Expand All @@ -9,7 +18,7 @@

//

type Props = CollectionInputProps<C, Expand>;
type Props = CollectionInputProps<C, E>;

let {
collection,
Expand All @@ -25,7 +34,7 @@

//

type Record = QueryResponse<C, Expand>;
type Record = PocketbaseQueryResponse<C, E>;

let records = $state<Record[]>([]);
let recordId = $state<RecordIdString | undefined>();
Expand All @@ -45,8 +54,8 @@
//

const loadRecords = $derived(function () {
const query = new PocketbaseQuery(collection, queryOptions);
query.getFullList().then((res) => (records = res));
const runners = createPocketbaseQueryAgent({ collection, ...queryOptions });
runners.getFullList().then((res) => (records = res));
});

$effect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
RecordIdString,
CollectionRelatedCollections as Related
} from '@/pocketbase/types';
import type { ExpandQueryOption } from '@/pocketbase/query';
import type { PocketbaseQueryExpandOption } from '@/pocketbase/query';
import type { GenericRecord, KeyOf, MaybePromise } from '@/utils/types';
import type { Snippet } from 'svelte';
import type { FormPath, SuperForm } from 'sveltekit-superforms';
Expand Down Expand Up @@ -57,7 +57,7 @@ export type FieldsOptions<C extends CollectionName, R = CollectionFormData[C]> =
};

export type RelationFieldOptions<C extends CollectionName> = CollectionFieldModeProp &
CollectionInputRecordProps<C, ExpandQueryOption<C>>;
CollectionInputRecordProps<C, PocketbaseQueryExpandOption<C>>;

export type FieldSnippet<C extends CollectionName, T = CollectionFormData[C]> = Snippet<
[{ form: SuperForm<T & GenericRecord>; field: FormPath<T & GenericRecord> }]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
<script lang="ts" generics="C extends CollectionName, Expand extends ExpandQueryOption<C> = never">
<script
lang="ts"
generics="C extends CollectionName, E extends PocketbaseQueryExpandOption<C> = never"
>
// Logic
import { CollectionManager } from './collectionManager.svelte.js';
import { setupComponentPocketbaseSubscriptions } from '@/pocketbase/subscriptions';
import {
setCollectionManagerContext,
type CollectionManagerContext
type CollectionManagerContext,
type Filter,
type FilterGroup
} from './collectionManagerContext';

// Logic - Types
import type {
ExpandQueryOption,
PocketbaseQueryExpandOption,
PocketbaseQueryOptions,
QueryResponse
PocketbaseQueryResponse,
PocketbaseQueryAgentOptions
} from '@/pocketbase/query';
import type { CollectionName } from '@/pocketbase/collections-models';
import type {
Expand All @@ -28,6 +34,7 @@
import Pagination from './collectionManagerPagination.svelte';
import Search from './collectionManagerSearch.svelte';
import Header from './collectionManagerHeader.svelte';
import Filters from './collectionManagerFilters.svelte';

// UI
import { m } from '@/i18n';
Expand All @@ -45,21 +52,24 @@
records: Snippet<
[
{
records: QueryResponse<C, Expand>[];
records: PocketbaseQueryResponse<C, E>[];
Card: typeof Card;
Table: typeof Table;
Pagination: typeof Pagination;
}
]
>;
emptyState: Snippet<[{ EmptyState: typeof EmptyState }]>;
top: Snippet<[{ Search: typeof Search; Header: typeof Header }]>;
top: Snippet<[{ Search: typeof Search; Header: typeof Header; Filters: typeof Filters }]>;
contentWrapper: Snippet<[children: () => ReturnType<Snippet>]>;
};

type Options = {
queryOptions: Partial<PocketbaseQueryOptions<C, Expand>>;
queryOptions: PocketbaseQueryOptions<C, E>;
queryAgentOptions: PocketbaseQueryAgentOptions;
filters: (Filter | FilterGroup)[];
subscribe: 'off' | 'expanded_collections' | CollectionName[];

hide: ('empty_state' | 'pagination')[];

formUIOptions: CollectionFormUIOptions;
Expand All @@ -75,24 +85,34 @@
editFormFieldsOptions: Partial<FieldsOptions<C>>;
};

//

const {
collection,
queryOptions = {},
queryAgentOptions = {},
hide = [],
subscribe = 'expanded_collections',
top,
records,
emptyState,
contentWrapper,
filters = [],
...rest
}: Props = $props();

//

const manager = $derived(new CollectionManager(collection, queryOptions));
const manager = $derived(
new CollectionManager(collection, {
query: queryOptions,
queryAgent: queryAgentOptions
})
);

const context = $derived<CollectionManagerContext<C, Expand>>({
const context = $derived<CollectionManagerContext<C, E>>({
manager,
filters,
formsOptions: {
base: {
uiOptions: rest.formUIOptions,
Expand Down Expand Up @@ -122,7 +142,7 @@
});
</script>

{@render top?.({ Search, Header })}
{@render top?.({ Search, Header, Filters })}
{@render (contentWrapper ?? defaultContentWrapper)(content)}

{#snippet defaultContentWrapper(children: () => ReturnType<Snippet>)}
Expand All @@ -142,7 +162,7 @@
{#if !hide.includes('pagination')}
<Pagination class="mt-6" />
{/if}
{:else if manager.queryOptions.search && manager.records.length === 0}
{:else if manager.query.hasSearch() && manager.records.length === 0}
<EmptyState title={m.No_records_found()} icon={SearchIcon} />
{:else if emptyState}
{@render emptyState({ EmptyState })}
Expand Down
Loading