mirror of
https://github.com/colanode/colanode.git
synced 2025-12-16 11:47:47 +01:00
Use tanstackdb for chat list
This commit is contained in:
@@ -1,99 +0,0 @@
|
|||||||
import { SelectNode } from '@colanode/client/databases/workspace';
|
|
||||||
import { WorkspaceQueryHandlerBase } from '@colanode/client/handlers/queries/workspace-query-handler-base';
|
|
||||||
import { mapNode } from '@colanode/client/lib/mappers';
|
|
||||||
import { ChangeCheckResult, QueryHandler } from '@colanode/client/lib/types';
|
|
||||||
import { ChatListQueryInput } from '@colanode/client/queries/chats/chat-list';
|
|
||||||
import { Event } from '@colanode/client/types/events';
|
|
||||||
import { LocalChatNode } from '@colanode/client/types/nodes';
|
|
||||||
|
|
||||||
export class ChatListQueryHandler
|
|
||||||
extends WorkspaceQueryHandlerBase
|
|
||||||
implements QueryHandler<ChatListQueryInput>
|
|
||||||
{
|
|
||||||
public async handleQuery(
|
|
||||||
input: ChatListQueryInput
|
|
||||||
): Promise<LocalChatNode[]> {
|
|
||||||
const rows = await this.fetchChildren(input);
|
|
||||||
return rows.map(mapNode) as LocalChatNode[];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async checkForChanges(
|
|
||||||
event: Event,
|
|
||||||
input: ChatListQueryInput,
|
|
||||||
output: LocalChatNode[]
|
|
||||||
): Promise<ChangeCheckResult<ChatListQueryInput>> {
|
|
||||||
if (
|
|
||||||
event.type === 'workspace.deleted' &&
|
|
||||||
event.workspace.userId === input.userId
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
event.type === 'node.created' &&
|
|
||||||
event.workspace.userId === input.userId &&
|
|
||||||
event.node.type === 'chat'
|
|
||||||
) {
|
|
||||||
const newChildren = [...output, event.node];
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: newChildren,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
event.type === 'node.updated' &&
|
|
||||||
event.workspace.userId === input.userId &&
|
|
||||||
event.node.type === 'chat'
|
|
||||||
) {
|
|
||||||
const node = output.find((node) => node.id === event.node.id);
|
|
||||||
if (node) {
|
|
||||||
const newChildren = output.map((node) =>
|
|
||||||
node.id === event.node.id ? (event.node as LocalChatNode) : node
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: newChildren,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
event.type === 'node.deleted' &&
|
|
||||||
event.workspace.userId === input.userId &&
|
|
||||||
event.node.type === 'chat'
|
|
||||||
) {
|
|
||||||
const node = output.find((node) => node.id === event.node.id);
|
|
||||||
if (node) {
|
|
||||||
const newChildren = output.filter((node) => node.id !== event.node.id);
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: newChildren,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
hasChanges: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async fetchChildren(
|
|
||||||
input: ChatListQueryInput
|
|
||||||
): Promise<SelectNode[]> {
|
|
||||||
const workspace = this.getWorkspace(input.userId);
|
|
||||||
|
|
||||||
const rows = await workspace.database
|
|
||||||
.selectFrom('nodes')
|
|
||||||
.selectAll()
|
|
||||||
.where('parent_id', 'is', null)
|
|
||||||
.where('type', '=', 'chat')
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import { AccountListQueryHandler } from './accounts/accounts-list';
|
|||||||
import { MetadataListQueryHandler } from './apps/metadata-list';
|
import { MetadataListQueryHandler } from './apps/metadata-list';
|
||||||
import { TabsListQueryHandler } from './apps/tabs-list';
|
import { TabsListQueryHandler } from './apps/tabs-list';
|
||||||
import { AvatarGetQueryHandler } from './avatars/avatar-get';
|
import { AvatarGetQueryHandler } from './avatars/avatar-get';
|
||||||
import { ChatListQueryHandler } from './chats/chat-list';
|
|
||||||
import { DatabaseListQueryHandler } from './databases/database-list';
|
import { DatabaseListQueryHandler } from './databases/database-list';
|
||||||
import { DatabaseViewListQueryHandler } from './databases/database-view-list';
|
import { DatabaseViewListQueryHandler } from './databases/database-view-list';
|
||||||
import { DocumentGetQueryHandler } from './documents/document-get';
|
import { DocumentGetQueryHandler } from './documents/document-get';
|
||||||
@@ -89,7 +88,6 @@ export const buildQueryHandlerMap = (app: AppService): QueryHandlerMap => {
|
|||||||
'user.storage.get': new UserStorageGetQueryHandler(app),
|
'user.storage.get': new UserStorageGetQueryHandler(app),
|
||||||
'local.file.get': new LocalFileGetQueryHandler(app),
|
'local.file.get': new LocalFileGetQueryHandler(app),
|
||||||
'file.download.request.get': new FileDownloadRequestGetQueryHandler(app),
|
'file.download.request.get': new FileDownloadRequestGetQueryHandler(app),
|
||||||
'chat.list': new ChatListQueryHandler(app),
|
|
||||||
'space.list': new SpaceListQueryHandler(app),
|
'space.list': new SpaceListQueryHandler(app),
|
||||||
'document.get': new DocumentGetQueryHandler(app),
|
'document.get': new DocumentGetQueryHandler(app),
|
||||||
'document.state.get': new DocumentStateGetQueryHandler(app),
|
'document.state.get': new DocumentStateGetQueryHandler(app),
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { LocalChatNode } from '@colanode/client/types/nodes';
|
|
||||||
|
|
||||||
export type ChatListQueryInput = {
|
|
||||||
type: 'chat.list';
|
|
||||||
page: number;
|
|
||||||
count: number;
|
|
||||||
userId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
declare module '@colanode/client/queries' {
|
|
||||||
interface QueryMap {
|
|
||||||
'chat.list': {
|
|
||||||
input: ChatListQueryInput;
|
|
||||||
output: LocalChatNode[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ import { sha256 } from 'js-sha256';
|
|||||||
|
|
||||||
export * from './accounts/account-list';
|
export * from './accounts/account-list';
|
||||||
export * from './apps/metadata-list';
|
export * from './apps/metadata-list';
|
||||||
export * from './chats/chat-list';
|
|
||||||
export * from './databases/database-list';
|
export * from './databases/database-list';
|
||||||
export * from './databases/database-view-list';
|
export * from './databases/database-view-list';
|
||||||
export * from './documents/document-get';
|
export * from './documents/document-get';
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Collection, createLiveQueryCollection, eq } from '@tanstack/react-db';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Download,
|
Download,
|
||||||
|
LocalChatNode,
|
||||||
LocalNode,
|
LocalNode,
|
||||||
LocalRecordNode,
|
LocalRecordNode,
|
||||||
Upload,
|
Upload,
|
||||||
@@ -26,6 +27,7 @@ class WorkspaceCollections {
|
|||||||
public readonly uploads: Collection<Upload, string>;
|
public readonly uploads: Collection<Upload, string>;
|
||||||
public readonly nodes: Collection<LocalNode, string>;
|
public readonly nodes: Collection<LocalNode, string>;
|
||||||
public readonly records: Collection<LocalRecordNode>;
|
public readonly records: Collection<LocalRecordNode>;
|
||||||
|
public readonly chats: Collection<LocalChatNode>;
|
||||||
|
|
||||||
constructor(userId: string) {
|
constructor(userId: string) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
@@ -34,8 +36,14 @@ class WorkspaceCollections {
|
|||||||
this.uploads = createUploadsCollection(userId);
|
this.uploads = createUploadsCollection(userId);
|
||||||
this.nodes = createNodesCollection(userId);
|
this.nodes = createNodesCollection(userId);
|
||||||
|
|
||||||
|
this.chats = createLiveQueryCollection((q) =>
|
||||||
|
q.from({ nodes: this.nodes }).where(({ nodes }) => eq(nodes.type, 'chat'))
|
||||||
|
);
|
||||||
|
|
||||||
this.records = createLiveQueryCollection((q) =>
|
this.records = createLiveQueryCollection((q) =>
|
||||||
q.from({ node: this.nodes }).where(({ node }) => eq(node.type, 'record'))
|
q
|
||||||
|
.from({ nodes: this.nodes })
|
||||||
|
.where(({ nodes }) => eq(nodes.type, 'record'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
|
import { useLiveQuery } from '@tanstack/react-db';
|
||||||
|
|
||||||
|
import { collections } from '@colanode/ui/collections';
|
||||||
import { ChatCreatePopover } from '@colanode/ui/components/chats/chat-create-popover';
|
import { ChatCreatePopover } from '@colanode/ui/components/chats/chat-create-popover';
|
||||||
import { ChatSidebarItem } from '@colanode/ui/components/chats/chat-sidebar-item';
|
import { ChatSidebarItem } from '@colanode/ui/components/chats/chat-sidebar-item';
|
||||||
import { SidebarHeader } from '@colanode/ui/components/layouts/sidebars/sidebar-header';
|
import { SidebarHeader } from '@colanode/ui/components/layouts/sidebars/sidebar-header';
|
||||||
import { Link } from '@colanode/ui/components/ui/link';
|
import { Link } from '@colanode/ui/components/ui/link';
|
||||||
import { useWorkspace } from '@colanode/ui/contexts/workspace';
|
import { useWorkspace } from '@colanode/ui/contexts/workspace';
|
||||||
import { useLiveQuery } from '@colanode/ui/hooks/use-live-query';
|
|
||||||
|
|
||||||
export const SidebarChats = () => {
|
export const SidebarChats = () => {
|
||||||
const workspace = useWorkspace();
|
const workspace = useWorkspace();
|
||||||
|
|
||||||
const chatListQuery = useLiveQuery({
|
const chatListQuery = useLiveQuery((q) =>
|
||||||
type: 'chat.list',
|
q
|
||||||
userId: workspace.userId,
|
.from({ chats: collections.workspace(workspace.userId).chats })
|
||||||
page: 0,
|
.orderBy(({ chats }) => chats.id, 'asc')
|
||||||
count: 100,
|
);
|
||||||
});
|
|
||||||
|
|
||||||
const chats = chatListQuery.data ?? [];
|
const chats = chatListQuery.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col group/sidebar h-full px-2">
|
<div className="flex flex-col group/sidebar h-full px-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user