Compare commits
2 Commits
chore/anal
...
dev/pages-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e92f4d58b | ||
|
|
e37db8d8f4 |
@@ -262,7 +262,7 @@ class PageViewSet(BaseViewSet):
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def lock(self, request, slug, project_id, pk):
|
||||
page = Page.objects.filter(
|
||||
pk=pk, workspace__slug=slug, projects__id=project_id
|
||||
@@ -272,7 +272,7 @@ class PageViewSet(BaseViewSet):
|
||||
page.save()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def unlock(self, request, slug, project_id, pk):
|
||||
page = Page.objects.filter(
|
||||
pk=pk, workspace__slug=slug, projects__id=project_id
|
||||
@@ -283,7 +283,7 @@ class PageViewSet(BaseViewSet):
|
||||
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def access(self, request, slug, project_id, pk):
|
||||
access = request.data.get("access", 0)
|
||||
page = Page.objects.filter(
|
||||
@@ -330,7 +330,7 @@ class PageViewSet(BaseViewSet):
|
||||
pages = PageSerializer(queryset, many=True).data
|
||||
return Response(pages, status=status.HTTP_200_OK)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def archive(self, request, slug, project_id, pk):
|
||||
page = Page.objects.get(
|
||||
pk=pk, workspace__slug=slug, projects__id=project_id
|
||||
@@ -365,7 +365,7 @@ class PageViewSet(BaseViewSet):
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def unarchive(self, request, slug, project_id, pk):
|
||||
page = Page.objects.get(
|
||||
pk=pk, workspace__slug=slug, projects__id=project_id
|
||||
@@ -438,7 +438,6 @@ class PageViewSet(BaseViewSet):
|
||||
|
||||
|
||||
class PageFavoriteViewSet(BaseViewSet):
|
||||
|
||||
model = UserFavorite
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER])
|
||||
@@ -465,7 +464,6 @@ class PageFavoriteViewSet(BaseViewSet):
|
||||
|
||||
|
||||
class PageLogEndpoint(BaseAPIView):
|
||||
|
||||
serializer_class = PageLogSerializer
|
||||
model = PageLog
|
||||
|
||||
@@ -504,7 +502,6 @@ class PageLogEndpoint(BaseAPIView):
|
||||
|
||||
|
||||
class SubPagesEndpoint(BaseAPIView):
|
||||
|
||||
@method_decorator(gzip_page)
|
||||
def get(self, request, slug, project_id, page_id):
|
||||
pages = (
|
||||
@@ -522,7 +519,6 @@ class SubPagesEndpoint(BaseAPIView):
|
||||
|
||||
|
||||
class PagesDescriptionViewSet(BaseViewSet):
|
||||
|
||||
@allow_permission(
|
||||
[
|
||||
ROLE.ADMIN,
|
||||
|
||||
23
apiserver/plane/bgtasks/delete_pages_from_trash.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Third party imports
|
||||
from celery import shared_task
|
||||
|
||||
# Django imports
|
||||
from django.utils import timezone
|
||||
|
||||
# Module imports
|
||||
from plane.db.models import Page
|
||||
from plane.utils.exception_logger import log_exception
|
||||
|
||||
|
||||
@shared_task
|
||||
def delete_pages_from_trash():
|
||||
try:
|
||||
# Get all the pages whose archived_at is not null, i.e., they are in the trash
|
||||
Page.objects.filter(
|
||||
archived_at__isnull=False,
|
||||
archived_at__lte=timezone.now() - timezone.timedelta(days=90),
|
||||
).delete()
|
||||
return
|
||||
except Exception as e:
|
||||
log_exception(e)
|
||||
return
|
||||
@@ -40,6 +40,10 @@ app.conf.beat_schedule = {
|
||||
"task": "plane.bgtasks.api_logs_task.delete_api_logs",
|
||||
"schedule": crontab(hour=0, minute=0),
|
||||
},
|
||||
"check-every-day-to-delete-pages-from-trash": {
|
||||
"task": "plane.bgtasks.delete_pages_from_trash.delete_pages_from_trash",
|
||||
"schedule": crontab(hour=0, minute=0),
|
||||
},
|
||||
"run-every-6-hours-for-instance-trace": {
|
||||
"task": "plane.license.bgtasks.tracer.instance_traces",
|
||||
"schedule": crontab(hour="*/6", minute=0),
|
||||
|
||||
@@ -303,6 +303,7 @@ CELERY_IMPORTS = (
|
||||
"plane.bgtasks.email_notification_task",
|
||||
"plane.bgtasks.api_logs_task",
|
||||
"plane.license.bgtasks.tracer",
|
||||
"plane.bgtasks.delete_pages_from_trash",
|
||||
# management tasks
|
||||
"plane.bgtasks.dummy_data_task",
|
||||
)
|
||||
|
||||
2
packages/types/src/pages.d.ts
vendored
@@ -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"
|
||||
|
||||
@@ -20,7 +20,7 @@ const PageDetailsPage = observer(() => {
|
||||
const { workspaceSlug, projectId, pageId } = useParams();
|
||||
|
||||
// store hooks
|
||||
const { getPageById } = useProjectPages();
|
||||
const { fetchPageById } = useProjectPages();
|
||||
const page = usePage(pageId?.toString() ?? "");
|
||||
const { id, name } = page;
|
||||
|
||||
@@ -28,7 +28,7 @@ const PageDetailsPage = observer(() => {
|
||||
const { error: pageDetailsError } = useSWR(
|
||||
workspaceSlug && projectId && pageId ? `PAGE_DETAILS_${pageId}` : null,
|
||||
workspaceSlug && projectId && pageId
|
||||
? () => getPageById(workspaceSlug?.toString(), projectId?.toString(), pageId.toString())
|
||||
? () => fetchPageById(workspaceSlug?.toString(), projectId?.toString(), pageId.toString())
|
||||
: null,
|
||||
{
|
||||
revalidateIfStale: false,
|
||||
|
||||
@@ -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 <></>;
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ const pageTabs: { key: TPageNavigationTabs; label: string }[] = [
|
||||
label: "Private",
|
||||
},
|
||||
{
|
||||
key: "archived",
|
||||
label: "Archived",
|
||||
key: "trash",
|
||||
label: "Trash",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -2,33 +2,29 @@
|
||||
|
||||
import { Loader } from "@plane/ui";
|
||||
|
||||
export const PageLoader: React.FC = (props) => {
|
||||
const {} = props;
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-full flex flex-col">
|
||||
<div className="px-3 border-b border-custom-border-100 py-3">
|
||||
<Loader className="relative flex items-center gap-2">
|
||||
<Loader.Item width="200px" height="30px" />
|
||||
<div className="relative flex items-center gap-2 ml-auto">
|
||||
<Loader.Item width="100px" height="30px" />
|
||||
<Loader.Item width="100px" height="30px" />
|
||||
export const PageLoader: React.FC = () => (
|
||||
<div className="relative w-full h-full flex flex-col">
|
||||
<div className="px-3 border-b border-custom-border-100 py-3">
|
||||
<Loader className="relative flex items-center gap-2">
|
||||
<Loader.Item width="200px" height="30px" />
|
||||
<div className="relative flex items-center gap-2 ml-auto">
|
||||
<Loader.Item width="100px" height="30px" />
|
||||
<Loader.Item width="100px" height="30px" />
|
||||
</div>
|
||||
</Loader>
|
||||
</div>
|
||||
<div>
|
||||
{Array.from(Array(10)).map((_, index) => (
|
||||
<Loader key={index} className="relative flex items-center gap-2 p-3 py-4 border-b border-custom-border-100">
|
||||
<Loader.Item width={`${250 + 10 * Math.floor(Math.random() * 10)}px`} height="22px" />
|
||||
<div className="ml-auto relative flex items-center gap-2">
|
||||
<Loader.Item width="60px" height="22px" />
|
||||
<Loader.Item width="22px" height="22px" />
|
||||
<Loader.Item width="22px" height="22px" />
|
||||
<Loader.Item width="22px" height="22px" />
|
||||
</div>
|
||||
</Loader>
|
||||
</div>
|
||||
<div>
|
||||
{Array.from(Array(10)).map((i) => (
|
||||
<Loader key={i} className="relative flex items-center gap-2 p-3 py-4 border-b border-custom-border-100">
|
||||
<Loader.Item width={`${250 + 10 * Math.floor(Math.random() * 10)}px`} height="22px" />
|
||||
<div className="ml-auto relative flex items-center gap-2">
|
||||
<Loader.Item width="60px" height="22px" />
|
||||
<Loader.Item width="22px" height="22px" />
|
||||
<Loader.Item width="22px" height="22px" />
|
||||
<Loader.Item width="22px" height="22px" />
|
||||
</div>
|
||||
</Loader>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -31,12 +31,8 @@ export interface IProjectPageStore {
|
||||
updateFilters: <T extends keyof TPageFilters>(filterKey: T, filterValue: TPageFilters[T]) => void;
|
||||
clearAllFilters: () => void;
|
||||
// actions
|
||||
getAllPages: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
pageType: TPageNavigationTabs
|
||||
) => Promise<TPage[] | undefined>;
|
||||
getPageById: (workspaceSlug: string, projectId: string, pageId: string) => Promise<TPage | undefined>;
|
||||
fetchAllPages: (workspaceSlug: string, projectId: string) => Promise<TPage[]>;
|
||||
fetchPageById: (workspaceSlug: string, projectId: string, pageId: string) => Promise<TPage>;
|
||||
createPage: (pageData: Partial<TPage>) => Promise<TPage | undefined>;
|
||||
removePage: (pageId: string) => Promise<void>;
|
||||
}
|
||||
@@ -66,8 +62,8 @@ export class ProjectPageStore implements IProjectPageStore {
|
||||
updateFilters: action,
|
||||
clearAllFilters: action,
|
||||
// actions
|
||||
getAllPages: action,
|
||||
getPageById: action,
|
||||
fetchAllPages: action,
|
||||
fetchPageById: action,
|
||||
createPage: action,
|
||||
removePage: action,
|
||||
});
|
||||
@@ -154,13 +150,14 @@ export class ProjectPageStore implements IProjectPageStore {
|
||||
/**
|
||||
* @description fetch all the pages
|
||||
*/
|
||||
getAllPages = async (workspaceSlug: string, projectId: string, pageType: TPageNavigationTabs) => {
|
||||
fetchAllPages = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
if (!workspaceSlug || !projectId) return undefined;
|
||||
if (!workspaceSlug || !projectId) {
|
||||
throw new Error("workspace slug or project id not provided");
|
||||
}
|
||||
|
||||
const currentPageIds = this.getCurrentProjectPageIds(pageType);
|
||||
runInAction(() => {
|
||||
this.loader = currentPageIds && currentPageIds.length > 0 ? `mutation-loader` : `init-loader`;
|
||||
this.loader = this.isAnyPageAvailable ? `mutation-loader` : `init-loader`;
|
||||
this.error = undefined;
|
||||
});
|
||||
|
||||
@@ -187,13 +184,15 @@ export class ProjectPageStore implements IProjectPageStore {
|
||||
* @description fetch the details of a page
|
||||
* @param {string} pageId
|
||||
*/
|
||||
getPageById = async (workspaceSlug: string, projectId: string, pageId: string) => {
|
||||
fetchPageById = async (workspaceSlug: string, projectId: string, pageId: string) => {
|
||||
try {
|
||||
if (!workspaceSlug || !projectId || !pageId) return undefined;
|
||||
if (!workspaceSlug || !projectId || !pageId) {
|
||||
throw new Error("workspace slug, project id or page id not provided");
|
||||
}
|
||||
|
||||
const currentPageId = this.pageById(pageId);
|
||||
const currentPage = this.pageById(pageId);
|
||||
runInAction(() => {
|
||||
this.loader = currentPageId ? `mutation-loader` : `init-loader`;
|
||||
this.loader = currentPage ? `mutation-loader` : `init-loader`;
|
||||
this.error = undefined;
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 48 KiB |
BIN
web/public/empty-state/pages/Pages empty states/public-dark.webp
Normal file
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 48 KiB |
BIN
web/public/empty-state/pages/Pages empty states/trash-dark.webp
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
web/public/empty-state/pages/Pages empty states/trash-light.webp
Normal file
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 48 KiB |
BIN
web/public/empty-state/pages/trash-dark.webp
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
web/public/empty-state/pages/trash-light.webp
Normal file
|
After Width: | Height: | Size: 52 KiB |