mirror of
https://github.com/colanode/colanode.git
synced 2025-12-16 11:47:47 +01:00
Minor fixes and improvements for tabs
This commit is contained in:
@@ -168,7 +168,7 @@ export const fetchEntryBreadcrumb = async (
|
|||||||
.selectFrom('entry_paths')
|
.selectFrom('entry_paths')
|
||||||
.select('ancestor_id')
|
.select('ancestor_id')
|
||||||
.where('descendant_id', '=', entryId)
|
.where('descendant_id', '=', entryId)
|
||||||
.orderBy('level', 'asc')
|
.orderBy('level', 'desc')
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
return rows.map((row) => row.ancestor_id);
|
return rows.map((row) => row.ancestor_id);
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
import { Entry } from '@colanode/core';
|
|
||||||
|
|
||||||
import { SelectEntry } from '@/main/databases/workspace';
|
|
||||||
import { ChangeCheckResult, QueryHandler } from '@/main/lib/types';
|
|
||||||
import { fetchEntryAncestors } from '@/main/lib/utils';
|
|
||||||
import { mapEntry } from '@/main/lib/mappers';
|
|
||||||
import { EntryTreeGetQueryInput } from '@/shared/queries/entries/entry-tree-get';
|
|
||||||
import { Event } from '@/shared/types/events';
|
|
||||||
import { WorkspaceQueryHandlerBase } from '@/main/queries/workspace-query-handler-base';
|
|
||||||
|
|
||||||
export class EntryTreeGetQueryHandler
|
|
||||||
extends WorkspaceQueryHandlerBase
|
|
||||||
implements QueryHandler<EntryTreeGetQueryInput>
|
|
||||||
{
|
|
||||||
public async handleQuery(input: EntryTreeGetQueryInput): Promise<Entry[]> {
|
|
||||||
const rows = await this.fetchEntries(input);
|
|
||||||
return rows.map(mapEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async checkForChanges(
|
|
||||||
event: Event,
|
|
||||||
input: EntryTreeGetQueryInput,
|
|
||||||
output: Entry[]
|
|
||||||
): Promise<ChangeCheckResult<EntryTreeGetQueryInput>> {
|
|
||||||
if (
|
|
||||||
event.type === 'workspace_deleted' &&
|
|
||||||
event.workspace.accountId === input.accountId &&
|
|
||||||
event.workspace.id === input.workspaceId
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
event.type === 'entry_created' &&
|
|
||||||
event.accountId === input.accountId &&
|
|
||||||
event.workspaceId === input.workspaceId &&
|
|
||||||
event.entry.id === input.entryId
|
|
||||||
) {
|
|
||||||
const newResult = await this.handleQuery(input);
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: newResult,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
event.type === 'entry_updated' &&
|
|
||||||
event.accountId === input.accountId &&
|
|
||||||
event.workspaceId === input.workspaceId
|
|
||||||
) {
|
|
||||||
const entry = output.find((entry) => entry.id === event.entry.id);
|
|
||||||
if (entry) {
|
|
||||||
const newEntries = output.map((entry) => {
|
|
||||||
if (entry.id === event.entry.id) {
|
|
||||||
return event.entry;
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: newEntries,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
event.type === 'entry_deleted' &&
|
|
||||||
event.accountId === input.accountId &&
|
|
||||||
event.workspaceId === input.workspaceId
|
|
||||||
) {
|
|
||||||
const entry = output.find((entry) => entry.id === event.entry.id);
|
|
||||||
if (entry) {
|
|
||||||
const newResult = await this.handleQuery(input);
|
|
||||||
return {
|
|
||||||
hasChanges: true,
|
|
||||||
result: newResult,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
hasChanges: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async fetchEntries(
|
|
||||||
input: EntryTreeGetQueryInput
|
|
||||||
): Promise<SelectEntry[]> {
|
|
||||||
const workspace = this.getWorkspace(input.accountId, input.workspaceId);
|
|
||||||
|
|
||||||
const rows = await fetchEntryAncestors(workspace.database, input.entryId);
|
|
||||||
if (rows.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const result: SelectEntry[] = [];
|
|
||||||
|
|
||||||
let entry = rows.find((row) => row.id === input.entryId);
|
|
||||||
if (!entry) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
while (entry) {
|
|
||||||
result.unshift(entry);
|
|
||||||
entry = rows.find(
|
|
||||||
(row) => row.id !== entry?.id && row.id === entry?.parent_id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!entry) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,6 @@ import { MessageReactionsAggregateQueryHandler } from '@/main/queries/messages/m
|
|||||||
import { MessageBreadcrumbGetQueryHandler } from '@/main/queries/messages/message-breadcrumb-get';
|
import { MessageBreadcrumbGetQueryHandler } from '@/main/queries/messages/message-breadcrumb-get';
|
||||||
import { EntryChildrenGetQueryHandler } from '@/main/queries/entries/entry-children-get';
|
import { EntryChildrenGetQueryHandler } from '@/main/queries/entries/entry-children-get';
|
||||||
import { EntryGetQueryHandler } from '@/main/queries/entries/entry-get';
|
import { EntryGetQueryHandler } from '@/main/queries/entries/entry-get';
|
||||||
import { EntryTreeGetQueryHandler } from '@/main/queries/entries/entry-tree-get';
|
|
||||||
import { EntryBreadcrumbGetQueryHandler } from '@/main/queries/entries/entry-breadcrumb-get';
|
import { EntryBreadcrumbGetQueryHandler } from '@/main/queries/entries/entry-breadcrumb-get';
|
||||||
import { RadarDataGetQueryHandler } from '@/main/queries/interactions/radar-data-get';
|
import { RadarDataGetQueryHandler } from '@/main/queries/interactions/radar-data-get';
|
||||||
import { RecordListQueryHandler } from '@/main/queries/records/record-list';
|
import { RecordListQueryHandler } from '@/main/queries/records/record-list';
|
||||||
@@ -64,7 +63,6 @@ export const queryHandlerMap: QueryHandlerMap = {
|
|||||||
icon_list: new IconListQueryHandler(),
|
icon_list: new IconListQueryHandler(),
|
||||||
icon_search: new IconSearchQueryHandler(),
|
icon_search: new IconSearchQueryHandler(),
|
||||||
icon_category_list: new IconCategoryListQueryHandler(),
|
icon_category_list: new IconCategoryListQueryHandler(),
|
||||||
entry_tree_get: new EntryTreeGetQueryHandler(),
|
|
||||||
entry_children_get: new EntryChildrenGetQueryHandler(),
|
entry_children_get: new EntryChildrenGetQueryHandler(),
|
||||||
radar_data_get: new RadarDataGetQueryHandler(),
|
radar_data_get: new RadarDataGetQueryHandler(),
|
||||||
file_metadata_get: new FileMetadataGetQueryHandler(),
|
file_metadata_get: new FileMetadataGetQueryHandler(),
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export const LayoutTabs = ({
|
|||||||
value={tab.id}
|
value={tab.id}
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
'overflow-hidden rounded-b-none bg-muted py-2 data-[state=active]:z-10 data-[state=active]:shadow-none h-10 group/tab app-no-drag-region',
|
'overflow-hidden rounded-b-none bg-muted py-2 data-[state=active]:z-10 data-[state=active]:shadow-none h-10 group/tab app-no-drag-region flex items-center justify-between gap-2',
|
||||||
tab.preview && 'italic'
|
tab.preview && 'italic'
|
||||||
)}
|
)}
|
||||||
onAuxClick={(e) => {
|
onAuxClick={(e) => {
|
||||||
@@ -66,33 +66,35 @@ export const LayoutTabs = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{match(getIdType(tab.id))
|
<div className="overflow-hidden truncate">
|
||||||
.with(IdType.Channel, () => (
|
{match(getIdType(tab.id))
|
||||||
<ChannelContainerTab channelId={tab.id} />
|
.with(IdType.Channel, () => (
|
||||||
))
|
<ChannelContainerTab channelId={tab.id} />
|
||||||
.with(IdType.Page, () => <PageContainerTab pageId={tab.id} />)
|
))
|
||||||
.with(IdType.Database, () => (
|
.with(IdType.Page, () => <PageContainerTab pageId={tab.id} />)
|
||||||
<DatabaseContainerTab databaseId={tab.id} />
|
.with(IdType.Database, () => (
|
||||||
))
|
<DatabaseContainerTab databaseId={tab.id} />
|
||||||
.with(IdType.Record, () => (
|
))
|
||||||
<RecordContainerTab recordId={tab.id} />
|
.with(IdType.Record, () => (
|
||||||
))
|
<RecordContainerTab recordId={tab.id} />
|
||||||
.with(IdType.Chat, () => <ChatContainerTab chatId={tab.id} />)
|
))
|
||||||
.with(IdType.Folder, () => (
|
.with(IdType.Chat, () => <ChatContainerTab chatId={tab.id} />)
|
||||||
<FolderContainerTab folderId={tab.id} />
|
.with(IdType.Folder, () => (
|
||||||
))
|
<FolderContainerTab folderId={tab.id} />
|
||||||
.with(IdType.File, () => <FileContainerTab fileId={tab.id} />)
|
))
|
||||||
.otherwise(() => null)}
|
.with(IdType.File, () => <FileContainerTab fileId={tab.id} />)
|
||||||
|
.otherwise(() => null)}
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="opacity-0 group-hover/tab:opacity-100 group-data-[state=active]/tab:opacity-100 transition-opacity duration-200"
|
className="opacity-0 group-hover/tab:opacity-100 group-data-[state=active]/tab:opacity-100 transition-opacity duration-200 flex-shrink-0"
|
||||||
onClick={() => onClose(tab.id)}
|
onClick={() => onClose(tab.id)}
|
||||||
>
|
>
|
||||||
<X className="size-4 text-muted-foreground ml-2 hover:text-primary" />
|
<X className="size-4 text-muted-foreground hover:text-primary" />
|
||||||
</div>
|
</div>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
))}
|
))}
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<ScrollBar orientation="horizontal" />
|
<ScrollBar orientation="horizontal" />
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
<div className="flex-grow overflow-hidden">
|
<div className="flex-grow overflow-hidden">
|
||||||
|
|||||||
@@ -274,12 +274,10 @@ export const useLayoutState = () => {
|
|||||||
if (!existingTab.active) {
|
if (!existingTab.active) {
|
||||||
replaceLeftContainerMetadata({
|
replaceLeftContainerMetadata({
|
||||||
...leftContainerMetadata,
|
...leftContainerMetadata,
|
||||||
tabs: leftContainerMetadata.tabs
|
tabs: leftContainerMetadata.tabs.map((t) => ({
|
||||||
.filter((t) => keepCurrent || !t.preview)
|
...t,
|
||||||
.map((t) => ({
|
active: t.id === tab ? true : undefined,
|
||||||
...t,
|
})),
|
||||||
active: t.id === tab ? true : undefined,
|
|
||||||
})),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,12 +308,10 @@ export const useLayoutState = () => {
|
|||||||
if (!existingTab.active) {
|
if (!existingTab.active) {
|
||||||
replaceRightContainerMetadata({
|
replaceRightContainerMetadata({
|
||||||
...rightContainerMetadata,
|
...rightContainerMetadata,
|
||||||
tabs: rightContainerMetadata.tabs
|
tabs: rightContainerMetadata.tabs.map((t) => ({
|
||||||
.filter((t) => keepCurrent || !t.preview)
|
...t,
|
||||||
.map((t) => ({
|
active: t.id === tab ? true : undefined,
|
||||||
...t,
|
})),
|
||||||
active: t.id === tab ? true : undefined,
|
|
||||||
})),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { Entry } from '@colanode/core';
|
|
||||||
|
|
||||||
export type EntryTreeGetQueryInput = {
|
|
||||||
type: 'entry_tree_get';
|
|
||||||
entryId: string;
|
|
||||||
accountId: string;
|
|
||||||
workspaceId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
declare module '@/shared/queries' {
|
|
||||||
interface QueryMap {
|
|
||||||
entry_tree_get: {
|
|
||||||
input: EntryTreeGetQueryInput;
|
|
||||||
output: Entry[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user