Skip to content

Commit

Permalink
chore: add sync for page access cahnge
Browse files Browse the repository at this point in the history
  • Loading branch information
aaryan610 committed Dec 16, 2024
1 parent 383fb56 commit d52b747
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ export const DocumentCollaborativeEvents = {
unlock: { client: "unlocked", server: "unlock" },
archive: { client: "archived", server: "archive" },
unarchive: { client: "unarchived", server: "unarchive" },
"make-public": { client: "made-public", server: "make-public" },
"make-private": { client: "made-private", server: "make-private" },
} as const;
10 changes: 8 additions & 2 deletions web/core/components/pages/dropdowns/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
LockKeyholeOpen,
Trash2,
} from "lucide-react";
// plane editor
import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor";
// plane ui
import { ArchiveIcon, ContextMenu, CustomMenu, TContextMenuItem } from "@plane/ui";
// components
Expand Down Expand Up @@ -44,19 +46,23 @@ export type TPageActions =
| "move";

type Props = {
editorRef?: EditorRefApi | EditorReadOnlyRefApi | null;
extraOptions?: (TContextMenuItem & { key: TPageActions })[];
optionsOrder: TPageActions[];
page: IPage;
parentRef?: React.RefObject<HTMLElement>;
};

export const PageActions: React.FC<Props> = observer((props) => {
const { extraOptions, optionsOrder, page, parentRef } = props;
const { editorRef, extraOptions, optionsOrder, page, parentRef } = props;
// states
const [deletePageModal, setDeletePageModal] = useState(false);
const [movePageModal, setMovePageModal] = useState(false);
// page operations
const { pageOperations } = usePageOperations(page);
const { pageOperations } = usePageOperations({
editorRef,
page,
});
// derived values
const {
access,
Expand Down
9 changes: 4 additions & 5 deletions web/core/components/pages/editor/header/extra-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ import useOnlineStatus from "@/hooks/use-online-status";
import { IPage } from "@/store/pages/page";

type Props = {
editorRef: React.RefObject<EditorRefApi>;
editorRef: EditorRefApi | EditorReadOnlyRefApi | null;
page: IPage;
readOnlyEditorRef: React.RefObject<EditorReadOnlyRefApi>;
};

export const PageExtraOptions: React.FC<Props> = observer((props) => {
const { editorRef, page, readOnlyEditorRef } = props;
const { editorRef, page } = props;
// derived values
const {
archived_at,
Expand Down Expand Up @@ -84,8 +83,8 @@ export const PageExtraOptions: React.FC<Props> = observer((props) => {
iconClassName="text-custom-text-100"
/>
)}
<PageInfoPopover editorRef={isContentEditable ? editorRef.current : readOnlyEditorRef.current} />
<PageOptionsDropdown editorRef={isContentEditable ? editorRef.current : readOnlyEditorRef.current} page={page} />
<PageInfoPopover editorRef={editorRef} />
<PageOptionsDropdown editorRef={editorRef} page={page} />
</div>
);
});
18 changes: 5 additions & 13 deletions web/core/components/pages/editor/header/mobile-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,34 @@ import { usePageFilters } from "@/hooks/use-page-filters";
import { IPage } from "@/store/pages/page";

type Props = {
editorReady: boolean;
editorRef: React.RefObject<EditorRefApi>;
editorRef: EditorRefApi | EditorReadOnlyRefApi | null;
page: IPage;
readOnlyEditorReady: boolean;
readOnlyEditorRef: React.RefObject<EditorReadOnlyRefApi>;
setSidePeekVisible: (sidePeekState: boolean) => void;
sidePeekVisible: boolean;
};

export const PageEditorMobileHeaderRoot: React.FC<Props> = observer((props) => {
const { editorReady, editorRef, page, readOnlyEditorReady, readOnlyEditorRef, setSidePeekVisible, sidePeekVisible } =
props;
const { editorRef, page, setSidePeekVisible, sidePeekVisible } = props;
// derived values
const { isContentEditable } = page;
// page filters
const { isFullWidth } = usePageFilters();

if (!editorRef.current && !readOnlyEditorRef.current) return null;

return (
<>
<Header variant={EHeaderVariant.SECONDARY}>
<div className="flex-shrink-0 my-auto">
<PageSummaryPopover
editorRef={isContentEditable ? editorRef.current : readOnlyEditorRef.current}
editorRef={editorRef}
isFullWidth={isFullWidth}
sidePeekVisible={sidePeekVisible}
setSidePeekVisible={setSidePeekVisible}
/>
</div>
<PageExtraOptions editorRef={editorRef} page={page} readOnlyEditorRef={readOnlyEditorRef} />
<PageExtraOptions editorRef={editorRef} page={page} />
</Header>
<Header variant={EHeaderVariant.TERNARY}>
{(editorReady || readOnlyEditorReady) && isContentEditable && editorRef.current && (
<PageToolbar editorRef={editorRef?.current} />
)}
{isContentEditable && editorRef && <PageToolbar editorRef={editorRef as EditorRefApi} />}
</Header>
</>
);
Expand Down
2 changes: 2 additions & 0 deletions web/core/components/pages/editor/header/options-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
pageTitle={name ?? ""}
/>
<PageActions
editorRef={editorRef}
extraOptions={EXTRA_MENU_OPTIONS}
optionsOrder={[
"full-screen",
"copy-markdown",
"copy-link",
"toggle-lock",
"make-a-copy",
"move",
"archive-restore",
Expand Down
11 changes: 5 additions & 6 deletions web/core/components/pages/editor/header/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
const { isContentEditable } = page;
// page filters
const { isFullWidth } = usePageFilters();
// derived values
const resolvedEditorRef = isContentEditable ? editorRef.current : readOnlyEditorRef.current;

if (!editorRef.current && !readOnlyEditorRef.current) return null;
if (!resolvedEditorRef) return null;

return (
<>
Expand All @@ -53,14 +55,11 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
<PageToolbar editorRef={editorRef?.current} />
)}
</Header.LeftItem>
<PageExtraOptions editorRef={editorRef} page={page} readOnlyEditorRef={readOnlyEditorRef} />
<PageExtraOptions editorRef={resolvedEditorRef} page={page} />
</Header>
<div className="md:hidden">
<PageEditorMobileHeaderRoot
editorRef={editorRef}
readOnlyEditorRef={readOnlyEditorRef}
editorReady={editorReady}
readOnlyEditorReady={readOnlyEditorReady}
editorRef={resolvedEditorRef}
page={page}
sidePeekVisible={sidePeekVisible}
setSidePeekVisible={setSidePeekVisible}
Expand Down
4 changes: 3 additions & 1 deletion web/core/components/pages/list/block-item-action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export const BlockItemAction: FC<Props> = observer((props) => {
const page = usePage(pageId);
const { getUserDetails } = useMember();
// page operations
const { pageOperations } = usePageOperations(page);
const { pageOperations } = usePageOperations({
page,
});
// derived values
const { access, created_at, is_favorite, owned_by, canCurrentUserFavoritePage } = page;
const ownerDetails = owned_by ? getUserDetails(owned_by) : undefined;
Expand Down
22 changes: 20 additions & 2 deletions web/core/hooks/use-collaborative-page-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ type CollaborativeActionEvent =
| { type: "sendMessageToServer"; message: TDocumentEventsServer }
| { type: "receivedMessageFromServer"; message: TDocumentEventsClient };

export const useCollaborativePageActions = (editorRef: EditorRefApi | EditorReadOnlyRefApi | null, page: IPage) => {
type Props = {
editorRef?: EditorRefApi | EditorReadOnlyRefApi | null;
page: IPage;
};

export const useCollaborativePageActions = (props: Props) => {
const { editorRef, page } = props;
// currentUserAction local state to track if the current action is being processed, a
// local action is basically the action performed by the current user to avoid double operations
const [currentActionBeingProcessed, setCurrentActionBeingProcessed] = useState<TDocumentEventsClient | null>(null);
Expand All @@ -37,6 +43,14 @@ export const useCollaborativePageActions = (editorRef: EditorRefApi | EditorRead
execute: (shouldSync) => page.restore(shouldSync),
errorMessage: "Page could not be restored. Please try again later.",
},
[DocumentCollaborativeEvents["make-public"].client]: {
execute: (shouldSync) => page.makePublic(shouldSync),
errorMessage: "Page could not be made public. Please try again later.",
},
[DocumentCollaborativeEvents["make-private"].client]: {
execute: (shouldSync) => page.makePrivate(shouldSync),
errorMessage: "Page could not be made private. Please try again later.",
},
}),
[page]
);
Expand Down Expand Up @@ -64,6 +78,7 @@ export const useCollaborativePageActions = (editorRef: EditorRefApi | EditorRead
);

useEffect(() => {
if (!editorRef) return;
if (currentActionBeingProcessed) {
const serverEventName = getServerEventName(currentActionBeingProcessed);
if (serverEventName) {
Expand All @@ -73,9 +88,12 @@ export const useCollaborativePageActions = (editorRef: EditorRefApi | EditorRead
}, [currentActionBeingProcessed, editorRef]);

useEffect(() => {
const realTimeStatelessMessageListener = editorRef?.listenToRealTimeUpdate();
if (!editorRef) return;

const realTimeStatelessMessageListener = editorRef?.listenToRealTimeUpdate();
console.log(realTimeStatelessMessageListener);
const handleStatelessMessage = (message: { payload: TDocumentEventsClient }) => {
console.log("aaa", message);
if (currentActionBeingProcessed === message.payload) {
setCurrentActionBeingProcessed(null);
return;
Expand Down
16 changes: 10 additions & 6 deletions web/core/hooks/use-page-operations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useMemo } from "react";
import { useParams } from "next/navigation";
// plane editor
import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor";
// plane ui
import { setToast, TOAST_TYPE } from "@plane/ui";
// helpers
Expand All @@ -19,32 +21,34 @@ export type TPageOperations = {
toggleArchive: () => void;
};

type Props = {
editorRef?: EditorRefApi | EditorReadOnlyRefApi | null;
page: IPage;
};

export const usePageOperations = (
page: IPage
props: Props
): {
pageOperations: TPageOperations;
} => {
const { page } = props;
// params
const { workspaceSlug, projectId } = useParams();
// derived values
const {
access,
addToFavorites,
archive,
archived_at,
duplicate,
id,
is_favorite,
is_locked,
lock,
makePrivate,
makePublic,
removePageFromFavorites,
restore,
unlock,
} = page;
// collaborative actions
const { executeCollaborativeAction } = useCollaborativePageActions(undefined, page);
const { executeCollaborativeAction } = useCollaborativePageActions(props);
// page operations
const pageOperations: TPageOperations = useMemo(() => {
const pageLink = projectId ? `${workspaceSlug}/projects/${projectId}/pages/${id}` : `${workspaceSlug}/pages/${id}`;
Expand Down
48 changes: 26 additions & 22 deletions web/core/store/pages/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export interface IPage extends TPage {
update: (pageData: Partial<TPage>) => Promise<TPage | undefined>;
updateTitle: (title: string) => void;
updateDescription: (document: TDocumentPayload) => Promise<void>;
makePublic: () => Promise<void>;
makePrivate: () => Promise<void>;
makePublic: (shouldSync?: boolean) => Promise<void>;
makePrivate: (shouldSync?: boolean) => Promise<void>;
lock: (shouldSync?: boolean) => Promise<void>;
unlock: (shouldSync?: boolean) => Promise<void>;
archive: (shouldSync?: boolean) => Promise<void>;
Expand Down Expand Up @@ -415,44 +415,48 @@ export class Page implements IPage {
/**
* @description make the page public
*/
makePublic = async () => {
makePublic = async (shouldSync: boolean = true) => {
const { workspaceSlug, projectId } = this.store.router;
if (!workspaceSlug || !projectId || !this.id) return undefined;

const pageAccess = this.access;
runInAction(() => (this.access = EPageAccess.PUBLIC));

try {
await this.pageService.updateAccess(workspaceSlug, projectId, this.id, {
access: EPageAccess.PUBLIC,
});
} catch (error) {
runInAction(() => {
this.access = pageAccess;
});
throw error;
if (shouldSync) {
try {
await this.pageService.updateAccess(workspaceSlug, projectId, this.id, {
access: EPageAccess.PUBLIC,
});
} catch (error) {
runInAction(() => {
this.access = pageAccess;
});
throw error;
}
}
};

/**
* @description make the page private
*/
makePrivate = async () => {
makePrivate = async (shouldSync: boolean = true) => {
const { workspaceSlug, projectId } = this.store.router;
if (!workspaceSlug || !projectId || !this.id) return undefined;

const pageAccess = this.access;
runInAction(() => (this.access = EPageAccess.PRIVATE));

try {
await this.pageService.updateAccess(workspaceSlug, projectId, this.id, {
access: EPageAccess.PRIVATE,
});
} catch (error) {
runInAction(() => {
this.access = pageAccess;
});
throw error;
if (shouldSync) {
try {
await this.pageService.updateAccess(workspaceSlug, projectId, this.id, {
access: EPageAccess.PRIVATE,
});
} catch (error) {
runInAction(() => {
this.access = pageAccess;
});
throw error;
}
}
};

Expand Down

0 comments on commit d52b747

Please sign in to comment.