dev: pages trash

This commit is contained in:
Aaryan Khandelwal
2024-11-22 13:31:34 +05:30
parent ca91d5909b
commit e37db8d8f4
21 changed files with 86 additions and 62 deletions

View File

@@ -23,7 +23,7 @@ export type TPage = {
};
// page filters
export type TPageNavigationTabs = "public" | "private" | "archived";
export type TPageNavigationTabs = "public" | "private" | "trash";
export type TPageFiltersSortKey =
| "name"

View File

@@ -1,7 +1,8 @@
"use client";
import { useEffect } from "react";
import { observer } from "mobx-react";
import { useParams, useSearchParams } from "next/navigation";
import { useParams, useSearchParams, useRouter } from "next/navigation";
// types
import { TPageNavigationTabs } from "@plane/types";
// components
@@ -12,14 +13,18 @@ import { PagesListRoot, PagesListView } from "@/components/pages";
import { EmptyStateType } from "@/constants/empty-state";
// hooks
import { useProject } from "@/hooks/store";
import { useQueryParams } from "@/hooks/use-query-params";
const ProjectPagesPage = observer(() => {
// router
const router = useRouter();
// params
const { workspaceSlug, projectId } = useParams();
const searchParams = useSearchParams();
const type = searchParams.get("type");
const { workspaceSlug, projectId } = useParams();
// store hooks
const { getProjectById, currentProjectDetails } = useProject();
const { updateQueryParams } = useQueryParams();
// derived values
const project = projectId ? getProjectById(projectId.toString()) : undefined;
const pageTitle = project?.name ? `${project?.name} - Pages` : undefined;
@@ -27,9 +32,21 @@ const ProjectPagesPage = observer(() => {
const currentPageType = (): TPageNavigationTabs => {
const pageType = type?.toString();
if (pageType === "private") return "private";
if (pageType === "archived") return "archived";
if (pageType === "trash") return "trash";
return "public";
};
// update the route to public pages if the type is invalid
useEffect(() => {
const pageType = type?.toString();
if (pageType !== "public" && pageType !== "private" && pageType !== "trash") {
const updatedRoute = updateQueryParams({
paramsToAdd: {
type: "public",
},
});
router.push(updatedRoute);
}
}, [router, type, updateQueryParams]);
if (!workspaceSlug || !projectId) return <></>;

View File

@@ -22,8 +22,8 @@ const pageTabs: { key: TPageNavigationTabs; label: string }[] = [
label: "Private",
},
{
key: "archived",
label: "Archived",
key: "trash",
label: "Trash",
},
];

View File

@@ -32,35 +32,35 @@ export const PagesListMainContent: React.FC<Props> = observer((props) => {
if (loader === "init-loader") return <PageLoader />;
// if no pages exist in the active page type
if (!isAnyPageAvailable || pageIds?.length === 0) {
if (!isAnyPageAvailable) {
return (
<EmptyState
type={EmptyStateType.PROJECT_PAGE}
primaryButtonOnClick={() => {
toggleCreatePageModal({ isOpen: true });
}}
/>
);
}
if (pageType === "public")
return (
<EmptyState
type={EmptyStateType.PROJECT_PAGE_PUBLIC}
primaryButtonOnClick={() => {
toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PUBLIC });
}}
/>
);
if (pageType === "private")
return (
<EmptyState
type={EmptyStateType.PROJECT_PAGE_PRIVATE}
primaryButtonOnClick={() => {
toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PRIVATE });
}}
/>
);
if (pageType === "archived") return <EmptyState type={EmptyStateType.PROJECT_PAGE_ARCHIVED} />;
return (
<div className="size-full">
{!isAnyPageAvailable && (
<EmptyState
type={EmptyStateType.PROJECT_PAGE}
primaryButtonOnClick={() => {
toggleCreatePageModal({ isOpen: true });
}}
/>
)}
{pageType === "public" ? (
<EmptyState
type={EmptyStateType.PROJECT_PAGE_PUBLIC}
primaryButtonOnClick={() => {
toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PUBLIC });
}}
/>
) : pageType === "private" ? (
<EmptyState
type={EmptyStateType.PROJECT_PAGE_PRIVATE}
primaryButtonOnClick={() => {
toggleCreatePageModal({ isOpen: true, pageAccess: EPageAccess.PRIVATE });
}}
/>
) : pageType === "trash" ? (
<EmptyState type={EmptyStateType.PROJECT_PAGE_TRASH} />
) : null}
</div>
);
}
// if no pages match the filter criteria
if (filteredPageIds?.length === 0)

View File

@@ -95,7 +95,7 @@ export class ProjectPageService extends APIService {
});
}
async archive(
async moveToTrash(
workspaceSlug: string,
projectId: string,
pageId: string
@@ -109,7 +109,7 @@ export class ProjectPageService extends APIService {
});
}
async restore(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
async restoreFromTrash(workspaceSlug: string, projectId: string, pageId: string): Promise<void> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/archive/`)
.then((response) => response?.data)
.catch((error) => {

View File

@@ -22,7 +22,7 @@ export interface IPage extends TPage {
canCurrentUserDuplicatePage: boolean;
canCurrentUserLockPage: boolean;
canCurrentUserChangeAccess: boolean;
canCurrentUserArchivePage: boolean;
canCurrentUserTrashPage: boolean;
canCurrentUserDeletePage: boolean;
canCurrentUserFavoritePage: boolean;
isContentEditable: boolean;
@@ -38,8 +38,8 @@ export interface IPage extends TPage {
makePrivate: () => Promise<void>;
lock: () => Promise<void>;
unlock: () => Promise<void>;
archive: () => Promise<void>;
restore: () => Promise<void>;
moveToTrash: () => Promise<void>;
restoreFromTrash: () => Promise<void>;
updatePageLogo: (logo_props: TLogoProps) => Promise<void>;
addToFavorites: () => Promise<void>;
removePageFromFavorites: () => Promise<void>;
@@ -132,7 +132,7 @@ export class Page implements IPage {
canCurrentUserDuplicatePage: computed,
canCurrentUserLockPage: computed,
canCurrentUserChangeAccess: computed,
canCurrentUserArchivePage: computed,
canCurrentUserTrashPage: computed,
canCurrentUserDeletePage: computed,
canCurrentUserFavoritePage: computed,
isContentEditable: computed,
@@ -144,8 +144,8 @@ export class Page implements IPage {
makePrivate: action,
lock: action,
unlock: action,
archive: action,
restore: action,
moveToTrash: action,
restoreFromTrash: action,
updatePageLogo: action,
addToFavorites: action,
removePageFromFavorites: action,
@@ -204,9 +204,11 @@ export class Page implements IPage {
};
}
/**
* @description returns true if the current logged in user is the owner of the page
*/
get isCurrentUserOwner() {
const currentUserId = this.store.user.data?.id;
if (!currentUserId) return false;
return this.owned_by === currentUserId;
}
@@ -215,7 +217,6 @@ export class Page implements IPage {
*/
get canCurrentUserEditPage() {
const { workspaceSlug, projectId } = this.store.router;
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
workspaceSlug?.toString() || "",
projectId?.toString() || ""
@@ -228,7 +229,6 @@ export class Page implements IPage {
*/
get canCurrentUserDuplicatePage() {
const { workspaceSlug, projectId } = this.store.router;
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
workspaceSlug?.toString() || "",
projectId?.toString() || ""
@@ -240,22 +240,31 @@ export class Page implements IPage {
* @description returns true if the current logged in user can lock the page
*/
get canCurrentUserLockPage() {
return this.isCurrentUserOwner;
const { workspaceSlug, projectId } = this.store.router;
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
workspaceSlug?.toString() || "",
projectId?.toString() || ""
);
return this.isCurrentUserOwner || currentUserProjectRole === EUserPermissions.ADMIN;
}
/**
* @description returns true if the current logged in user can change the access of the page
*/
get canCurrentUserChangeAccess() {
return this.isCurrentUserOwner;
const { workspaceSlug, projectId } = this.store.router;
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
workspaceSlug?.toString() || "",
projectId?.toString() || ""
);
return this.isCurrentUserOwner || currentUserProjectRole === EUserPermissions.ADMIN;
}
/**
* @description returns true if the current logged in user can archive the page
* @description returns true if the current logged in user can trash the page
*/
get canCurrentUserArchivePage() {
get canCurrentUserTrashPage() {
const { workspaceSlug, projectId } = this.store.router;
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
workspaceSlug?.toString() || "",
projectId?.toString() || ""
@@ -268,7 +277,6 @@ export class Page implements IPage {
*/
get canCurrentUserDeletePage() {
const { workspaceSlug, projectId } = this.store.router;
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
workspaceSlug?.toString() || "",
projectId?.toString() || ""
@@ -281,7 +289,6 @@ export class Page implements IPage {
*/
get canCurrentUserFavoritePage() {
const { workspaceSlug, projectId } = this.store.router;
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
workspaceSlug?.toString() || "",
projectId?.toString() || ""
@@ -301,11 +308,11 @@ export class Page implements IPage {
projectId?.toString() || ""
);
const isPublic = this.access === EPageAccess.PUBLIC;
const isArchived = this.archived_at;
const isTrashed = this.archived_at;
const isLocked = this.is_locked;
return (
!isArchived &&
!isTrashed &&
!isLocked &&
(isOwner || (isPublic && !!currentUserRole && currentUserRole >= EUserPermissions.MEMBER))
);
@@ -469,12 +476,12 @@ export class Page implements IPage {
};
/**
* @description archive the page
* @description move the page to trash
*/
archive = async () => {
moveToTrash = async () => {
const { workspaceSlug, projectId } = this.store.router;
if (!workspaceSlug || !projectId || !this.id) return undefined;
const response = await this.pageService.archive(workspaceSlug, projectId, this.id);
const response = await this.pageService.moveToTrash(workspaceSlug, projectId, this.id);
runInAction(() => {
this.archived_at = response.archived_at;
});
@@ -482,12 +489,12 @@ export class Page implements IPage {
};
/**
* @description restore the page
* @description restore the page from trash
*/
restore = async () => {
restoreFromTrash = async () => {
const { workspaceSlug, projectId } = this.store.router;
if (!workspaceSlug || !projectId || !this.id) return undefined;
await this.pageService.restore(workspaceSlug, projectId, this.id);
await this.pageService.restoreFromTrash(workspaceSlug, projectId, this.id);
runInAction(() => {
this.archived_at = null;
});

View File

@@ -14,7 +14,7 @@ export const filterPagesByPageType = (pageType: TPageNavigationTabs, pages: TPag
pages.filter((page) => {
if (pageType === "public") return page.access === 0 && !page.archived_at;
if (pageType === "private") return page.access === 1 && !page.archived_at;
if (pageType === "archived") return page.archived_at;
if (pageType === "trash") return page.archived_at;
return true;
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB