mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-23 20:18:42 +08:00
feat: delete work space
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
import Modal from '@/ui/modal';
|
||||||
|
import Input from '@/ui/input';
|
||||||
|
import {
|
||||||
|
StyledModalHeader,
|
||||||
|
StyledTextContent,
|
||||||
|
StyledModalWrapper,
|
||||||
|
StyledInputContent,
|
||||||
|
StyledButtonContent,
|
||||||
|
StyledWorkspaceName,
|
||||||
|
} from './style';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { ModalCloseButton } from '@/ui/modal';
|
||||||
|
import { Button } from '@/ui/button';
|
||||||
|
import { deleteWorkspace } from '@pathfinder/data-services';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
interface WorkspaceDeleteProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
workspaceName: string;
|
||||||
|
workspaceId: string;
|
||||||
|
nextWorkSpaceId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WorkspaceDelete = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
workspaceId,
|
||||||
|
workspaceName,
|
||||||
|
nextWorkSpaceId,
|
||||||
|
}: WorkspaceDeleteProps) => {
|
||||||
|
const [deleteStr, setDeleteStr] = useState<string>('');
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const handlerInputChange = (workspaceName: string) => {
|
||||||
|
setDeleteStr(workspaceName);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async () => {
|
||||||
|
await deleteWorkspace({ id: workspaceId });
|
||||||
|
router.push(`/workspace/${nextWorkSpaceId}`);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal open={open} onClose={onClose}>
|
||||||
|
<StyledModalWrapper>
|
||||||
|
<ModalCloseButton onClick={onClose} />
|
||||||
|
<StyledModalHeader>Delete Workspace</StyledModalHeader>
|
||||||
|
<StyledTextContent>
|
||||||
|
This action cannot be undone. This will permanently delete (
|
||||||
|
<StyledWorkspaceName>{workspaceName}</StyledWorkspaceName>) along with
|
||||||
|
all its content.
|
||||||
|
</StyledTextContent>
|
||||||
|
<StyledInputContent>
|
||||||
|
<Input
|
||||||
|
onChange={handlerInputChange}
|
||||||
|
placeholder="Please type “delete” to confirm"
|
||||||
|
value={deleteStr}
|
||||||
|
></Input>
|
||||||
|
</StyledInputContent>
|
||||||
|
<StyledButtonContent>
|
||||||
|
<Button shape="circle" onClick={onClose}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
disabled={deleteStr !== 'delete'}
|
||||||
|
onClick={handleDelete}
|
||||||
|
type="danger"
|
||||||
|
shape="circle"
|
||||||
|
style={{ marginLeft: '24px' }}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</StyledButtonContent>
|
||||||
|
</StyledModalWrapper>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkspaceDelete;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './delete';
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { styled } from '@/styles';
|
||||||
|
import { Button } from '@/ui/button';
|
||||||
|
|
||||||
|
export const StyledModalWrapper = styled('div')(({ theme }) => {
|
||||||
|
return {
|
||||||
|
position: 'relative',
|
||||||
|
padding: '0px',
|
||||||
|
width: '460px',
|
||||||
|
background: theme.colors.popoverBackground,
|
||||||
|
borderRadius: '12px',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledModalHeader = styled('div')(({ theme }) => {
|
||||||
|
return {
|
||||||
|
margin: '44px 0px 12px 0px',
|
||||||
|
width: '460px',
|
||||||
|
fontWeight: '600',
|
||||||
|
fontSize: '20px;',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: theme.colors.popoverColor,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// export const StyledModalContent = styled('div')(({ theme }) => {});
|
||||||
|
|
||||||
|
export const StyledTextContent = styled('div')(({ theme }) => {
|
||||||
|
return {
|
||||||
|
margin: 'auto',
|
||||||
|
width: '425px',
|
||||||
|
fontFamily: 'Avenir Next',
|
||||||
|
fontStyle: 'normal',
|
||||||
|
fontWeight: '400',
|
||||||
|
fontSize: '18px',
|
||||||
|
lineHeight: '26px',
|
||||||
|
textAlign: 'center',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledInputContent = styled('div')(({ theme }) => {
|
||||||
|
return {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'center',
|
||||||
|
margin: '40px 0 24px 0',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledButtonContent = styled('div')(({ theme }) => {
|
||||||
|
return {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'center',
|
||||||
|
margin: '0px 0 32px 0',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StyledWorkspaceName = styled('span')(({ theme }) => {
|
||||||
|
return {
|
||||||
|
color: '#E8178A',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// export const StyledCancelButton = styled(Button)(({ theme }) => {
|
||||||
|
// return {
|
||||||
|
// width: '100px',
|
||||||
|
// justifyContent: 'center',
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// export const StyledDeleteButton = styled(Button)(({ theme }) => {
|
||||||
|
// return {
|
||||||
|
// width: '100px',
|
||||||
|
// justifyContent: 'center',
|
||||||
|
// };
|
||||||
|
// });
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import Modal, { ModalCloseButton } from '@/ui/modal';
|
|
||||||
import {
|
import {
|
||||||
StyledDeleteButtonContainer,
|
StyledDeleteButtonContainer,
|
||||||
StyledSettingAvatar,
|
StyledSettingAvatar,
|
||||||
StyledSettingAvatarContent,
|
StyledSettingAvatarContent,
|
||||||
StyledSettingInputContainer,
|
StyledSettingInputContainer,
|
||||||
} from './style';
|
} from './style';
|
||||||
|
import { StyledSettingH2 } from '../style';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button } from '@/ui/button';
|
import { Button } from '@/ui/button';
|
||||||
@@ -12,15 +12,20 @@ import Input from '@/ui/input';
|
|||||||
import { Workspace, WorkspaceType } from '@pathfinder/data-services';
|
import { Workspace, WorkspaceType } from '@pathfinder/data-services';
|
||||||
import { useAppState } from '@/providers/app-state-provider';
|
import { useAppState } from '@/providers/app-state-provider';
|
||||||
import { WorkspaceDetails } from '@/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent';
|
import { WorkspaceDetails } from '@/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent';
|
||||||
import { StyledSettingH2 } from '../style';
|
import { WorkspaceDelete } from './delete';
|
||||||
|
import { Workspace as StoreWorkspaces } from '@blocksuite/store';
|
||||||
|
|
||||||
export const GeneralPage = ({
|
export const GeneralPage = ({
|
||||||
workspace,
|
workspace,
|
||||||
owner,
|
owner,
|
||||||
|
workspaces,
|
||||||
}: {
|
}: {
|
||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
owner: WorkspaceDetails[string]['owner'];
|
owner: WorkspaceDetails[string]['owner'];
|
||||||
|
workspaces: Record<string, StoreWorkspaces | null>;
|
||||||
}) => {
|
}) => {
|
||||||
const { workspaces, user, currentWorkspace } = useAppState();
|
const { user, currentWorkspace, workspacesMeta } = useAppState();
|
||||||
|
const [showDelete, setShowDelete] = useState<boolean>(false);
|
||||||
const [workspaceName, setWorkspaceName] = useState<string>(
|
const [workspaceName, setWorkspaceName] = useState<string>(
|
||||||
workspaces[workspace.id]?.meta.name ||
|
workspaces[workspace.id]?.meta.name ||
|
||||||
(workspace.type === WorkspaceType.Private && user
|
(workspace.type === WorkspaceType.Private && user
|
||||||
@@ -33,8 +38,28 @@ export const GeneralPage = ({
|
|||||||
currentWorkspace?.meta.setName(newName);
|
currentWorkspace?.meta.setName(newName);
|
||||||
workspaces[workspace.id]?.meta.setName(newName);
|
workspaces[workspace.id]?.meta.setName(newName);
|
||||||
};
|
};
|
||||||
|
const currentWorkspaceIndex = workspacesMeta.findIndex(
|
||||||
|
meta => meta.id === workspace.id
|
||||||
|
);
|
||||||
|
const nextWorkSpaceId =
|
||||||
|
currentWorkspaceIndex > workspacesMeta.length - 1
|
||||||
|
? workspacesMeta[currentWorkspaceIndex - 1]?.id
|
||||||
|
: workspacesMeta[currentWorkspaceIndex + 1]?.id;
|
||||||
|
const handleCloseDelete = () => {
|
||||||
|
setShowDelete(false);
|
||||||
|
};
|
||||||
|
const handleClickDelete = () => {
|
||||||
|
setShowDelete(true);
|
||||||
|
};
|
||||||
return workspace ? (
|
return workspace ? (
|
||||||
<div>
|
<div>
|
||||||
|
<WorkspaceDelete
|
||||||
|
open={showDelete}
|
||||||
|
onClose={handleCloseDelete}
|
||||||
|
workspaceName={workspaceName}
|
||||||
|
workspaceId={workspace.id}
|
||||||
|
nextWorkSpaceId={nextWorkSpaceId}
|
||||||
|
></WorkspaceDelete>
|
||||||
<StyledSettingH2 marginTop={56}>Workspace Avatar</StyledSettingH2>
|
<StyledSettingH2 marginTop={56}>Workspace Avatar</StyledSettingH2>
|
||||||
<StyledSettingAvatarContent>
|
<StyledSettingAvatarContent>
|
||||||
<StyledSettingAvatar
|
<StyledSettingAvatar
|
||||||
@@ -43,6 +68,7 @@ export const GeneralPage = ({
|
|||||||
>
|
>
|
||||||
W
|
W
|
||||||
</StyledSettingAvatar>
|
</StyledSettingAvatar>
|
||||||
|
{/* TODO: add upload logic */}
|
||||||
{/* {isOwner ? (
|
{/* {isOwner ? (
|
||||||
<StyledAvatarUploadBtn shape="round">upload</StyledAvatarUploadBtn>
|
<StyledAvatarUploadBtn shape="round">upload</StyledAvatarUploadBtn>
|
||||||
) : null} */}
|
) : null} */}
|
||||||
@@ -70,7 +96,7 @@ export const GeneralPage = ({
|
|||||||
></Input>
|
></Input>
|
||||||
</StyledSettingInputContainer>
|
</StyledSettingInputContainer>
|
||||||
<StyledDeleteButtonContainer>
|
<StyledDeleteButtonContainer>
|
||||||
<Button type="danger" shape="circle">
|
<Button type="danger" shape="circle" onClick={handleClickDelete}>
|
||||||
Delete Workspace
|
Delete Workspace
|
||||||
</Button>
|
</Button>
|
||||||
</StyledDeleteButtonContainer>
|
</StyledDeleteButtonContainer>
|
||||||
|
|||||||
@@ -40,17 +40,16 @@ import { InviteMembers } from '../invite-members/index';
|
|||||||
import {
|
import {
|
||||||
getWorkspaceMembers,
|
getWorkspaceMembers,
|
||||||
Workspace,
|
Workspace,
|
||||||
WorkspaceType,
|
|
||||||
Member,
|
Member,
|
||||||
removeMember,
|
removeMember,
|
||||||
} from '@pathfinder/data-services';
|
} from '@pathfinder/data-services';
|
||||||
import { Avatar } from '@mui/material';
|
import { Avatar } from '@mui/material';
|
||||||
import { Menu, MenuItem } from '@/ui/menu';
|
import { Menu, MenuItem } from '@/ui/menu';
|
||||||
import { toast } from '@/ui/toast';
|
import { toast } from '@/ui/toast';
|
||||||
import { useConfirm } from '@/providers/confirm-provider';
|
|
||||||
import { useAppState } from '@/providers/app-state-provider';
|
import { useAppState } from '@/providers/app-state-provider';
|
||||||
import { WorkspaceDetails } from '../workspace-slider-bar/WorkspaceSelector/SelectorPopperContent';
|
import { WorkspaceDetails } from '../workspace-slider-bar/WorkspaceSelector/SelectorPopperContent';
|
||||||
import { GeneralPage } from './general';
|
import { GeneralPage } from './general';
|
||||||
|
import { Workspace as StoreWorkspaces } from '@blocksuite/store';
|
||||||
|
|
||||||
enum ActiveTab {
|
enum ActiveTab {
|
||||||
'general' = 'general',
|
'general' = 'general',
|
||||||
@@ -68,6 +67,7 @@ type WorkspaceSettingProps = {
|
|||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
owner: WorkspaceDetails[string]['owner'];
|
owner: WorkspaceDetails[string]['owner'];
|
||||||
|
workspaces: Record<string, StoreWorkspaces | null>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const WorkspaceSettingTab = ({ activeTab, onTabChange }: SettingTabProps) => {
|
const WorkspaceSettingTab = ({ activeTab, onTabChange }: SettingTabProps) => {
|
||||||
@@ -115,8 +115,9 @@ export const WorkspaceSetting = ({
|
|||||||
onClose,
|
onClose,
|
||||||
workspace,
|
workspace,
|
||||||
owner,
|
owner,
|
||||||
|
workspaces,
|
||||||
}: WorkspaceSettingProps) => {
|
}: WorkspaceSettingProps) => {
|
||||||
const { workspaces, user } = useAppState();
|
const { user } = useAppState();
|
||||||
const [activeTab, setActiveTab] = useState<ActiveTab>(ActiveTab.general);
|
const [activeTab, setActiveTab] = useState<ActiveTab>(ActiveTab.general);
|
||||||
const handleTabChange = (tab: ActiveTab) => {
|
const handleTabChange = (tab: ActiveTab) => {
|
||||||
setActiveTab(tab);
|
setActiveTab(tab);
|
||||||
@@ -148,7 +149,11 @@ export const WorkspaceSetting = ({
|
|||||||
) : null}
|
) : null}
|
||||||
<StyledSettingContent>
|
<StyledSettingContent>
|
||||||
{activeTab === ActiveTab.general && (
|
{activeTab === ActiveTab.general && (
|
||||||
<GeneralPage workspace={workspace} owner={owner} />
|
<GeneralPage
|
||||||
|
workspace={workspace}
|
||||||
|
owner={owner}
|
||||||
|
workspaces={workspaces}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{activeTab === ActiveTab.members && workspace && (
|
{activeTab === ActiveTab.members && workspace && (
|
||||||
<MembersPage workspace={workspace} />
|
<MembersPage workspace={workspace} />
|
||||||
|
|||||||
+39
-2
@@ -12,7 +12,12 @@ import {
|
|||||||
} from './WorkspaceItem';
|
} from './WorkspaceItem';
|
||||||
import { WorkspaceSetting } from '@/components/workspace-setting';
|
import { WorkspaceSetting } from '@/components/workspace-setting';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { getWorkspaceDetail, WorkspaceType } from '@pathfinder/data-services';
|
import {
|
||||||
|
downloadWorkspace,
|
||||||
|
getWorkspaceDetail,
|
||||||
|
WorkspaceType,
|
||||||
|
} from '@pathfinder/data-services';
|
||||||
|
import { Workspace } from '@blocksuite/store';
|
||||||
|
|
||||||
export type WorkspaceDetails = Record<
|
export type WorkspaceDetails = Record<
|
||||||
string,
|
string,
|
||||||
@@ -26,13 +31,16 @@ type SelectorPopperContentProps = {
|
|||||||
export const SelectorPopperContent = ({
|
export const SelectorPopperContent = ({
|
||||||
isShow,
|
isShow,
|
||||||
}: SelectorPopperContentProps) => {
|
}: SelectorPopperContentProps) => {
|
||||||
const { user, workspacesMeta, workspaces } = useAppState();
|
const { user, workspacesMeta } = useAppState();
|
||||||
const [settingWorkspaceId, setSettingWorkspaceId] = useState<string | null>(
|
const [settingWorkspaceId, setSettingWorkspaceId] = useState<string | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
const [workSpaceDetails, setWorkSpaceDetails] = useState<WorkspaceDetails>(
|
const [workSpaceDetails, setWorkSpaceDetails] = useState<WorkspaceDetails>(
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
const [workspaces, setWorkspaces] = useState<
|
||||||
|
Record<string, Workspace | null>
|
||||||
|
>({});
|
||||||
const handleClickSettingWorkspace = (workspaceId: string) => {
|
const handleClickSettingWorkspace = (workspaceId: string) => {
|
||||||
setSettingWorkspaceId(workspaceId);
|
setSettingWorkspaceId(workspaceId);
|
||||||
};
|
};
|
||||||
@@ -73,10 +81,38 @@ export const SelectorPopperContent = ({
|
|||||||
setWorkSpaceDetails(workSpaceDetails);
|
setWorkSpaceDetails(workSpaceDetails);
|
||||||
}, [user, workspacesMeta]);
|
}, [user, workspacesMeta]);
|
||||||
|
|
||||||
|
// TODO: add to context
|
||||||
|
const refreshWorkspaces = useCallback(async () => {
|
||||||
|
const workspacesList = await Promise.all(
|
||||||
|
workspacesMeta.map(async ({ id }) => {
|
||||||
|
const workspace = new Workspace({
|
||||||
|
room: id,
|
||||||
|
providers: [],
|
||||||
|
});
|
||||||
|
const updates = await downloadWorkspace({ workspaceId: id });
|
||||||
|
updates &&
|
||||||
|
Workspace.Y.applyUpdate(workspace.doc, new Uint8Array(updates));
|
||||||
|
// if after update, the space:meta is empty, then we need to get map with doc
|
||||||
|
workspace.doc.getMap('space:meta');
|
||||||
|
return { id, workspace };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const workspaces: Record<string, Workspace | null> = {};
|
||||||
|
|
||||||
|
workspacesList.forEach(({ id, workspace }) => {
|
||||||
|
workspaces[id] = workspace;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('workspaces', workspaces);
|
||||||
|
|
||||||
|
setWorkspaces(workspaces);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isShow) {
|
if (isShow) {
|
||||||
setSettingWorkspaceId(null);
|
setSettingWorkspaceId(null);
|
||||||
refreshDetails();
|
refreshDetails();
|
||||||
|
refreshWorkspaces();
|
||||||
}
|
}
|
||||||
}, [isShow, refreshDetails]);
|
}, [isShow, refreshDetails]);
|
||||||
|
|
||||||
@@ -128,6 +164,7 @@ export const SelectorPopperContent = ({
|
|||||||
name: user.name,
|
name: user.name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
workspaces={workspaces}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<StyledDivider />
|
<StyledDivider />
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export type CreateEditorHandler = (page: StorePage) => EditorContainer | null;
|
|||||||
export interface AppStateValue {
|
export interface AppStateValue {
|
||||||
user: AccessTokenMessage | null;
|
user: AccessTokenMessage | null;
|
||||||
workspacesMeta: Workspace[];
|
workspacesMeta: Workspace[];
|
||||||
workspaces: Record<string, StoreWorkspace | null>;
|
|
||||||
|
|
||||||
currentWorkspaceId: string;
|
currentWorkspaceId: string;
|
||||||
currentWorkspace: StoreWorkspace | null;
|
currentWorkspace: StoreWorkspace | null;
|
||||||
@@ -56,7 +55,7 @@ export const AppState = createContext<AppStateContext>({
|
|||||||
loadPage: () => Promise.resolve(null),
|
loadPage: () => Promise.resolve(null),
|
||||||
createPage: () => Promise.resolve(null),
|
createPage: () => Promise.resolve(null),
|
||||||
synced: false,
|
synced: false,
|
||||||
workspaces: {},
|
// workspaces: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const useAppState = () => {
|
export const useAppState = () => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import type {
|
|||||||
LoadWorkspaceHandler,
|
LoadWorkspaceHandler,
|
||||||
CreateEditorHandler,
|
CreateEditorHandler,
|
||||||
} from './context';
|
} from './context';
|
||||||
import { downloadWorkspace, token } from '@pathfinder/data-services';
|
import { token } from '@pathfinder/data-services';
|
||||||
import { WebsocketProvider } from './y-websocket';
|
import { WebsocketProvider } from './y-websocket';
|
||||||
|
|
||||||
const getEditorParams = (workspaceId: string) => {
|
const getEditorParams = (workspaceId: string) => {
|
||||||
@@ -90,19 +90,9 @@ const DynamicBlocksuite = ({
|
|||||||
);
|
);
|
||||||
if (indexDBProvider) {
|
if (indexDBProvider) {
|
||||||
(indexDBProvider as IndexedDBDocProvider).on('synced', async () => {
|
(indexDBProvider as IndexedDBDocProvider).on('synced', async () => {
|
||||||
// const updates = await downloadWorkspace({ workspaceId });
|
|
||||||
// updates &&
|
|
||||||
// Workspace.Y.applyUpdate(workspace.doc, new Uint8Array(updates));
|
|
||||||
// if after update, the space:meta is empty, then we need to get map with doc
|
|
||||||
workspace.doc.getMap('space:meta');
|
|
||||||
resolve(workspace);
|
resolve(workspace);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const updates = await downloadWorkspace({ workspaceId });
|
|
||||||
updates &&
|
|
||||||
Workspace.Y.applyUpdate(workspace.doc, new Uint8Array(updates));
|
|
||||||
// if after update, the space:meta is empty, then we need to get map with doc
|
|
||||||
workspace.doc.getMap('space:meta');
|
|
||||||
resolve(workspace);
|
resolve(workspace);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
currentWorkspace: null,
|
currentWorkspace: null,
|
||||||
currentPage: null,
|
currentPage: null,
|
||||||
editor: null,
|
editor: null,
|
||||||
workspaces: {},
|
|
||||||
// Synced is used to ensure that the provider has synced with the server,
|
// Synced is used to ensure that the provider has synced with the server,
|
||||||
// So after Synced set to true, the other state is sure to be set.
|
// So after Synced set to true, the other state is sure to be set.
|
||||||
synced: false,
|
synced: false,
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ export const Input = (props: inputProps) => {
|
|||||||
} = props;
|
} = props;
|
||||||
const [value, setValue] = useState<string>(valueProp || '');
|
const [value, setValue] = useState<string>(valueProp || '');
|
||||||
const handleChange: InputHTMLAttributes<HTMLInputElement>['onChange'] = e => {
|
const handleChange: InputHTMLAttributes<HTMLInputElement>['onChange'] = e => {
|
||||||
|
if (
|
||||||
|
(maxLength && e.target.value.length > maxLength) ||
|
||||||
|
(minLength && e.target.value.length < minLength)
|
||||||
|
)
|
||||||
|
return;
|
||||||
setValue(e.target.value);
|
setValue(e.target.value);
|
||||||
onChange && onChange(e.target.value);
|
onChange && onChange(e.target.value);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user