mirror of
https://github.com/AppFlowy-IO/AppFlowy-Web.git
synced 2025-12-01 03:47:55 +08:00
chore: fix switch view (#71)
* chore: fix switch view * chore: fix the issue of switch database view
This commit is contained in:
@@ -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]);
|
||||
|
||||
@@ -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>
|
||||
const handleViewChange = useCallback(
|
||||
(newViewId: string) => {
|
||||
setIsLoading(true);
|
||||
onChangeView(newViewId);
|
||||
},
|
||||
[onChangeView]
|
||||
);
|
||||
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 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>
|
||||
</>
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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}
|
||||
calendar={calendarData?.calendarApi}
|
||||
currentView={calendarData?.currentView}
|
||||
onViewChange={calendarData?.handleViewChange}
|
||||
slideDirection={slideDirection}
|
||||
emptyEvents={calendarData.emptyEvents}
|
||||
emptyEvents={calendarData?.emptyEvents}
|
||||
onDragStart={handleDragStart}
|
||||
draggingRowId={draggingRowId}
|
||||
onDragEnd={handleDragEnd}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Normal week header - always visible for comparison */}
|
||||
{calendarData && calendarData.shouldShowWeekHeader && (
|
||||
<StickyWeekHeader
|
||||
headerCells={calendarData.weekHeaderCells}
|
||||
headerCells={calendarData?.weekHeaderCells}
|
||||
visible={true}
|
||||
scrollLeft={calendarData.weekHeaderScrollLeft}
|
||||
currentView={calendarData.currentView}
|
||||
scrollLeft={calendarData?.weekHeaderScrollLeft}
|
||||
currentView={calendarData?.currentView}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Calendar content without toolbar */}
|
||||
<CalendarContent
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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' : ''} ${
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
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() {
|
||||
const { fields } = useRenderFields();
|
||||
@@ -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>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user