mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: implement the interface of move nested views (#3042)
* fix: implement the interface of move nested views * fix: update rust ci ubuntu version * fix: update rust ci version
This commit is contained in:
parent
6e9a5a16a6
commit
915ce02157
14
.github/workflows/rust_ci.yaml
vendored
14
.github/workflows/rust_ci.yaml
vendored
@ -22,7 +22,6 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUST_TOOLCHAIN: "1.70"
|
||||
FLUTTER_VERSION: "3.10.1"
|
||||
|
||||
jobs:
|
||||
test-on-ubuntu:
|
||||
@ -40,14 +39,6 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
profile: minimal
|
||||
|
||||
- name: Install flutter
|
||||
id: flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install prerequisites
|
||||
working-directory: frontend
|
||||
run: |
|
||||
@ -60,11 +51,6 @@ jobs:
|
||||
workspaces: |
|
||||
frontend/rust-lib
|
||||
|
||||
- name: Build FlowySDK
|
||||
working-directory: frontend
|
||||
run: |
|
||||
cargo make --profile development-linux-x86_64 appflowy-core-dev
|
||||
|
||||
- name: Run rust-lib tests
|
||||
working-directory: frontend/rust-lib
|
||||
run: RUST_LOG=info RUST_BACKTRACE=1 cargo test --no-default-features --features="rev-sqlite"
|
||||
|
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -105,7 +105,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1030,7 +1030,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1048,7 +1048,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -1066,7 +1066,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1093,7 +1093,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1105,7 +1105,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1124,7 +1124,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -1144,7 +1144,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1164,7 +1164,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1198,7 +1198,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
|
@ -34,18 +34,18 @@ default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
|
||||
#collab = { path = "../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../AppFlowy-Collab/collab-folder" }
|
||||
#collab-document = { path = "../../AppFlowy-Collab/collab-document" }
|
||||
#collab-database = { path = "../../AppFlowy-Collab/collab-database" }
|
||||
#appflowy-integrate = { path = "../../AppFlowy-Collab/appflowy-integrate" }
|
||||
#collab = { path = "../../../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../../../AppFlowy-Collab/collab-folder" }
|
||||
#collab-document = { path = "../../../../AppFlowy-Collab/collab-document" }
|
||||
#collab-database = { path = "../../../../AppFlowy-Collab/collab-database" }
|
||||
#appflowy-integrate = { path = "../../../../AppFlowy-Collab/appflowy-integrate" }
|
||||
|
||||
|
||||
|
||||
|
@ -94,8 +94,12 @@ function BlockDragDropContext({ children }: { children: React.ReactNode }) {
|
||||
const draggingNode = document.querySelector(`[data-draggable-id="${draggingId}"]`);
|
||||
|
||||
if (!draggingNode) return;
|
||||
const nodeWidth = draggingNode.clientWidth;
|
||||
const nodeHeight = draggingNode.clientHeight;
|
||||
const clone = draggingNode.cloneNode(true);
|
||||
|
||||
shadow.style.width = `${nodeWidth}px`;
|
||||
shadow.style.height = `${nodeHeight}px`;
|
||||
shadow.appendChild(clone);
|
||||
}, [dragShadowVisible, draggingId]);
|
||||
|
||||
@ -111,7 +115,6 @@ function BlockDragDropContext({ children }: { children: React.ReactNode }) {
|
||||
pointerEvents: 'none',
|
||||
opacity: dragShadowVisible ? 1 : 0,
|
||||
zIndex: 1000,
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
@ -1,10 +1,9 @@
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useAppDispatch, useAppSelector } from '$app/stores/store';
|
||||
import { blockDraggableActions, BlockDraggableType, DragInsertType } from '$app_reducers/block-draggable/slice';
|
||||
import { getDragDropContext } from '$app/utils/draggable';
|
||||
|
||||
export function useDraggableState(id: string, type: BlockDraggableType) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const dispatch = useAppDispatch();
|
||||
const { dropState, isDragging } = useAppSelector((state) => {
|
||||
const draggableState = state.blockDraggable;
|
||||
@ -28,7 +27,6 @@ export function useDraggableState(id: string, type: BlockDraggableType) {
|
||||
|
||||
const onDragStart = useCallback(
|
||||
(event: React.MouseEvent | MouseEvent) => {
|
||||
if (!ref.current) return;
|
||||
if (event.button !== 0) return;
|
||||
|
||||
event.preventDefault();
|
||||
@ -73,7 +71,6 @@ export function useDraggableState(id: string, type: BlockDraggableType) {
|
||||
|
||||
return {
|
||||
onDragStart,
|
||||
ref,
|
||||
beforeDropping,
|
||||
afterDropping,
|
||||
childDropping,
|
||||
|
@ -1,19 +1,24 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { HTMLAttributes, useEffect } from 'react';
|
||||
import { useDraggableState } from '$app/components/_shared/BlockDraggable/BlockDraggable.hooks';
|
||||
import { BlockDraggableType } from '$app_reducers/block-draggable/slice';
|
||||
|
||||
function BlockDraggable({
|
||||
id,
|
||||
type,
|
||||
children,
|
||||
getAnchorEl,
|
||||
}: {
|
||||
id: string;
|
||||
type: BlockDraggableType;
|
||||
children: React.ReactNode;
|
||||
getAnchorEl?: () => HTMLElement | null;
|
||||
}) {
|
||||
const { onDragStart, ref, beforeDropping, afterDropping, childDropping, isDragging } = useDraggableState(id, type);
|
||||
function BlockDraggable(
|
||||
{
|
||||
id,
|
||||
type,
|
||||
children,
|
||||
getAnchorEl,
|
||||
className,
|
||||
...props
|
||||
}: {
|
||||
id: string;
|
||||
type: BlockDraggableType;
|
||||
children: React.ReactNode;
|
||||
getAnchorEl?: () => HTMLElement | null;
|
||||
} & HTMLAttributes<HTMLDivElement>,
|
||||
ref: React.Ref<HTMLDivElement>
|
||||
) {
|
||||
const { onDragStart, beforeDropping, afterDropping, childDropping, isDragging } = useDraggableState(id, type);
|
||||
|
||||
const commonCls = 'pointer-events-none absolute z-10 w-[100%] bg-fill-hover transition-all duration-200';
|
||||
|
||||
@ -34,15 +39,16 @@ function BlockDraggable({
|
||||
data-draggable-id={id}
|
||||
data-draggable-type={type}
|
||||
onMouseDown={getAnchorEl ? undefined : onDragStart}
|
||||
className={'relative'}
|
||||
className={`relative ${className || ''}`}
|
||||
style={{
|
||||
opacity: isDragging ? 0.7 : 1,
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{
|
||||
<div
|
||||
style={{
|
||||
display: beforeDropping ? 'block' : 'none',
|
||||
visibility: beforeDropping ? 'visible' : 'hidden',
|
||||
}}
|
||||
className={`${commonCls} left-0 top-[-2px] h-[4px]`}
|
||||
/>
|
||||
@ -52,7 +58,7 @@ function BlockDraggable({
|
||||
{
|
||||
<div
|
||||
style={{
|
||||
display: childDropping ? 'block' : 'none',
|
||||
visibility: childDropping ? 'visible' : 'hidden',
|
||||
}}
|
||||
className={`${commonCls} left-0 top-0 h-[100%] opacity-[0.3]`}
|
||||
/>
|
||||
@ -60,7 +66,7 @@ function BlockDraggable({
|
||||
{
|
||||
<div
|
||||
style={{
|
||||
display: afterDropping ? 'block' : 'none',
|
||||
visibility: afterDropping ? 'visible' : 'hidden',
|
||||
}}
|
||||
className={`${commonCls} bottom-[-2px] left-0 h-[4px]`}
|
||||
/>
|
||||
@ -70,4 +76,4 @@ function BlockDraggable({
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(BlockDraggable);
|
||||
export default React.memo(React.forwardRef(BlockDraggable));
|
||||
|
@ -8,10 +8,10 @@ import { RANGE_NAME, RECT_RANGE_NAME } from '$app/constants/document/name';
|
||||
import { getNode } from '$app/utils/document/node';
|
||||
import { get } from '$app/utils/tool';
|
||||
|
||||
const headingBlockTopOffset: Record<number, number> = {
|
||||
1: 6,
|
||||
2: 4,
|
||||
3: 3,
|
||||
const headingBlockTopOffset: Record<number, string> = {
|
||||
1: '1.65rem',
|
||||
2: '1.3rem',
|
||||
3: '0.25rem',
|
||||
};
|
||||
|
||||
export function useBlockSideToolbar(id: string) {
|
||||
|
@ -29,7 +29,7 @@ export default function BlockSideToolbar({ id }: { id: string }) {
|
||||
opacity: show ? 1 : 0,
|
||||
top: topOffset,
|
||||
}}
|
||||
className='absolute left-[-50px] inline-flex h-[calc(1.5em_+_3px)] transition-opacity duration-100'
|
||||
className='absolute left-[-50px] inline-flex transition-opacity duration-100'
|
||||
>
|
||||
{/** Add Block below */}
|
||||
<Tooltip disableInteractive={true} title={t('blockActions.addBelowTooltip')} placement={'top-start'}>
|
||||
@ -59,7 +59,16 @@ export default function BlockSideToolbar({ id }: { id: string }) {
|
||||
</Tooltip>
|
||||
|
||||
{/** Open menu or drag */}
|
||||
<Tooltip disableInteractive={true} title={t('blockActions.dragAndOpenTooltip')} placement={'top-start'}>
|
||||
<Tooltip
|
||||
disableInteractive={true}
|
||||
title={
|
||||
<div className={'flex flex-col items-center justify-center'}>
|
||||
<div>{t('blockActions.dragTooltip')}</div>
|
||||
<div>{t('blockActions.openMenuTooltip')}</div>
|
||||
</div>
|
||||
}
|
||||
placement={'top-start'}
|
||||
>
|
||||
<IconButton
|
||||
style={{
|
||||
pointerEvents: show ? 'auto' : 'none',
|
||||
|
@ -87,14 +87,16 @@ function NodeComponent({ id, ...props }: { id: string } & React.HTMLAttributes<H
|
||||
getAnchorEl={() => {
|
||||
return ref.current?.querySelector(`[data-draggable-anchor="${id}"]`) || null;
|
||||
}}
|
||||
{...props}
|
||||
ref={ref}
|
||||
data-block-id={node.id}
|
||||
className={`pt-[0.5px] ${className}`}
|
||||
>
|
||||
<div {...props} ref={ref} data-block-id={node.id} className={`relative ${className}`}>
|
||||
{renderBlock()}
|
||||
<BlockOverlay id={id} />
|
||||
{isSelected ? (
|
||||
<div className='pointer-events-none absolute inset-0 z-[-1] my-[1px] rounded-[4px] bg-content-blue-100' />
|
||||
) : null}
|
||||
</div>
|
||||
{renderBlock()}
|
||||
<BlockOverlay id={id} />
|
||||
{isSelected ? (
|
||||
<div className='pointer-events-none absolute inset-0 z-[-1] my-[1px] rounded-[4px] bg-content-blue-100' />
|
||||
) : null}
|
||||
</BlockDraggable>
|
||||
</NodeIdContext.Provider>
|
||||
);
|
||||
|
@ -49,12 +49,7 @@ export default function VirtualizedList({
|
||||
const id = childIds[virtualRow.index];
|
||||
|
||||
return (
|
||||
<div
|
||||
className='mt-[-0.5px] pt-[0.5px]'
|
||||
key={id}
|
||||
data-index={virtualRow.index}
|
||||
ref={virtualize.measureElement}
|
||||
>
|
||||
<div key={id} data-index={virtualRow.index} ref={virtualize.measureElement}>
|
||||
{virtualRow.index === 0 ? <DocumentTitle id={node.id} /> : null}
|
||||
{renderNode(id)}
|
||||
</div>
|
||||
|
@ -36,6 +36,13 @@ export function useLoadChildPages(pageId: string) {
|
||||
[dispatch, pageId]
|
||||
);
|
||||
|
||||
const onPageChanged = useCallback(
|
||||
(page: Page) => {
|
||||
dispatch(pagesActions.onPageChanged(page));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const onPageCollapsed = useCallback(async () => {
|
||||
dispatch(pagesActions.removeChildPages(pageId));
|
||||
await controller.unsubscribe();
|
||||
@ -52,8 +59,9 @@ export function useLoadChildPages(pageId: string) {
|
||||
);
|
||||
await controller.subscribe({
|
||||
onChildPagesChanged,
|
||||
onPageChanged,
|
||||
});
|
||||
}, [controller, dispatch, onChildPagesChanged, pageId]);
|
||||
}, [controller, dispatch, onChildPagesChanged, onPageChanged, pageId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (collapsed) {
|
||||
|
@ -11,7 +11,7 @@ function NestedPage({ pageId }: { pageId: string }) {
|
||||
const { onAddPage, onPageClick, onDeletePage, onDuplicatePage, onRenamePage } = usePageActions(pageId);
|
||||
|
||||
return (
|
||||
<BlockDraggable id={pageId} type={BlockDraggableType.PAGE}>
|
||||
<BlockDraggable id={pageId} type={BlockDraggableType.PAGE} data-page-id={pageId}>
|
||||
<NestedPageTitle
|
||||
onClick={() => {
|
||||
onPageClick();
|
||||
|
@ -17,6 +17,7 @@ import {
|
||||
MoveGroupRowPayloadPB,
|
||||
MoveRowPayloadPB,
|
||||
RowIdPB,
|
||||
DatabaseEventUpdateDatabaseSetting,
|
||||
} from '@/services/backend/events/flowy-database2';
|
||||
import {
|
||||
GetFieldPayloadPB,
|
||||
@ -41,12 +42,14 @@ export class DatabaseBackendService {
|
||||
const payload = DatabaseViewIdPB.fromObject({
|
||||
value: this.viewId,
|
||||
});
|
||||
|
||||
return DatabaseEventGetDatabase(payload);
|
||||
};
|
||||
|
||||
/// Close a database
|
||||
closeDatabase = async () => {
|
||||
const payload = ViewIdPB.fromObject({ value: this.viewId });
|
||||
|
||||
return FolderEventCloseView(payload);
|
||||
};
|
||||
|
||||
@ -57,6 +60,7 @@ export class DatabaseBackendService {
|
||||
/// only support in kanban board.
|
||||
createRow = async (params?: { rowId?: string; groupId?: string }) => {
|
||||
const payload = CreateRowPayloadPB.fromObject({ view_id: this.viewId });
|
||||
|
||||
if (params?.rowId !== undefined) {
|
||||
payload.start_row_id = params.rowId;
|
||||
}
|
||||
@ -64,16 +68,19 @@ export class DatabaseBackendService {
|
||||
if (params?.groupId !== undefined) {
|
||||
payload.group_id = params.groupId;
|
||||
}
|
||||
|
||||
return DatabaseEventCreateRow(payload);
|
||||
};
|
||||
|
||||
duplicateRow = async (rowId: string) => {
|
||||
const payload = RowIdPB.fromObject({ view_id: this.viewId, row_id: rowId });
|
||||
|
||||
return DatabaseEventDuplicateRow(payload);
|
||||
};
|
||||
|
||||
deleteRow = async (rowId: string) => {
|
||||
const payload = RowIdPB.fromObject({ view_id: this.viewId, row_id: rowId });
|
||||
|
||||
return DatabaseEventDeleteRow(payload);
|
||||
};
|
||||
|
||||
@ -85,6 +92,7 @@ export class DatabaseBackendService {
|
||||
from_row_id: fromRowId,
|
||||
to_group_id: toGroupId,
|
||||
});
|
||||
|
||||
if (toRowId !== undefined) {
|
||||
payload.to_row_id = toRowId;
|
||||
}
|
||||
@ -98,6 +106,7 @@ export class DatabaseBackendService {
|
||||
from_group_id: fromGroupId,
|
||||
to_group_id: toGroupId,
|
||||
});
|
||||
|
||||
return DatabaseEventMoveGroup(payload);
|
||||
};
|
||||
|
||||
@ -115,6 +124,7 @@ export class DatabaseBackendService {
|
||||
/// Get a group by id
|
||||
getGroup = (groupId: string) => {
|
||||
const payload = DatabaseGroupIdPB.fromObject({ view_id: this.viewId, group_id: groupId });
|
||||
|
||||
return DatabaseEventGetGroup(payload);
|
||||
};
|
||||
|
||||
@ -125,6 +135,7 @@ export class DatabaseBackendService {
|
||||
from_index: params.fromIndex,
|
||||
to_index: params.toIndex,
|
||||
});
|
||||
|
||||
return DatabaseEventMoveField(payload);
|
||||
};
|
||||
|
||||
@ -132,11 +143,13 @@ export class DatabaseBackendService {
|
||||
/// It should only call once after the board open
|
||||
loadGroups = () => {
|
||||
const payload = DatabaseViewIdPB.fromObject({ value: this.viewId });
|
||||
|
||||
return DatabaseEventGetGroups(payload);
|
||||
};
|
||||
|
||||
getSettings = () => {
|
||||
const payload = DatabaseViewIdPB.fromObject({ value: this.viewId });
|
||||
|
||||
return DatabaseEventGetDatabaseSetting(payload);
|
||||
};
|
||||
}
|
||||
|
@ -6,14 +6,14 @@ import {
|
||||
FolderEventDuplicateView,
|
||||
FolderEventCloseView,
|
||||
FolderEventImportData,
|
||||
FolderEventMoveView,
|
||||
ViewIdPB,
|
||||
CreateViewPayloadPB,
|
||||
UpdateViewPayloadPB,
|
||||
RepeatedViewIdPB,
|
||||
ViewPB,
|
||||
ImportPB,
|
||||
MoveViewPayloadPB,
|
||||
MoveNestedViewPayloadPB,
|
||||
FolderEventMoveNestedView,
|
||||
} from '@/services/backend/events/flowy-folder2';
|
||||
import { Page } from '$app_reducers/pages/slice';
|
||||
|
||||
@ -31,16 +31,13 @@ export class PageBackendService {
|
||||
};
|
||||
|
||||
movePage = async (params: { viewId: string; parentId: string; prevId?: string }) => {
|
||||
console.log('movePage', params);
|
||||
const payload = new MoveViewPayloadPB({
|
||||
const payload = new MoveNestedViewPayloadPB({
|
||||
view_id: params.viewId,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
parent_view_id: params.parentId,
|
||||
new_parent_id: params.parentId,
|
||||
prev_view_id: params.prevId,
|
||||
});
|
||||
|
||||
return FolderEventMoveView(payload);
|
||||
return FolderEventMoveNestedView(payload);
|
||||
};
|
||||
|
||||
createPage = async (params: ReturnType<typeof CreateViewPayloadPB.prototype.toObject>) => {
|
||||
|
@ -72,16 +72,22 @@ export class PageController {
|
||||
return this.getPage(parentPageId);
|
||||
};
|
||||
|
||||
subscribe = async (callbacks: { onChildPagesChanged?: (childPages: Page[]) => void }) => {
|
||||
const onChildPagesChanged = async () => {
|
||||
subscribe = async (callbacks: {
|
||||
onChildPagesChanged?: (childPages: Page[]) => void;
|
||||
onPageChanged?: (page: Page) => void;
|
||||
}) => {
|
||||
const onChanged = async () => {
|
||||
const page = await this.getPage();
|
||||
const childPages = await this.getChildPages();
|
||||
|
||||
callbacks.onPageChanged?.(page);
|
||||
callbacks.onChildPagesChanged?.(childPages);
|
||||
};
|
||||
|
||||
this.onChangeQueue = new AsyncQueue(onChildPagesChanged);
|
||||
this.onChangeQueue = new AsyncQueue(onChanged);
|
||||
await this.observer.subscribeView(this.id, {
|
||||
didUpdateChildViews: this.didUpdateChildPages,
|
||||
didUpdateView: this.didUpdateView,
|
||||
});
|
||||
};
|
||||
|
||||
@ -123,4 +129,8 @@ export class PageController {
|
||||
private didUpdateChildPages = (payload: Uint8Array) => {
|
||||
this.onChangeQueue?.enqueue(Math.random());
|
||||
};
|
||||
|
||||
private didUpdateView = (payload: Uint8Array) => {
|
||||
this.onChangeQueue?.enqueue(Math.random());
|
||||
};
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ export class WorkspaceObserver {
|
||||
viewId: string,
|
||||
callbacks: {
|
||||
didUpdateChildViews: (payload: Uint8Array) => void;
|
||||
didUpdateView: (payload: Uint8Array) => void;
|
||||
}
|
||||
) => {
|
||||
this.listener = new WorkspaceNotificationObserver({
|
||||
@ -69,6 +70,10 @@ export class WorkspaceObserver {
|
||||
if (!result.ok) break;
|
||||
callbacks.didUpdateChildViews(result.val);
|
||||
break;
|
||||
case FolderNotification.DidUpdateView:
|
||||
if (!result.ok) break;
|
||||
callbacks.didUpdateView(result.val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -61,6 +61,12 @@ export const pagesSlice = createSlice({
|
||||
state.relationMap[id] = children;
|
||||
},
|
||||
|
||||
onPageChanged(state, action: PayloadAction<Page>) {
|
||||
const page = action.payload;
|
||||
|
||||
state.pageMap[page.id] = page;
|
||||
},
|
||||
|
||||
removeChildPages(state, action: PayloadAction<string>) {
|
||||
const parentId = action.payload;
|
||||
|
||||
|
@ -13,7 +13,8 @@
|
||||
"addAboveCmd": "Alt+click",
|
||||
"addAboveMacCmd": "Option+click",
|
||||
"addAboveTooltip": "to add above",
|
||||
"dragAndOpenTooltip": "Drag to reorder, click to open"
|
||||
"dragTooltip": "Drag to move",
|
||||
"openMenuTooltip": "Click to open menu"
|
||||
},
|
||||
"signUp": {
|
||||
"buttonText": "Sign Up",
|
||||
|
20
frontend/rust-lib/Cargo.lock
generated
20
frontend/rust-lib/Cargo.lock
generated
@ -85,7 +85,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -897,7 +897,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -915,7 +915,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -933,7 +933,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -960,7 +960,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -972,7 +972,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -991,7 +991,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -1011,7 +1011,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1031,7 +1031,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1065,7 +1065,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=52b550b#52b550b3dc3ff5969b92fea0c0a2b03530d73d20"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
|
@ -34,15 +34,15 @@ opt-level = 3
|
||||
incremental = false
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "52b550b" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
|
||||
#collab = { path = "../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../AppFlowy-Collab/collab-folder" }
|
||||
#collab-database= { path = "../AppFlowy-Collab/collab-database" }
|
||||
#collab-document = { path = "../AppFlowy-Collab/collab-document" }
|
||||
#appflowy-integrate = { path = "../AppFlowy-Collab/appflowy-integrate" }
|
||||
#collab = { path = "../../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../../AppFlowy-Collab/collab-folder" }
|
||||
#collab-database= { path = "../../../AppFlowy-Collab/collab-database" }
|
||||
#collab-document = { path = "../../../AppFlowy-Collab/collab-document" }
|
||||
#appflowy-integrate = { path = "../../../AppFlowy-Collab/appflowy-integrate" }
|
||||
|
||||
|
@ -369,6 +369,26 @@ pub struct MoveViewPayloadPB {
|
||||
pub to: i32,
|
||||
}
|
||||
|
||||
/// * `view_id` - A string slice that holds the id of the view to be moved.
|
||||
/// * `new_parent_id` - A string slice that holds the id of the new parent view.
|
||||
/// * `prev_view_id` - An `Option<String>` that holds the id of the view after which the `view_id` should be positioned.
|
||||
///
|
||||
/// If `prev_view_id` is provided, the moved view will be placed right after
|
||||
/// the view corresponding to `prev_view_id` under the `new_parent_id`.
|
||||
///
|
||||
/// If `prev_view_id` is `None`, the moved view will become the first child of the new parent.
|
||||
#[derive(Default, ProtoBuf)]
|
||||
pub struct MoveNestedViewPayloadPB {
|
||||
#[pb(index = 1)]
|
||||
pub view_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub new_parent_id: String,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub prev_view_id: Option<String>,
|
||||
}
|
||||
|
||||
pub struct MoveViewParams {
|
||||
pub view_id: String,
|
||||
pub from: usize,
|
||||
@ -388,6 +408,27 @@ impl TryInto<MoveViewParams> for MoveViewPayloadPB {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MoveNestedViewParams {
|
||||
pub view_id: String,
|
||||
pub new_parent_id: String,
|
||||
pub prev_view_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<MoveNestedViewParams> for MoveNestedViewPayloadPB {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<MoveNestedViewParams, Self::Error> {
|
||||
let view_id = ViewIdentify::parse(self.view_id)?.0;
|
||||
let new_parent_id = ViewIdentify::parse(self.new_parent_id)?.0;
|
||||
let prev_view_id = self.prev_view_id;
|
||||
Ok(MoveNestedViewParams {
|
||||
view_id,
|
||||
new_parent_id,
|
||||
prev_view_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// impl<'de> Deserialize<'de> for ViewDataType {
|
||||
// fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
|
||||
// where
|
||||
|
@ -163,6 +163,17 @@ pub(crate) async fn move_view_handler(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn move_nested_view_handler(
|
||||
data: AFPluginData<MoveNestedViewPayloadPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let params: MoveNestedViewParams = data.into_inner().try_into()?;
|
||||
folder
|
||||
.move_nested_view(params.view_id, params.new_parent_id, params.prev_view_id)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn duplicate_view_handler(
|
||||
data: AFPluginData<ViewPB>,
|
||||
|
@ -29,6 +29,7 @@ pub fn init(folder: Arc<FolderManager>) -> AFPlugin {
|
||||
.event(FolderEvent::SetLatestView, set_latest_view_handler)
|
||||
.event(FolderEvent::CloseView, close_view_handler)
|
||||
.event(FolderEvent::MoveView, move_view_handler)
|
||||
.event(FolderEvent::MoveNestedView, move_nested_view_handler)
|
||||
// Trash
|
||||
.event(FolderEvent::ReadTrash, read_trash_handler)
|
||||
.event(FolderEvent::PutbackTrash, putback_trash_handler)
|
||||
@ -132,4 +133,13 @@ pub enum FolderEvent {
|
||||
|
||||
#[event()]
|
||||
GetFolderSnapshots = 31,
|
||||
|
||||
/// Moves a nested view to a new location in the hierarchy.
|
||||
///
|
||||
/// This function takes the `view_id` of the view to be moved,
|
||||
/// `new_parent_id` of the view under which the `view_id` should be moved,
|
||||
/// and an optional `prev_view_id` to position the `view_id` right after
|
||||
/// this specific view.
|
||||
#[event(input = "MoveNestedViewPayloadPB")]
|
||||
MoveNestedView = 32,
|
||||
}
|
||||
|
@ -450,6 +450,42 @@ impl FolderManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Moves a nested view to a new location in the hierarchy.
|
||||
///
|
||||
/// This function takes the `view_id` of the view to be moved,
|
||||
/// `new_parent_id` of the view under which the `view_id` should be moved,
|
||||
/// and an optional `prev_view_id` to position the `view_id` right after
|
||||
/// this specific view.
|
||||
///
|
||||
/// If `prev_view_id` is provided, the moved view will be placed right after
|
||||
/// the view corresponding to `prev_view_id` under the `new_parent_id`.
|
||||
/// If `prev_view_id` is `None`, the moved view will become the first child of the new parent.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `view_id` - A string slice that holds the id of the view to be moved.
|
||||
/// * `new_parent_id` - A string slice that holds the id of the new parent view.
|
||||
/// * `prev_view_id` - An `Option<String>` that holds the id of the view after which the `view_id` should be positioned.
|
||||
///
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn move_nested_view(
|
||||
&self,
|
||||
view_id: String,
|
||||
new_parent_id: String,
|
||||
prev_view_id: Option<String>,
|
||||
) -> FlowyResult<()> {
|
||||
let view = self.get_view(&view_id).await?;
|
||||
let old_parent_id = view.parent_view_id;
|
||||
self.with_folder((), |folder| {
|
||||
folder.move_nested_view(&view_id, &new_parent_id, prev_view_id);
|
||||
});
|
||||
notify_parent_view_did_change(
|
||||
self.mutex_folder.clone(),
|
||||
vec![new_parent_id, old_parent_id],
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Move the view with given id from one position to another position.
|
||||
/// The view will be moved to the new position in the same parent view.
|
||||
/// The passed in index is the index of the view that displayed in the UI.
|
||||
|
@ -248,3 +248,47 @@ async fn view_delete_all_permanent() {
|
||||
assert_eq!(test.parent_view.child_views.len(), 0);
|
||||
assert_eq!(test.trash.len(), 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_view_event_test() {
|
||||
let mut test = FolderTest::new().await;
|
||||
let parent_view = test.parent_view.clone();
|
||||
test
|
||||
.run_scripts(vec![
|
||||
CreateView {
|
||||
name: "View A".to_owned(),
|
||||
desc: "View A description".to_owned(),
|
||||
layout: ViewLayout::Document,
|
||||
},
|
||||
ReloadParentView(parent_view.id.clone()),
|
||||
])
|
||||
.await;
|
||||
let view_ids = test
|
||||
.parent_view
|
||||
.child_views
|
||||
.iter()
|
||||
.map(|view| view.id.clone())
|
||||
.collect::<Vec<String>>();
|
||||
let move_view_id = view_ids[0].clone();
|
||||
let new_prev_view_id = view_ids[1].clone();
|
||||
let new_parent_view_id = parent_view.id.clone();
|
||||
test
|
||||
.run_scripts(vec![
|
||||
MoveView {
|
||||
view_id: move_view_id.clone(),
|
||||
new_parent_id: new_parent_view_id.clone(),
|
||||
prev_view_id: Some(new_prev_view_id.clone()),
|
||||
},
|
||||
ReloadParentView(parent_view.id.clone()),
|
||||
])
|
||||
.await;
|
||||
|
||||
let after_view_ids = test
|
||||
.parent_view
|
||||
.child_views
|
||||
.iter()
|
||||
.map(|view| view.id.clone())
|
||||
.collect::<Vec<String>>();
|
||||
assert_eq!(after_view_ids[0], view_ids[1]);
|
||||
assert_eq!(after_view_ids[1], view_ids[0]);
|
||||
}
|
||||
|
@ -42,6 +42,11 @@ pub enum FolderScript {
|
||||
},
|
||||
DeleteView,
|
||||
DeleteViews(Vec<String>),
|
||||
MoveView {
|
||||
view_id: String,
|
||||
new_parent_id: String,
|
||||
prev_view_id: Option<String>,
|
||||
},
|
||||
|
||||
// Trash
|
||||
RestoreAppFromTrash,
|
||||
@ -128,6 +133,13 @@ impl FolderTest {
|
||||
let view = create_view(sdk, &self.parent_view.id, &name, &desc, layout).await;
|
||||
self.child_view = view;
|
||||
},
|
||||
FolderScript::MoveView {
|
||||
view_id,
|
||||
new_parent_id,
|
||||
prev_view_id,
|
||||
} => {
|
||||
move_view(sdk, view_id, new_parent_id, prev_view_id).await;
|
||||
},
|
||||
FolderScript::AssertView(view) => {
|
||||
assert_eq!(self.child_view, view, "View not equal");
|
||||
},
|
||||
@ -256,6 +268,23 @@ pub async fn read_view(sdk: &FlowyCoreTest, view_id: &str) -> ViewPB {
|
||||
.parse::<ViewPB>()
|
||||
}
|
||||
|
||||
pub async fn move_view(
|
||||
sdk: &FlowyCoreTest,
|
||||
view_id: String,
|
||||
parent_id: String,
|
||||
prev_view_id: Option<String>,
|
||||
) {
|
||||
let request = MoveNestedViewPayloadPB {
|
||||
view_id,
|
||||
new_parent_id: parent_id,
|
||||
prev_view_id,
|
||||
};
|
||||
EventBuilder::new(sdk.clone())
|
||||
.event(MoveNestedView)
|
||||
.payload(request)
|
||||
.async_send()
|
||||
.await;
|
||||
}
|
||||
pub async fn update_view(
|
||||
sdk: &FlowyCoreTest,
|
||||
view_id: &str,
|
||||
|
@ -508,3 +508,67 @@ fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> {
|
||||
("1234".repeat(100), ErrorCode::WorkspaceNameTooLong),
|
||||
]
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_view_across_parent_test() {
|
||||
let test = FlowyCoreTest::new_with_guest_user().await;
|
||||
let current_workspace = test.get_current_workspace().await.workspace;
|
||||
let parent_1 = test
|
||||
.create_view(¤t_workspace.id, "My view 1".to_string())
|
||||
.await;
|
||||
let parent_2 = test
|
||||
.create_view(¤t_workspace.id, "My view 2".to_string())
|
||||
.await;
|
||||
|
||||
for j in 1..6 {
|
||||
let _ = test
|
||||
.create_view(&parent_1.id, format!("My 1-{} view 1", j))
|
||||
.await;
|
||||
}
|
||||
|
||||
let views = test.get_view(&parent_1.id).await.child_views;
|
||||
// Move `My 1-1 view 1` to `My view 2`
|
||||
let move_view_id = views[0].id.clone();
|
||||
let new_parent_id = parent_2.id.clone();
|
||||
let prev_id = None;
|
||||
move_folder_nested_view(test.clone(), move_view_id, new_parent_id, prev_id).await;
|
||||
let parent1_views = test.get_view(&parent_1.id).await.child_views;
|
||||
let parent2_views = test.get_view(&parent_2.id).await.child_views;
|
||||
assert_eq!(parent2_views.len(), 1);
|
||||
assert_eq!(parent2_views[0].name, "My 1-1 view 1");
|
||||
assert_eq!(parent1_views[0].name, "My 1-2 view 1");
|
||||
|
||||
// Move My 1-2 view 1 from My view 1 to the current workspace and insert it after My view 1.
|
||||
let move_view_id = parent1_views[0].id.clone();
|
||||
let new_parent_id = current_workspace.id.clone();
|
||||
let prev_id = Some(parent_1.id.clone());
|
||||
move_folder_nested_view(test.clone(), move_view_id, new_parent_id, prev_id).await;
|
||||
let parent1_views = test.get_view(&parent_1.id).await.child_views;
|
||||
let workspace_views = test.get_all_workspace_views().await;
|
||||
let workspace_views_len = workspace_views.len();
|
||||
assert_eq!(parent1_views[0].name, "My 1-3 view 1");
|
||||
assert_eq!(workspace_views[workspace_views_len - 3].name, "My view 1");
|
||||
assert_eq!(
|
||||
workspace_views[workspace_views_len - 2].name,
|
||||
"My 1-2 view 1"
|
||||
);
|
||||
assert_eq!(workspace_views[workspace_views_len - 1].name, "My view 2");
|
||||
}
|
||||
|
||||
async fn move_folder_nested_view(
|
||||
sdk: FlowyCoreTest,
|
||||
view_id: String,
|
||||
new_parent_id: String,
|
||||
prev_view_id: Option<String>,
|
||||
) {
|
||||
let payload = MoveNestedViewPayloadPB {
|
||||
view_id,
|
||||
new_parent_id,
|
||||
prev_view_id,
|
||||
};
|
||||
EventBuilder::new(sdk)
|
||||
.event(flowy_folder2::event_map::FolderEvent::MoveNestedView)
|
||||
.payload(payload)
|
||||
.async_send()
|
||||
.await;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user