mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: added authorization to pages (#3006)
* chore: updated pages authorization * chore: updated pages empty state image
This commit is contained in:
parent
13667d491b
commit
1f860312c6
@ -1,4 +1,3 @@
|
|||||||
import { FC } from "react";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { FileText, Plus } from "lucide-react";
|
import { FileText, Plus } from "lucide-react";
|
||||||
@ -8,18 +7,22 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
import { Breadcrumbs, Button } from "@plane/ui";
|
import { Breadcrumbs, Button } from "@plane/ui";
|
||||||
// helper
|
// helper
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
|
// constants
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export interface IPagesHeaderProps {
|
export const PagesHeader = observer(() => {
|
||||||
showButton?: boolean;
|
// router
|
||||||
}
|
|
||||||
|
|
||||||
export const PagesHeader: FC<IPagesHeaderProps> = observer((props) => {
|
|
||||||
const { showButton = false } = props;
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
// mobx store
|
||||||
|
const {
|
||||||
|
user: { currentProjectRole },
|
||||||
|
project: { currentProjectDetails },
|
||||||
|
commandPalette: { toggleCreatePageModal },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const canUserCreatePage =
|
||||||
const { currentProjectDetails } = projectStore;
|
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex w-full flex-shrink-0 flex-row z-10 h-[3.75rem] items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
<div className="relative flex w-full flex-shrink-0 flex-row z-10 h-[3.75rem] items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||||
@ -50,14 +53,9 @@ export const PagesHeader: FC<IPagesHeaderProps> = observer((props) => {
|
|||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{showButton && (
|
{canUserCreatePage && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button variant="primary" prependIcon={<Plus />} size="sm" onClick={() => toggleCreatePageModal(true)}>
|
||||||
variant="primary"
|
|
||||||
prependIcon={<Plus />}
|
|
||||||
size="sm"
|
|
||||||
onClick={() => commandPaletteStore.toggleCreatePageModal(true)}
|
|
||||||
>
|
|
||||||
Create Page
|
Create Page
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -102,13 +102,7 @@ export const PageForm: React.FC<Props> = (props) => {
|
|||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="primary" size="sm" type="submit" loading={isSubmitting}>
|
<Button variant="primary" size="sm" type="submit" loading={isSubmitting}>
|
||||||
{data
|
{data ? (isSubmitting ? "Updating..." : "Update page") : isSubmitting ? "Creating..." : "Create Page"}
|
||||||
? isSubmitting
|
|
||||||
? "Updating Page..."
|
|
||||||
: "Update Page"
|
|
||||||
: isSubmitting
|
|
||||||
? "Creating Page..."
|
|
||||||
: "Create Page"}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// icons
|
|
||||||
import {
|
import {
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
Archive,
|
Archive,
|
||||||
@ -14,12 +13,13 @@ import {
|
|||||||
Star,
|
Star,
|
||||||
Trash2,
|
Trash2,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
|
||||||
// helpers
|
// helpers
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
import { renderShortDate, render24HourFormatTime, renderLongDateFormat } from "helpers/date-time.helper";
|
import { render24HourFormatTime, renderFormattedDate } from "helpers/date-time.helper";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu, Tooltip } from "@plane/ui";
|
import { CustomMenu, Tooltip } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
@ -39,10 +39,10 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
|
|||||||
// states
|
// states
|
||||||
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
|
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
|
||||||
const [deletePageModal, setDeletePageModal] = useState(false);
|
const [deletePageModal, setDeletePageModal] = useState(false);
|
||||||
// store
|
// mobx store
|
||||||
const {
|
const {
|
||||||
page: { archivePage, removeFromFavorites, addToFavorites, makePublic, makePrivate, restorePage },
|
page: { archivePage, removeFromFavorites, addToFavorites, makePublic, makePrivate, restorePage },
|
||||||
user: { currentProjectRole },
|
user: { currentUser, currentProjectRole },
|
||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// hooks
|
// hooks
|
||||||
@ -145,7 +145,15 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
|
|||||||
setCreateUpdatePageModal(true);
|
setCreateUpdatePageModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const userCanEdit = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
const ownerDetails = projectMembers?.find((projectMember) => projectMember.member.id === page.owned_by)?.member;
|
||||||
|
const isCurrentUserOwner = page.owned_by === currentUser?.id;
|
||||||
|
|
||||||
|
const userCanEdit =
|
||||||
|
isCurrentUserOwner ||
|
||||||
|
(currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole));
|
||||||
|
const userCanChangeAccess = isCurrentUserOwner;
|
||||||
|
const userCanArchive = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
const userCanDelete = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -185,7 +193,7 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
|
|||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-2.5">
|
||||||
{page.archived_at ? (
|
{page.archived_at ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
tooltipContent={`Archived at ${render24HourFormatTime(page.archived_at)} on ${renderShortDate(
|
tooltipContent={`Archived at ${render24HourFormatTime(page.archived_at)} on ${renderFormattedDate(
|
||||||
page.archived_at
|
page.archived_at
|
||||||
)}`}
|
)}`}
|
||||||
>
|
>
|
||||||
@ -193,27 +201,25 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
tooltipContent={`Last updated at ${render24HourFormatTime(page.updated_at)} on ${renderShortDate(
|
tooltipContent={`Last updated at ${render24HourFormatTime(
|
||||||
page.updated_at
|
page.updated_at
|
||||||
)}`}
|
)} on ${renderFormattedDate(page.updated_at)}`}
|
||||||
>
|
>
|
||||||
<p className="text-sm text-custom-text-200">{render24HourFormatTime(page.updated_at)}</p>
|
<p className="text-sm text-custom-text-200">{render24HourFormatTime(page.updated_at)}</p>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{!page.archived_at && userCanEdit && (
|
<Tooltip tooltipContent={`${page.is_favorite ? "Remove from favorites" : "Mark as favorite"}`}>
|
||||||
<Tooltip tooltipContent={`${page.is_favorite ? "Remove from favorites" : "Mark as favorite"}`}>
|
{page.is_favorite ? (
|
||||||
{page.is_favorite ? (
|
<button type="button" onClick={handleRemoveFromFavorites}>
|
||||||
<button type="button" onClick={handleRemoveFromFavorites}>
|
<Star className="h-3.5 w-3.5 text-orange-400 fill-orange-400" />
|
||||||
<Star className="h-3.5 w-3.5 text-orange-400 fill-orange-400" />
|
</button>
|
||||||
</button>
|
) : (
|
||||||
) : (
|
<button type="button" onClick={handleAddToFavorites}>
|
||||||
<button type="button" onClick={handleAddToFavorites}>
|
<Star className="h-3.5 w-3.5" />
|
||||||
<Star className="h-3.5 w-3.5" />
|
</button>
|
||||||
</button>
|
)}
|
||||||
)}
|
</Tooltip>
|
||||||
</Tooltip>
|
{userCanChangeAccess && (
|
||||||
)}
|
|
||||||
{!page.archived_at && userCanEdit && (
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
tooltipContent={`${
|
tooltipContent={`${
|
||||||
page.access
|
page.access
|
||||||
@ -234,64 +240,57 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
|
|||||||
)}
|
)}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
position="top-right"
|
position="top-right"
|
||||||
tooltipContent={`Created by ${
|
tooltipContent={`Created by ${ownerDetails?.display_name} on ${renderFormattedDate(page.created_at)}`}
|
||||||
projectMembers?.find((projectMember) => projectMember.member.id === page.created_by)?.member
|
|
||||||
.display_name ?? ""
|
|
||||||
} on ${renderLongDateFormat(`${page.created_at}`)}`}
|
|
||||||
>
|
>
|
||||||
<AlertCircle className="h-3.5 w-3.5" />
|
<AlertCircle className="h-3.5 w-3.5" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{page.archived_at ? (
|
<CustomMenu width="auto" placement="bottom-end" className="!-m-1" verticalEllipsis>
|
||||||
<CustomMenu width="auto" placement="bottom-end" className="!-m-1" verticalEllipsis>
|
{page.archived_at ? (
|
||||||
{userCanEdit && (
|
<>
|
||||||
<>
|
{userCanArchive && (
|
||||||
<CustomMenu.MenuItem onClick={handleRestorePage}>
|
<CustomMenu.MenuItem onClick={handleRestorePage}>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ArchiveRestoreIcon className="h-3 w-3" />
|
<ArchiveRestoreIcon className="h-3 w-3" />
|
||||||
<span>Restore page</span>
|
<span>Restore page</span>
|
||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
|
)}
|
||||||
|
{userCanDelete && (
|
||||||
<CustomMenu.MenuItem onClick={handleDeletePage}>
|
<CustomMenu.MenuItem onClick={handleDeletePage}>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Trash2 className="h-3 w-3" />
|
<Trash2 className="h-3 w-3" />
|
||||||
<span>Delete page</span>
|
<span>Delete page</span>
|
||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
</>
|
)}
|
||||||
)}
|
</>
|
||||||
<CustomMenu.MenuItem onClick={handleCopyUrl}>
|
) : (
|
||||||
<div className="flex items-center gap-2">
|
<>
|
||||||
<LinkIcon className="h-3 w-3" />
|
{userCanEdit && (
|
||||||
<span>Copy page link</span>
|
|
||||||
</div>
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
</CustomMenu>
|
|
||||||
) : (
|
|
||||||
<CustomMenu width="auto" placement="bottom-end" className="!-m-1" verticalEllipsis>
|
|
||||||
{userCanEdit && (
|
|
||||||
<>
|
|
||||||
<CustomMenu.MenuItem onClick={handleEditPage}>
|
<CustomMenu.MenuItem onClick={handleEditPage}>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Pencil className="h-3 w-3" />
|
<Pencil className="h-3 w-3" />
|
||||||
<span>Edit page</span>
|
<span>Edit page</span>
|
||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
|
)}
|
||||||
|
{userCanArchive && (
|
||||||
<CustomMenu.MenuItem onClick={handleArchivePage}>
|
<CustomMenu.MenuItem onClick={handleArchivePage}>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Archive className="h-3 w-3" />
|
<Archive className="h-3 w-3" />
|
||||||
<span>Archive page</span>
|
<span>Archive page</span>
|
||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
</>
|
)}
|
||||||
)}
|
</>
|
||||||
<CustomMenu.MenuItem onClick={handleCopyUrl}>
|
)}
|
||||||
<div className="flex items-center gap-2">
|
<CustomMenu.MenuItem onClick={handleCopyUrl}>
|
||||||
<LinkIcon className="h-3 w-3" />
|
<div className="flex items-center gap-2">
|
||||||
<span>Copy page link</span>
|
<LinkIcon className="h-3 w-3" />
|
||||||
</div>
|
<span>Copy page link</span>
|
||||||
</CustomMenu.MenuItem>
|
</div>
|
||||||
</CustomMenu>
|
</CustomMenu.MenuItem>
|
||||||
)}
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,9 +10,11 @@ import { NewEmptyState } from "components/common/new-empty-state";
|
|||||||
// ui
|
// ui
|
||||||
import { Loader } from "@plane/ui";
|
import { Loader } from "@plane/ui";
|
||||||
// images
|
// images
|
||||||
import emptyPage from "public/empty-state/empty_page.webp";
|
import emptyPage from "public/empty-state/empty_page.png";
|
||||||
// types
|
// types
|
||||||
import { IPage } from "types";
|
import { IPage } from "types";
|
||||||
|
// constants
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
type IPagesListView = {
|
type IPagesListView = {
|
||||||
pages: IPage[];
|
pages: IPage[];
|
||||||
@ -20,11 +22,27 @@ type IPagesListView = {
|
|||||||
|
|
||||||
export const PagesListView: FC<IPagesListView> = observer(({ pages }) => {
|
export const PagesListView: FC<IPagesListView> = observer(({ pages }) => {
|
||||||
// store
|
// store
|
||||||
const { commandPalette: commandPaletteStore } = useMobxStore();
|
const {
|
||||||
|
user: { currentProjectRole },
|
||||||
|
commandPalette: { toggleCreatePageModal },
|
||||||
|
} = useMobxStore();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
|
const canUserCreatePage =
|
||||||
|
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
|
||||||
|
|
||||||
|
const emptyStatePrimaryButton = canUserCreatePage
|
||||||
|
? {
|
||||||
|
primaryButton: {
|
||||||
|
icon: <Plus className="h-4 w-4" />,
|
||||||
|
text: "Create your first page",
|
||||||
|
onClick: () => toggleCreatePageModal(true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{pages && workspaceSlug && projectId ? (
|
{pages && workspaceSlug && projectId ? (
|
||||||
@ -51,11 +69,7 @@ export const PagesListView: FC<IPagesListView> = observer(({ pages }) => {
|
|||||||
"We wrote Parth and Meera’s love story. You could write your project’s mission, goals, and eventual vision.",
|
"We wrote Parth and Meera’s love story. You could write your project’s mission, goals, and eventual vision.",
|
||||||
direction: "right",
|
direction: "right",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
{...emptyStatePrimaryButton}
|
||||||
icon: <Plus className="h-4 w-4" />,
|
|
||||||
text: "Create your first page",
|
|
||||||
onClick: () => commandPaletteStore.toggleCreatePageModal(true),
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,7 +9,7 @@ import { NewEmptyState } from "components/common/new-empty-state";
|
|||||||
// ui
|
// ui
|
||||||
import { Loader } from "@plane/ui";
|
import { Loader } from "@plane/ui";
|
||||||
// assets
|
// assets
|
||||||
import emptyPage from "public/empty-state/empty_page.webp";
|
import emptyPage from "public/empty-state/empty_page.png";
|
||||||
// helpers
|
// helpers
|
||||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import { NextPageWithLayout } from "types/app";
|
|||||||
import { IPage } from "types";
|
import { IPage } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PAGE_DETAILS } from "constants/fetch-keys";
|
import { PAGE_DETAILS } from "constants/fetch-keys";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
// services
|
// services
|
||||||
const fileService = new FileService();
|
const fileService = new FileService();
|
||||||
@ -42,6 +43,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
appConfig: { envConfig },
|
appConfig: { envConfig },
|
||||||
|
user: { currentProjectRole },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -217,12 +219,24 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isPageReadOnly =
|
||||||
|
pageDetails?.is_locked ||
|
||||||
|
(currentProjectRole && [EUserWorkspaceRoles.VIEWER, EUserWorkspaceRoles.GUEST].includes(currentProjectRole));
|
||||||
|
|
||||||
|
const isCurrentUserOwner = pageDetails?.owned_by === user?.id;
|
||||||
|
|
||||||
|
const userCanDuplicate =
|
||||||
|
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
|
||||||
|
const userCanArchive = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
const userCanLock =
|
||||||
|
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{pageDetails ? (
|
{pageDetails ? (
|
||||||
<div className="flex h-full flex-col justify-between">
|
<div className="flex h-full flex-col justify-between">
|
||||||
<div className="h-full w-full overflow-hidden">
|
<div className="h-full w-full overflow-hidden">
|
||||||
{pageDetails.is_locked || pageDetails.archived_at ? (
|
{isPageReadOnly ? (
|
||||||
<DocumentReadOnlyEditorWithRef
|
<DocumentReadOnlyEditorWithRef
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={pageDetails.description_html}
|
value={pageDetails.description_html}
|
||||||
@ -278,18 +292,16 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
setIsSubmitting("submitting");
|
setIsSubmitting("submitting");
|
||||||
debouncedFormSave();
|
debouncedFormSave();
|
||||||
}}
|
}}
|
||||||
duplicationConfig={{ action: duplicate_page }}
|
duplicationConfig={userCanDuplicate ? { action: duplicate_page } : undefined}
|
||||||
pageArchiveConfig={
|
pageArchiveConfig={
|
||||||
user && pageDetails.owned_by === user.id
|
userCanArchive
|
||||||
? {
|
? {
|
||||||
is_archived: pageDetails.archived_at ? true : false,
|
is_archived: pageDetails.archived_at ? true : false,
|
||||||
action: pageDetails.archived_at ? unArchivePage : archivePage,
|
action: pageDetails.archived_at ? unArchivePage : archivePage,
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
pageLockConfig={
|
pageLockConfig={userCanLock ? { is_locked: false, action: lockPage } : undefined}
|
||||||
user && pageDetails.owned_by === user.id ? { is_locked: false, action: lockPage } : undefined
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -162,7 +162,7 @@ const ProjectPagesPage: NextPageWithLayout = observer(() => {
|
|||||||
|
|
||||||
ProjectPagesPage.getLayout = function getLayout(page: ReactElement) {
|
ProjectPagesPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
return (
|
return (
|
||||||
<AppLayout header={<PagesHeader showButton />} withProjectWrapper>
|
<AppLayout header={<PagesHeader />} withProjectWrapper>
|
||||||
{page}
|
{page}
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
);
|
);
|
||||||
|
BIN
web/public/empty-state/empty_page.png
Normal file
BIN
web/public/empty-state/empty_page.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
Before Width: | Height: | Size: 46 KiB |
Loading…
Reference in New Issue
Block a user