Skip to content

Commit

Permalink
Merge branch 'preview' into fix/image-upload-realtime
Browse files Browse the repository at this point in the history
  • Loading branch information
Palanikannan1437 committed Sep 16, 2024
2 parents 5c27a72 + 7450755 commit d7484df
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 86 deletions.
1 change: 1 addition & 0 deletions apiserver/plane/app/serializers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class Meta:
"is_bot",
"display_name",
"email",
"last_login_medium",
]
read_only_fields = [
"id",
Expand Down
2 changes: 1 addition & 1 deletion apiserver/plane/app/views/project/invite.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def create(self, request, slug):
ProjectMember(
project_id=project_id,
member=request.user,
role=15 if workspace_role >= 15 else 5,
role=workspace_role,
workspace=workspace,
created_by=request.user,
)
Expand Down
34 changes: 7 additions & 27 deletions apiserver/plane/app/views/workspace/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
WorkSpaceAdminPermission,
WorkspaceEntityPermission,
allow_permission,
ROLE
ROLE,
)

# Module imports
Expand Down Expand Up @@ -44,7 +44,6 @@ class WorkSpaceMemberViewSet(BaseViewSet):
serializer_class = WorkspaceMemberAdminSerializer
model = WorkspaceMember


search_fields = [
"member__display_name",
"member__first_name",
Expand Down Expand Up @@ -96,9 +95,7 @@ def list(self, request, slug):
user=False,
multiple=True,
)
@allow_permission(
allowed_roles=[ROLE.ADMIN], level="WORKSPACE"
)
@allow_permission(allowed_roles=[ROLE.ADMIN], level="WORKSPACE")
def partial_update(self, request, slug, pk):
workspace_member = WorkspaceMember.objects.get(
pk=pk,
Expand All @@ -112,25 +109,10 @@ def partial_update(self, request, slug, pk):
status=status.HTTP_400_BAD_REQUEST,
)

# Get the requested user role
requested_workspace_member = WorkspaceMember.objects.get(
workspace__slug=slug,
member=request.user,
is_active=True,
)
# Check if role is being updated
# One cannot update role higher than his own role
if (
"role" in request.data
and int(request.data.get("role", workspace_member.role))
> requested_workspace_member.role
):
return Response(
{
"error": "You cannot update a role that is higher than your own role"
},
status=status.HTTP_400_BAD_REQUEST,
)
if workspace_member.role > int(request.data.get("role")):
_ = ProjectMember.objects.filter(
workspace__slug=slug, member_id=workspace_member.member_id
).update(role=int(request.data.get("role")))

serializer = WorkSpaceMemberSerializer(
workspace_member, data=request.data, partial=True
Expand All @@ -151,9 +133,7 @@ def partial_update(self, request, slug, pk):
@invalidate_cache(
path="/api/users/me/workspaces/", user=False, multiple=True
)
@allow_permission(
allowed_roles=[ROLE.ADMIN], level="WORKSPACE"
)
@allow_permission(allowed_roles=[ROLE.ADMIN], level="WORKSPACE")
def destroy(self, request, slug, pk):
# Check the user role who is deleting the user
workspace_member = WorkspaceMember.objects.get(
Expand Down
6 changes: 3 additions & 3 deletions apiserver/plane/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
CELERY_BROKER_URL = AMQP_URL
else:
CELERY_BROKER_URL = f"amqp://{RABBITMQ_USER}:{RABBITMQ_PASSWORD}@{RABBITMQ_HOST}:{RABBITMQ_PORT}/{RABBITMQ_VHOST}"

CELERY_TIMEZONE = TIME_ZONE
CELERY_TASK_SERIALIZER = "json"
CELERY_RESULT_SERIALIZER = "json"
Expand Down Expand Up @@ -336,14 +336,14 @@
SESSION_COOKIE_HTTPONLY = True
SESSION_ENGINE = "plane.db.models.session"
SESSION_COOKIE_AGE = os.environ.get("SESSION_COOKIE_AGE", 604800)
SESSION_COOKIE_NAME = "plane-session-id"
SESSION_COOKIE_NAME = os.environ.get("SESSION_COOKIE_NAME", "session-id")
SESSION_COOKIE_DOMAIN = os.environ.get("COOKIE_DOMAIN", None)
SESSION_SAVE_EVERY_REQUEST = (
os.environ.get("SESSION_SAVE_EVERY_REQUEST", "0") == "1"
)

# Admin Cookie
ADMIN_SESSION_COOKIE_NAME = "plane-admin-session-id"
ADMIN_SESSION_COOKIE_NAME = "admin-session-id"
ADMIN_SESSION_COOKIE_AGE = os.environ.get("ADMIN_SESSION_COOKIE_AGE", 3600)

# CSRF cookies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export const CustomImageNode = (props: CustomImageNodeViewProps) => {
onUpload(url);
} catch (error) {
console.error("Error uploading file:", error);
// Handle error state here if needed
}
},
[editor.commands, onUpload]
Expand Down
1 change: 0 additions & 1 deletion packages/editor/src/core/extensions/extensions.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { HocuspocusProvider } from "@hocuspocus/provider";
import CharacterCount from "@tiptap/extension-character-count";
import Placeholder from "@tiptap/extension-placeholder";
import TaskItem from "@tiptap/extension-task-item";
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/workspace.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export interface IWorkspaceMember {
last_name?: string;
joining_date?: string;
display_name?: string;
last_login_medium?: string;
}

export interface IWorkspaceMemberMe {
Expand Down
39 changes: 28 additions & 11 deletions web/app/[workspaceSlug]/(projects)/settings/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,51 @@
"use client";

import { ReactNode } from "react";
import { FC, ReactNode } from "react";
import { observer } from "mobx-react";
// components
import { AppHeader } from "@/components/core";
// local components
import { WorkspaceSettingHeader } from "./header";
import { MobileWorkspaceSettingsTabs } from "./mobile-header-tabs";
import { WorkspaceSettingsSidebar } from "./sidebar";
import { NotAuthorizedView } from "@/components/auth-screens";
import { useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";

export interface IWorkspaceSettingLayout {
children: ReactNode;
}

export default function WorkspaceSettingLayout(props: IWorkspaceSettingLayout) {
const WorkspaceSettingLayout: FC<IWorkspaceSettingLayout> = observer((props) => {
const { children } = props;

const { workspaceUserInfo, allowPermissions } = useUserPermissions();

// derived values
const isWorkspaceAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);

return (
<>
<AppHeader header={<WorkspaceSettingHeader />} />
<MobileWorkspaceSettingsTabs />
<div className="inset-y-0 flex flex-row vertical-scrollbar scrollbar-lg h-full w-full overflow-y-auto">
<div className="px-page-x !pr-0 py-page-y flex-shrink-0 overflow-y-hidden sm:hidden hidden md:block lg:block">
<WorkspaceSettingsSidebar />
</div>
<div className="flex flex-col relative w-full overflow-hidden">
<div className="w-full h-full overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-page-x md:px-9 py-page-y">
{children}
</div>
</div>
{workspaceUserInfo && !isWorkspaceAdmin ? (
<NotAuthorizedView section="settings" />
) : (
<>
<div className="px-page-x !pr-0 py-page-y flex-shrink-0 overflow-y-hidden sm:hidden hidden md:block lg:block">
<WorkspaceSettingsSidebar />
</div>
<div className="flex flex-col relative w-full overflow-hidden">
<div className="w-full h-full overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-page-x md:px-9 py-page-y">
{children}
</div>
</div>
</>
)}
</div>
</>
);
}
});

export default WorkspaceSettingLayout;
31 changes: 23 additions & 8 deletions web/ce/components/workspace/settings/useMemberColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export const useMemberColumns = () => {

const columns = [
{
key: "Full Name",
content: "Full Name",
key: "Full name",
content: "Full name",
thClassName: "text-left",
tdRender: (rowData: RowData) => (
<NameColumn
Expand All @@ -38,21 +38,36 @@ export const useMemberColumns = () => {
/>
),
},

{
key: "Display Name",
content: "Display Name",
key: "Display name",
content: "Display name",
tdRender: (rowData: RowData) => <div className="w-32">{rowData.member.display_name}</div>,
},

{
key: "Account Type",
content: "Account Type",
key: "Email address",
content: "Email address",
tdRender: (rowData: RowData) => <div className="w-48 truncate">{rowData.member.email}</div>,
},

{
key: "Account type",
content: "Account type",
tdRender: (rowData: RowData) => <AccountTypeColumn rowData={rowData} workspaceSlug={workspaceSlug as string} />,
},

{
key: "Joining Date",
content: "Joining Date",
key: "Authentication",
content: "Authentication",
tdRender: (rowData: RowData) => (
<div className="capitalize">{rowData.member.last_login_medium?.replace("-", " ")}</div>
),
},

{
key: "Joining date",
content: "Joining date",
tdRender: (rowData: RowData) => <div>{getFormattedDate(rowData?.member?.joining_date || "")}</div>,
},
];
Expand Down
4 changes: 2 additions & 2 deletions web/ce/constants/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ export const WORKSPACE_SETTINGS = {
key: "general",
label: "General",
href: `/settings`,
access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
access: [EUserPermissions.ADMIN],
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/`,
Icon: SettingIcon,
},
members: {
key: "members",
label: "Members",
href: `/settings/members`,
access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER],
access: [EUserPermissions.ADMIN],
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`,
Icon: SettingIcon,
},
Expand Down
8 changes: 4 additions & 4 deletions web/core/components/project/settings/member-columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,17 @@ export const AccountTypeColumn: React.FC<AccountTypeProps> = observer((props) =>

// derived values
const isCurrentUser = currentUser?.id === rowData.member.id;
const isAdminRole = currentProjectRole === EUserPermissions.ADMIN;
const isRoleNonEditable = isCurrentUser || !isAdminRole;
const isAdminOrGuest = [EUserPermissions.ADMIN, EUserPermissions.GUEST].includes(rowData.role);
const isRoleNonEditable = isCurrentUser || isAdminOrGuest;

const checkCurrentOptionWorkspaceRole = (value: string) => {
const currentMemberWorkspaceRole = getWorkspaceMemberDetails(value)?.role as EUserPermissions | undefined;
if (!value || !currentMemberWorkspaceRole) return ROLE;

const isGuestOrViewer = [EUserPermissions.GUEST].includes(currentMemberWorkspaceRole);
const isGuestOROwner = [EUserPermissions.ADMIN, EUserPermissions.GUEST].includes(currentMemberWorkspaceRole);

return Object.fromEntries(
Object.entries(ROLE).filter(([key]) => !isGuestOrViewer || [5, 10].includes(parseInt(key)))
Object.entries(ROLE).filter(([key]) => !isGuestOROwner || [currentMemberWorkspaceRole].includes(parseInt(key)))
);
};

Expand Down
47 changes: 27 additions & 20 deletions web/core/components/workspace/sidebar/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import { IWorkspace } from "@plane/types";
import { Avatar, Loader, TOAST_TYPE, setToast } from "@plane/ui";
import { GOD_MODE_URL, cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useUser, useUserProfile, useWorkspace } from "@/hooks/store";
import { useAppTheme, useUser, useUserPermissions, useUserProfile, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
import { WorkspaceLogo } from "../logo";

// Static Data
Expand All @@ -25,12 +26,14 @@ const userLinks = (workspaceSlug: string) => [
name: "Workspace invites",
href: "/invitations",
icon: Mails,
access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
},
{
key: "settings",
name: "Workspace settings",
href: `/${workspaceSlug}/settings`,
icon: Settings,
access: [EUserPermissions.ADMIN],
},
];

Expand All @@ -46,6 +49,7 @@ export const SidebarDropdown = observer(() => {
signOut,
} = useUser();
const { updateUserProfile } = useUserProfile();
const { allowPermissions } = useUserPermissions();

const isUserInstanceAdmin = false;
const { currentWorkspace: activeWorkspace, workspaces } = useWorkspace();
Expand Down Expand Up @@ -168,7 +172,7 @@ export const SidebarDropdown = observer(() => {
alt="Workspace Logo"
/>
) : (
workspace?.name?.charAt(0) ?? "..."
(workspace?.name?.charAt(0) ?? "...")
)}
</span>
<h5
Expand Down Expand Up @@ -207,24 +211,27 @@ export const SidebarDropdown = observer(() => {
Create workspace
</Menu.Item>
</Link>
{userLinks(workspaceSlug?.toString() ?? "").map((link, index) => (
<Link
key={link.key}
href={link.href}
className="w-full"
onClick={() => {
if (index > 0) handleItemClick();
}}
>
<Menu.Item
as="div"
className="flex items-center gap-2 rounded px-2 py-1 text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
>
<link.icon className="h-4 w-4 flex-shrink-0" />
{link.name}
</Menu.Item>
</Link>
))}
{userLinks(workspaceSlug?.toString() ?? "").map(
(link, index) =>
allowPermissions(link.access, EUserPermissionsLevel.WORKSPACE) && (
<Link
key={link.key}
href={link.href}
className="w-full"
onClick={() => {
if (index > 0) handleItemClick();
}}
>
<Menu.Item
as="div"
className="flex items-center gap-2 rounded px-2 py-1 text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
>
<link.icon className="h-4 w-4 flex-shrink-0" />
{link.name}
</Menu.Item>
</Link>
)
)}
</div>
<div className="w-full px-4 py-2">
<Menu.Item
Expand Down
12 changes: 6 additions & 6 deletions web/core/layouts/auth-layout/project-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {

// derived values
const projectExists = projectId ? getProjectById(projectId.toString()) : null;
const hasPermissionToCurrentProject = projectId
? allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
EUserPermissionsLevel.PROJECT
)
: undefined;
const hasPermissionToCurrentProject = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
EUserPermissionsLevel.PROJECT,
workspaceSlug.toString(),
projectId.toString()
);

// check if the project member apis is loading
if (!projectMemberInfo && projectId && hasPermissionToCurrentProject === null)
Expand Down
Loading

0 comments on commit d7484df

Please sign in to comment.