chore: fix switch view (#71)

* chore: fix switch view

* chore: fix the issue of switch database view
This commit is contained in:
Kilu.He
2025-09-12 10:06:43 +08:00
committed by GitHub
parent 02ac0ee3ee
commit 3e94fe7cde
10 changed files with 79 additions and 106 deletions

View File

@@ -73,15 +73,25 @@ function Database(props: Database2Props) {
const newRowMap: Record<RowId, YDoc> = {};
if (!rowIds || !createRowDoc) return;
for (const id of rowIds) {
const promises = rowIds.map(async (id) => {
if (!id) {
continue;
return;
}
const rowKey = `${doc.guid}_rows_${id}`;
const rowDoc = await createRowDoc(rowKey);
newRowMap[id] = await createRowDoc(rowKey);
}
return { id, rowDoc };
});
const results = await Promise.all(promises);
results.forEach((result) => {
if (result) {
newRowMap[result.id] = result.rowDoc;
}
});
setRowDocMap(newRowMap);
}, [createRowDoc, doc.guid, rowIds]);

View File

@@ -1,4 +1,3 @@
import { AnimatePresence, motion } from 'framer-motion';
import { Suspense, useCallback, useEffect, useMemo, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
@@ -13,6 +12,7 @@ import { DatabaseTabs } from '@/components/database/components/tabs';
import { Calendar } from '@/components/database/fullcalendar';
import { Grid } from '@/components/database/grid';
import { ElementFallbackRender } from '@/components/error/ElementFallbackRender';
import { Progress } from '@/components/ui/progress';
import DatabaseConditions from 'src/components/database/components/conditions/DatabaseConditions';
@@ -31,6 +31,7 @@ function DatabaseViews({
}) {
const { childViews, viewIds } = useDatabaseViewsSelector(iidIndex, visibleViewIds);
const [isLoading, setIsLoading] = useState(false);
const [layout, setLayout] = useState<DatabaseViewLayout | null>(null);
const value = useMemo(() => {
return Math.max(
@@ -54,6 +55,7 @@ function DatabaseViews({
const observerEvent = () => {
setLayout(Number(activeView.get(YjsDatabaseKey.layout)) as DatabaseViewLayout);
setIsLoading(false);
};
observerEvent();
@@ -65,61 +67,13 @@ function DatabaseViews({
};
}, [activeView]);
const view = useMemo(() => {
// 使用 viewId 和 layout 的组合作为 key确保在任一变化时都有动画
const animationKey = `${layout}-${viewId}`;
switch (layout) {
case DatabaseViewLayout.Grid:
return (
<motion.div
key={animationKey}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{
duration: 0.15,
ease: 'easeOut',
}}
className="h-full w-full"
>
<Grid />
</motion.div>
);
case DatabaseViewLayout.Board:
return (
<motion.div
key={animationKey}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{
duration: 0.15,
ease: 'easeOut',
}}
className="h-full w-full"
>
<Board />
</motion.div>
);
case DatabaseViewLayout.Calendar:
return (
<motion.div
key={animationKey}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{
duration: 0.15,
ease: 'easeOut',
}}
className="h-full w-full"
>
<Calendar />
</motion.div>
);
}
}, [layout, viewId]);
const handleViewChange = useCallback(
(newViewId: string) => {
setIsLoading(true);
onChangeView(newViewId);
},
[onChangeView]
);
const skeleton = useMemo(() => {
switch (layout) {
@@ -134,6 +88,17 @@ function DatabaseViews({
}
}, [layout]);
const view = useMemo(() => {
switch (layout) {
case DatabaseViewLayout.Grid:
return <Grid />;
case DatabaseViewLayout.Board:
return <Board />;
case DatabaseViewLayout.Calendar:
return <Calendar />;
}
}, [layout]);
return (
<>
<DatabaseConditionsContext.Provider
@@ -148,19 +113,20 @@ function DatabaseViews({
viewName={viewName}
iidIndex={iidIndex}
selectedViewId={viewId}
setSelectedViewId={onChangeView}
setSelectedViewId={handleViewChange}
viewIds={viewIds}
/>
<DatabaseConditions />
<div className={'flex h-full w-full flex-1 flex-col overflow-hidden'}>
<div className={'relative flex h-full w-full flex-1 flex-col overflow-hidden'}>
<Suspense fallback={skeleton}>
<ErrorBoundary fallbackRender={ElementFallbackRender}>
<AnimatePresence mode="wait">
{view}
</AnimatePresence>
</ErrorBoundary>
<ErrorBoundary fallbackRender={ElementFallbackRender}>{view}</ErrorBoundary>
</Suspense>
{isLoading && (
<div className='absolute inset-0 z-50 flex items-center justify-center bg-white/50 backdrop-blur-sm'>
<Progress />
</div>
)}
</div>
</DatabaseConditionsContext.Provider>
</>

View File

@@ -18,7 +18,7 @@ import { NoDateButton } from './NoDateButton';
import { CalendarViewType } from './types';
interface CustomToolbarProps {
calendar: CalendarApi | null;
calendar?: CalendarApi | null;
onViewChange?: (view: CalendarViewType) => void;
slideDirection?: 'up' | 'down' | null;
emptyEvents?: CalendarEvent[];

View File

@@ -103,30 +103,26 @@ function Calendar() {
return (
<div className='calendar-wrapper pb-5'>
{/* Normal toolbar - always visible */}
{calendarData && (
<div ref={normalToolbarRef}>
<StickyCalendarToolbar
calendar={calendarData.calendarApi}
currentView={calendarData.currentView}
onViewChange={calendarData.handleViewChange}
slideDirection={slideDirection}
emptyEvents={calendarData.emptyEvents}
onDragStart={handleDragStart}
draggingRowId={draggingRowId}
onDragEnd={handleDragEnd}
/>
</div>
)}
<div ref={normalToolbarRef}>
<StickyCalendarToolbar
calendar={calendarData?.calendarApi}
currentView={calendarData?.currentView}
onViewChange={calendarData?.handleViewChange}
slideDirection={slideDirection}
emptyEvents={calendarData?.emptyEvents}
onDragStart={handleDragStart}
draggingRowId={draggingRowId}
onDragEnd={handleDragEnd}
/>
</div>
{/* Normal week header - always visible for comparison */}
{calendarData && calendarData.shouldShowWeekHeader && (
<StickyWeekHeader
headerCells={calendarData.weekHeaderCells}
visible={true}
scrollLeft={calendarData.weekHeaderScrollLeft}
currentView={calendarData.currentView}
/>
)}
<StickyWeekHeader
headerCells={calendarData?.weekHeaderCells}
visible={true}
scrollLeft={calendarData?.weekHeaderScrollLeft}
currentView={calendarData?.currentView}
/>
{/* Calendar content without toolbar */}
<CalendarContent

View File

@@ -10,9 +10,9 @@ import { CalendarViewType } from './types';
* Props for StickyCalendarToolbar component
*/
interface StickyCalendarToolbarProps {
calendar: CalendarApi | null;
currentView: CalendarViewType;
onViewChange: (view: CalendarViewType) => void;
calendar?: CalendarApi | null;
currentView?: CalendarViewType;
onViewChange?: (view: CalendarViewType) => void;
slideDirection?: 'up' | 'down' | null;
emptyEvents?: CalendarEvent[];
onDragStart?: (rowId: string) => void;

View File

@@ -19,7 +19,7 @@ interface HeaderCellData {
* Props for StickyWeekHeader component
*/
interface StickyWeekHeaderProps {
headerCells: HeaderCellData[];
headerCells?: HeaderCellData[];
visible: boolean;
scrollLeft?: number;
currentView?: CalendarViewType;
@@ -59,7 +59,7 @@ export function StickyWeekHeader({
return currentView === CalendarViewType.TIME_GRID_WEEK;
}, [currentView]);
if (!visible || headerCells.length === 0) {
if (!visible || headerCells?.length === 0) {
return null;
}
@@ -110,7 +110,7 @@ export function StickyWeekHeader({
)}
{/* Date columns */}
{headerCells.map((cell, index) => (
{headerCells?.map((cell, index) => (
<th
key={index}
className={`fc-col-header-cell ${cell.isToday ? 'fc-day-today' : ''} ${

View File

@@ -6,7 +6,7 @@ import { createHotkey, HOT_KEY_NAME, isInputElement } from '@/utils/hotkeys';
import { CalendarViewType } from '../types';
interface UseCalendarKeyboardShortcutsProps {
calendar: CalendarApi | null;
calendar?: CalendarApi | null;
currentView: CalendarViewType;
onViewChange?: (view: CalendarViewType) => void;
onPrev?: () => void;

View File

@@ -1,4 +1,4 @@
import { lazy } from 'react';
export const Calendar = lazy(() => import('./FullCalendar'));
export * from './event';
export * from './event';

View File

@@ -1,10 +1,11 @@
import { useEffect } from 'react';
import { useDatabaseContext, useDatabaseViewId } from '@/application/database-yjs';
import { useRenderFields } from '@/components/database/components/grid/grid-column';
import GridVirtualizer from '@/components/database/components/grid/grid-table/GridVirtualizer';
import { GridProvider } from '@/components/database/grid/GridProvider';
import { useEffect } from 'react';
export function Grid () {
export function Grid() {
const { fields } = useRenderFields();
const viewId = useDatabaseViewId();
@@ -18,13 +19,13 @@ export function Grid () {
return (
<GridProvider>
<div data-testid="database-grid" className={`database-grid relative grid-table-${viewId} flex w-full flex-1 flex-col`}>
<GridVirtualizer
columns={fields}
/>
<div
data-testid='database-grid'
className={`database-grid relative grid-table-${viewId} flex w-full flex-1 flex-col`}
>
<GridVirtualizer columns={fields} />
</div>
</GridProvider>
);
}

View File

@@ -185,7 +185,7 @@ export const useSync = (ws: AppflowyWebSocketType, bc: BroadcastChannelType, eve
return existingContext;
}
console.log(`Registering sync context for objectId ${context.doc.guid} with collabType ${context.collabType}`);
console.debug(`Registering sync context for objectId ${context.doc.guid} with collabType ${context.collabType}`);
context.emit = (message) => {
sendMessage(message);
postMessage(message);