mirror of
https://github.com/makeplane/plane.git
synced 2026-07-12 05:21:14 +02:00
Merge branch 'chore-cycles-upgrade' of github.com:makeplane/plane into chore-cycles-upgrade
This commit is contained in:
@@ -37,7 +37,7 @@ class IssueReactionViewSet(BaseViewSet):
|
||||
.distinct()
|
||||
)
|
||||
|
||||
@allow_permission(ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST)
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
def create(self, request, slug, project_id, issue_id):
|
||||
serializer = IssueReactionSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
@@ -60,7 +60,7 @@ class IssueReactionViewSet(BaseViewSet):
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@allow_permission(ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST)
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
def destroy(self, request, slug, project_id, issue_id, reaction_code):
|
||||
issue_reaction = IssueReaction.objects.get(
|
||||
workspace__slug=slug,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef, useState, useCallback, useLayoutEffect } from "react";
|
||||
import React, { useRef, useState, useCallback, useLayoutEffect, useEffect } from "react";
|
||||
import { NodeSelection } from "@tiptap/pm/state";
|
||||
// extensions
|
||||
import { CustomImageNodeViewProps } from "@/extensions/custom-image";
|
||||
@@ -13,52 +13,84 @@ export const CustomImageBlock: React.FC<CustomImageNodeViewProps> = (props) => {
|
||||
|
||||
const [size, setSize] = useState({ width: width || "35%", height: height || "auto" });
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [initialResizeComplete, setInitialResizeComplete] = useState(false);
|
||||
const isShimmerVisible = isLoading || !initialResizeComplete;
|
||||
const [editorContainer, setEditorContainer] = useState<HTMLElement | null>(null);
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const containerRect = useRef<DOMRect | null>(null);
|
||||
const imageRef = useRef<HTMLImageElement>(null);
|
||||
const isResizing = useRef(false);
|
||||
const aspectRatio = useRef(1);
|
||||
const aspectRatioRef = useRef<number | null>(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (imageRef.current) {
|
||||
const img = imageRef.current;
|
||||
img.onload = () => {
|
||||
if (node.attrs.width === "35%" && node.attrs.height === "auto") {
|
||||
aspectRatio.current = img.naturalWidth / img.naturalHeight;
|
||||
const initialWidth = Math.max(img.naturalWidth * 0.35, MIN_SIZE);
|
||||
const initialHeight = initialWidth / aspectRatio.current;
|
||||
setSize({ width: `${initialWidth}px`, height: `${initialHeight}px` });
|
||||
const closestEditorContainer = img.closest(".editor-container");
|
||||
if (!closestEditorContainer) {
|
||||
console.error("Editor container not found");
|
||||
return;
|
||||
}
|
||||
|
||||
setEditorContainer(closestEditorContainer as HTMLElement);
|
||||
|
||||
if (width === "35%") {
|
||||
const editorWidth = closestEditorContainer.clientWidth;
|
||||
const initialWidth = Math.max(editorWidth * 0.35, MIN_SIZE);
|
||||
const aspectRatio = img.naturalWidth / img.naturalHeight;
|
||||
const initialHeight = initialWidth / aspectRatio;
|
||||
|
||||
const newSize = {
|
||||
width: `${Math.round(initialWidth)}px`,
|
||||
height: `${Math.round(initialHeight)}px`,
|
||||
};
|
||||
|
||||
setSize(newSize);
|
||||
updateAttributes(newSize);
|
||||
}
|
||||
setInitialResizeComplete(true);
|
||||
setIsLoading(false);
|
||||
};
|
||||
}
|
||||
}, [src]);
|
||||
|
||||
const handleResizeStart = useCallback((e: React.MouseEvent | React.TouchEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
isResizing.current = true;
|
||||
if (containerRef.current) {
|
||||
containerRect.current = containerRef.current.getBoundingClientRect();
|
||||
}
|
||||
}, []);
|
||||
}, [width, height, updateAttributes]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
// for realtime resizing and undo/redo
|
||||
setSize({ width, height });
|
||||
}, [width, height]);
|
||||
|
||||
const handleResize = useCallback((e: MouseEvent | TouchEvent) => {
|
||||
if (!isResizing.current || !containerRef.current || !containerRect.current) return;
|
||||
const handleResizeStart = useCallback(
|
||||
(e: React.MouseEvent | React.TouchEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
isResizing.current = true;
|
||||
if (containerRef.current && editorContainer) {
|
||||
aspectRatioRef.current = Number(size.width.replace("px", "")) / Number(size.height.replace("px", ""));
|
||||
containerRect.current = containerRef.current.getBoundingClientRect();
|
||||
}
|
||||
},
|
||||
[size, editorContainer]
|
||||
);
|
||||
|
||||
const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
|
||||
const handleResize = useCallback(
|
||||
(e: MouseEvent | TouchEvent) => {
|
||||
if (!isResizing.current || !containerRef.current || !containerRect.current) return;
|
||||
|
||||
const newWidth = Math.max(clientX - containerRect.current.left, MIN_SIZE);
|
||||
const newHeight = newWidth / aspectRatio.current;
|
||||
if (size) {
|
||||
aspectRatioRef.current = Number(size.width.replace("px", "")) / Number(size.height.replace("px", ""));
|
||||
}
|
||||
|
||||
setSize({ width: `${newWidth}px`, height: `${newHeight}px` });
|
||||
}, []);
|
||||
if (!aspectRatioRef.current) return;
|
||||
|
||||
const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
|
||||
|
||||
const newWidth = Math.max(clientX - containerRect.current.left, MIN_SIZE);
|
||||
const newHeight = newWidth / aspectRatioRef.current;
|
||||
|
||||
setSize({ width: `${newWidth}px`, height: `${newHeight}px` });
|
||||
},
|
||||
[size]
|
||||
);
|
||||
|
||||
const handleResizeEnd = useCallback(() => {
|
||||
if (isResizing.current) {
|
||||
@@ -77,18 +109,23 @@ export const CustomImageBlock: React.FC<CustomImageNodeViewProps> = (props) => {
|
||||
[editor, getPos]
|
||||
);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const handleGlobalMouseMove = (e: MouseEvent) => handleResize(e);
|
||||
const handleGlobalMouseUp = () => handleResizeEnd();
|
||||
useEffect(() => {
|
||||
if (!editorContainer) return;
|
||||
|
||||
document.addEventListener("mousemove", handleGlobalMouseMove);
|
||||
document.addEventListener("mouseup", handleGlobalMouseUp);
|
||||
const handleMouseMove = (e: MouseEvent) => handleResize(e);
|
||||
const handleMouseUp = () => handleResizeEnd();
|
||||
const handleMouseLeave = () => handleResizeEnd();
|
||||
|
||||
editorContainer.addEventListener("mousemove", handleMouseMove);
|
||||
editorContainer.addEventListener("mouseup", handleMouseUp);
|
||||
editorContainer.addEventListener("mouseleave", handleMouseLeave);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleGlobalMouseMove);
|
||||
document.removeEventListener("mouseup", handleGlobalMouseUp);
|
||||
editorContainer.removeEventListener("mousemove", handleMouseMove);
|
||||
editorContainer.removeEventListener("mouseup", handleMouseUp);
|
||||
editorContainer.removeEventListener("mouseleave", handleMouseLeave);
|
||||
};
|
||||
}, [handleResize, handleResizeEnd]);
|
||||
}, [handleResize, handleResizeEnd, editorContainer]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -100,12 +137,16 @@ export const CustomImageBlock: React.FC<CustomImageNodeViewProps> = (props) => {
|
||||
height: size.height,
|
||||
}}
|
||||
>
|
||||
{isLoading && <div className="animate-pulse bg-custom-background-80 rounded-md" style={{ width, height }} />}
|
||||
{isShimmerVisible && (
|
||||
<div className="animate-pulse bg-custom-background-80 rounded-md" style={{ width, height }} />
|
||||
)}
|
||||
<img
|
||||
ref={imageRef}
|
||||
src={src}
|
||||
width={size.width}
|
||||
height={size.height}
|
||||
className={cn("block rounded-md", {
|
||||
hidden: isLoading,
|
||||
hidden: isShimmerVisible,
|
||||
"read-only-image": !editor.isEditable,
|
||||
})}
|
||||
style={{
|
||||
|
||||
@@ -46,6 +46,7 @@ export const TrackImageDeletionPlugin = (editor: Editor, deleteImage: DeleteImag
|
||||
|
||||
async function onNodeDeleted(src: string, deleteImage: DeleteImage): Promise<void> {
|
||||
try {
|
||||
if (!src) return;
|
||||
const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1);
|
||||
await deleteImage(assetUrlWithWorkspaceId);
|
||||
} catch (error) {
|
||||
|
||||
@@ -49,6 +49,7 @@ export const TrackImageRestorationPlugin = (editor: Editor, restoreImage: Restor
|
||||
|
||||
async function onNodeRestored(src: string, restoreImage: RestoreImage): Promise<void> {
|
||||
try {
|
||||
if (!src) return;
|
||||
const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1);
|
||||
await restoreImage(assetUrlWithWorkspaceId);
|
||||
} catch (error) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import useSWR from "swr";
|
||||
import { IAnalyticsParams } from "@plane/types";
|
||||
// services
|
||||
// components
|
||||
import { ContentWrapper } from "@plane/ui";
|
||||
import { CustomAnalyticsSelectBar, CustomAnalyticsMainContent, CustomAnalyticsSidebar } from "@/components/analytics";
|
||||
// types
|
||||
// fetch-keys
|
||||
@@ -54,7 +53,7 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
|
||||
|
||||
return (
|
||||
<div className={cn("relative flex h-full w-full overflow-hidden", isProjectLevel ? "flex-col-reverse" : "")}>
|
||||
<ContentWrapper>
|
||||
<div className="flex h-full w-full flex-col overflow-hidden">
|
||||
<CustomAnalyticsSelectBar
|
||||
control={control}
|
||||
setValue={setValue}
|
||||
@@ -68,7 +67,7 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
|
||||
params={params}
|
||||
fullScreen={fullScreen}
|
||||
/>
|
||||
</ContentWrapper>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@@ -5,6 +5,7 @@ import { IAnalyticsParams } from "@plane/types";
|
||||
import { SelectProject, SelectSegment, SelectXAxis, SelectYAxis } from "@/components/analytics";
|
||||
import { ANALYTICS_X_AXIS_VALUES } from "@/constants/analytics";
|
||||
import { useProject } from "@/hooks/store";
|
||||
import { Row } from "@plane/ui";
|
||||
// components
|
||||
// types
|
||||
|
||||
@@ -30,10 +31,10 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
|
||||
: ANALYTICS_X_AXIS_VALUES;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`grid items-center gap-4 pb-2.5 ${
|
||||
<Row
|
||||
className={`grid items-center gap-4 py-2.5 ${
|
||||
isProjectLevel ? "grid-cols-1 sm:grid-cols-3" : "grid-cols-2"
|
||||
} ${fullScreen ? "md:pb-5 lg:grid-cols-4" : ""}`}
|
||||
} ${fullScreen ? "md:py-5 lg:grid-cols-4" : ""}`}
|
||||
>
|
||||
{!isProjectLevel && (
|
||||
<div>
|
||||
@@ -88,6 +89,6 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, params, yAxisKey }) => (
|
||||
<div className="w-full overflow-hidden overflow-x-auto absolute left-0">
|
||||
<div className="w-full overflow-hidden overflow-x-auto">
|
||||
<table className="w-full overflow-hidden divide-y divide-custom-border-200 whitespace-nowrap border-y border-custom-border-200">
|
||||
<thead className="bg-custom-background-80">
|
||||
<tr className="divide-x divide-custom-border-200 text-sm text-custom-text-100">
|
||||
|
||||
@@ -54,7 +54,7 @@ export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
||||
});
|
||||
})
|
||||
.catch((errors) => {
|
||||
const isPermissionError = errors?.error === "Only admin or owner can delete the cycle";
|
||||
const isPermissionError = errors?.error === "You don't have the required permissions.";
|
||||
const currentError = isPermissionError
|
||||
? PROJECT_ERROR_MESSAGES.permissionError
|
||||
: PROJECT_ERROR_MESSAGES.cycleDeleteError;
|
||||
|
||||
@@ -66,7 +66,7 @@ export const OverviewStatsWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
return (
|
||||
<Card
|
||||
spacing={ECardSpacing.SM}
|
||||
className="flex-row grid lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-2 grid-cols-2 space-y-0
|
||||
className="flex-row grid lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-2 grid-cols-2 space-y-0 p-0.5
|
||||
[&>div>a>div]:border-r
|
||||
[&>div:last-child>a>div]:border-0
|
||||
[&>div>a>div]:border-custom-border-200
|
||||
@@ -79,8 +79,8 @@ export const OverviewStatsWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
key={stat.key}
|
||||
className={cn(
|
||||
`w-full flex flex-col gap-2 hover:bg-custom-background-80`,
|
||||
index === 0 ? "rounded-tl-xl lg:rounded-l-xl" : "",
|
||||
index === STATS_LIST.length - 1 ? "rounded-br-xl lg:rounded-r-xl" : "",
|
||||
index === 0 ? "rounded-l-md" : "",
|
||||
index === STATS_LIST.length - 1 ? "rounded-r-md" : "",
|
||||
index === 1 ? "rounded-tr-xl lg:rounded-[0px]" : "",
|
||||
index == 2 ? "rounded-bl-xl lg:rounded-[0px]" : ""
|
||||
)}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
||||
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { cn } from "@plane/editor";
|
||||
// plane packages
|
||||
import {
|
||||
@@ -90,6 +91,7 @@ export const ListGroup = observer((props: Props) => {
|
||||
const [isExpanded, setIsExpanded] = useState(true);
|
||||
const groupRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const { projectId } = useParams();
|
||||
const projectState = useProjectState();
|
||||
|
||||
const {
|
||||
@@ -216,7 +218,8 @@ export const ListGroup = observer((props: Props) => {
|
||||
);
|
||||
}, [groupRef?.current, group, orderBy, getGroupIndex, setDragColumnOrientation, setIsDraggingOverColumn]);
|
||||
|
||||
const isDragAllowed = !!group_by && DRAG_ALLOWED_GROUPS.includes(group_by);
|
||||
const isDragAllowed =
|
||||
!!group_by && DRAG_ALLOWED_GROUPS.includes(group_by) && canEditProperties(projectId?.toString());
|
||||
const canOverlayBeVisible = orderBy !== "sort_order" || !!group.isDropDisabled;
|
||||
|
||||
const isGroupByCreatedBy = group_by === "created_by";
|
||||
|
||||
@@ -6,12 +6,28 @@ import { ProjectIssueQuickActions } from "@/components/issues";
|
||||
// components
|
||||
// types
|
||||
// constants
|
||||
import { useUserPermissions } from "@/hooks/store";
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
import { BaseListRoot } from "../base-list-root";
|
||||
|
||||
export const ListLayout: FC = observer(() => {
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
if (!workspaceSlug || !projectId) return null;
|
||||
|
||||
return <BaseListRoot QuickActions={ProjectIssueQuickActions} />;
|
||||
const canEditPropertiesBasedOnProject = (projectId: string) =>
|
||||
allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug.toString(),
|
||||
projectId
|
||||
);
|
||||
|
||||
return (
|
||||
<BaseListRoot
|
||||
QuickActions={ProjectIssueQuickActions}
|
||||
canEditPropertiesBasedOnProject={canEditPropertiesBasedOnProject}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -25,10 +25,20 @@ type Props = {
|
||||
droppedLabelId: string | undefined,
|
||||
dropAtEndOfList: boolean
|
||||
) => void;
|
||||
isEditable?: boolean;
|
||||
};
|
||||
|
||||
export const ProjectSettingLabelGroup: React.FC<Props> = observer((props) => {
|
||||
const { label, labelChildren, handleLabelDelete, isUpdating, setIsUpdating, isLastChild, onDrop } = props;
|
||||
const {
|
||||
label,
|
||||
labelChildren,
|
||||
handleLabelDelete,
|
||||
isUpdating,
|
||||
setIsUpdating,
|
||||
isLastChild,
|
||||
onDrop,
|
||||
isEditable = false,
|
||||
} = props;
|
||||
|
||||
// states
|
||||
const [isEditLabelForm, setEditLabelForm] = useState(false);
|
||||
@@ -123,6 +133,7 @@ export const ProjectSettingLabelGroup: React.FC<Props> = observer((props) => {
|
||||
isChild
|
||||
isLastChild={index === labelChildren.length - 1}
|
||||
onDrop={onDrop}
|
||||
isEditable={isEditable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -111,6 +111,7 @@ export const ProjectSettingsLabelList: React.FC = observer(() => {
|
||||
setIsUpdating={setIsUpdating}
|
||||
isLastChild={index === projectLabelsTree.length - 1}
|
||||
onDrop={onDrop}
|
||||
isEditable={isEditable}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -123,6 +124,7 @@ export const ProjectSettingsLabelList: React.FC = observer(() => {
|
||||
isChild={false}
|
||||
isLastChild={index === projectLabelsTree.length - 1}
|
||||
onDrop={onDrop}
|
||||
isEditable={isEditable}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -56,7 +56,7 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
|
||||
});
|
||||
})
|
||||
.catch((errors) => {
|
||||
const isPermissionError = errors?.error === "Only admin or creator can delete the module";
|
||||
const isPermissionError = errors?.error === "You don't have the required permissions.";
|
||||
const currentError = isPermissionError
|
||||
? PROJECT_ERROR_MESSAGES.permissionError
|
||||
: PROJECT_ERROR_MESSAGES.moduleDeleteError;
|
||||
|
||||
@@ -67,7 +67,7 @@ export const WorkspaceDashboardView = observer(() => {
|
||||
<>
|
||||
<IssuePeekOverview />
|
||||
<ContentWrapper
|
||||
className={cn("gap-7", {
|
||||
className={cn("gap-7 bg-custom-background-90", {
|
||||
"vertical-scrollbar scrollbar-lg": windowWidth >= 768,
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -60,10 +60,10 @@ export const LeaveProjectModal: FC<ILeaveProjectModal> = observer((props) => {
|
||||
if (data) {
|
||||
if (data.projectName === project?.name) {
|
||||
if (data.confirmLeave === "Leave Project") {
|
||||
router.push(`/${workspaceSlug}/projects`);
|
||||
return leaveProject(workspaceSlug.toString(), project.id)
|
||||
.then(() => {
|
||||
handleClose();
|
||||
router.push(`/${workspaceSlug}/projects`);
|
||||
captureEvent(PROJECT_MEMBER_LEAVE, {
|
||||
state: "SUCCESS",
|
||||
element: "Project settings members page",
|
||||
|
||||
@@ -38,6 +38,7 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
||||
if (!workspaceSlug || !projectId || !memberId) return;
|
||||
|
||||
if (memberId === currentUser?.id) {
|
||||
router.push(`/${workspaceSlug}/projects`);
|
||||
await leaveProject(workspaceSlug.toString(), projectId.toString())
|
||||
.then(async () => {
|
||||
captureEvent(PROJECT_MEMBER_LEAVE, {
|
||||
@@ -45,7 +46,6 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
||||
element: "Project settings members page",
|
||||
});
|
||||
await fetchProjects(workspaceSlug.toString());
|
||||
router.push(`/${workspaceSlug}/projects`);
|
||||
})
|
||||
.catch((err) =>
|
||||
setToast({
|
||||
|
||||
@@ -97,9 +97,11 @@ export const AccountTypeColumn: React.FC<AccountTypeProps> = observer((props) =>
|
||||
|
||||
// derived values
|
||||
const isCurrentUser = currentUser?.id === rowData.member.id;
|
||||
const isAdminOrGuest = [EUserPermissions.ADMIN, EUserPermissions.GUEST].includes(rowData.role);
|
||||
const userWorkspaceRole = getWorkspaceMemberDetails(rowData.member.id)?.role;
|
||||
const isRoleNonEditable = isCurrentUser || (isAdminOrGuest && userWorkspaceRole !== EUserPermissions.MEMBER);
|
||||
const isProjectAdminOrGuest = [EUserPermissions.ADMIN, EUserPermissions.GUEST].includes(rowData.role);
|
||||
const isWorkspaceMember = [EUserPermissions.MEMBER].includes(
|
||||
Number(getWorkspaceMemberDetails(rowData.member.id)?.role) ?? EUserPermissions.GUEST
|
||||
);
|
||||
const isRoleNonEditable = isCurrentUser || (isProjectAdminOrGuest && !isWorkspaceMember);
|
||||
|
||||
const checkCurrentOptionWorkspaceRole = (value: string) => {
|
||||
const currentMemberWorkspaceRole = getWorkspaceMemberDetails(value)?.role as EUserPermissions | undefined;
|
||||
|
||||
@@ -114,9 +114,7 @@ export const AccountTypeColumn: React.FC<AccountTypeProps> = observer((props) =>
|
||||
<CustomSelect
|
||||
value={value}
|
||||
onChange={(value: EUserPermissions) => {
|
||||
console.log({ value, workspaceSlug }, "onChange");
|
||||
if (!workspaceSlug) return;
|
||||
|
||||
updateMember(workspaceSlug.toString(), rowData.member.id, {
|
||||
role: value as unknown as EUserPermissions, // Cast value to unknown first, then to EUserPermissions
|
||||
}).catch((err) => {
|
||||
|
||||
Reference in New Issue
Block a user