Compare commits

...

4 Commits

Author SHA1 Message Date
Vamsi krishna
f13027d6db chore: removed unused vars 2024-12-27 12:44:10 +05:30
NarayanBavisetti
f011364eb6 chore: issue search filter 2024-12-26 19:48:58 +05:30
Vamsi krishna
8dfd5d9c7d Merge branch 'preview' of github.com:makeplane/plane into fix-restrict_guest_user_assignees_mentions 2024-12-26 15:03:03 +05:30
Vamsi krishna
f2bb944661 fix: removing guest users from assignees and mentions in issues 2024-12-26 13:14:44 +05:30
8 changed files with 72 additions and 48 deletions

View File

@@ -277,28 +277,14 @@ class SearchEndpoint(BaseAPIView):
for field in fields:
q |= Q(**{f"{field}__icontains": query})
base_filters = Q(
q,
is_active=True,
workspace__slug=slug,
member__is_bot=False,
project_id=project_id,
role__gt=10,
)
if issue_id:
issue_created_by = (
Issue.objects.filter(id=issue_id)
.values_list("created_by_id", flat=True)
.first()
)
# Add condition to include `issue_created_by` in the query
filters = Q(member_id=issue_created_by) | base_filters
else:
filters = base_filters
# Query to fetch users
users = (
ProjectMember.objects.filter(filters)
ProjectMember.objects.filter(
q,
is_active=True,
workspace__slug=slug,
member__is_bot=False,
project_id=project_id,
)
.annotate(
member__avatar_url=Case(
When(
@@ -318,14 +304,35 @@ class SearchEndpoint(BaseAPIView):
)
)
.order_by("-created_at")
.values(
"member__avatar_url",
"member__display_name",
"member__id",
)[:count]
)
response_data["user_mention"] = list(users)
if issue_id:
issue_created_by = (
Issue.objects.filter(id=issue_id)
.values_list("created_by_id", flat=True)
.first()
)
users = (
users.filter(Q(role__gt=10) | Q(member_id=issue_created_by))
.distinct()
.values(
"member__avatar_url",
"member__display_name",
"member__id",
)
)
else:
users = (
users.filter(Q(role__gt=10))
.distinct()
.values(
"member__avatar_url",
"member__display_name",
"member__id",
)
)
response_data["user_mention"] = list(users[:count])
elif query_type == "project":
fields = ["name", "identifier"]

View File

@@ -79,5 +79,6 @@ export type TSearchEntityRequestPayload = {
project_id?: string;
query_type: TSearchEntities[];
query: string;
issue_id?: string;
team_id?: string;
};

View File

@@ -16,6 +16,7 @@ import { getFileURL } from "@/helpers/file.helper";
// hooks
import { useUser, useMember } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
import { EUserPermissions } from "@/plane-web/constants/user-permissions";
interface Props {
className?: string;
@@ -36,8 +37,7 @@ export const MemberOptions: React.FC<Props> = observer((props: Props) => {
// store hooks
const { workspaceSlug } = useParams();
const {
getUserDetails,
project: { getProjectMemberIds, fetchProjectMembers },
project: { getProjectMemberIds, fetchProjectMembers, getProjectMemberDetails },
workspace: { workspaceMemberIds },
} = useMember();
const { data: currentUser } = useUser();
@@ -59,7 +59,7 @@ export const MemberOptions: React.FC<Props> = observer((props: Props) => {
if (isOpen) {
onOpen();
if (!isMobile) {
inputRef.current && inputRef.current.focus();
if (inputRef.current) inputRef.current.focus();
}
}
}, [isOpen, isMobile]);
@@ -76,23 +76,30 @@ export const MemberOptions: React.FC<Props> = observer((props: Props) => {
}
};
const options = memberIds?.map((userId) => {
const userDetails = getUserDetails(userId);
return {
value: userId,
query: `${userDetails?.display_name} ${userDetails?.first_name} ${userDetails?.last_name}`,
content: (
<div className="flex items-center gap-2">
<Avatar name={userDetails?.display_name} src={getFileURL(userDetails?.avatar_url ?? "")} />
<span className="flex-grow truncate">{currentUser?.id === userId ? "You" : userDetails?.display_name}</span>
</div>
),
};
});
const options = memberIds
?.map((userId) => {
const userData = getProjectMemberDetails(userId);
const memeberDetails = userData?.member;
/**Restricting guest users from being shown in the dropdown */
const isGuest = (userData?.role ?? EUserPermissions.GUEST) === EUserPermissions.GUEST;
if (isGuest) return;
return {
value: userId,
query: `${memeberDetails?.display_name} ${memeberDetails?.first_name} ${memeberDetails?.last_name}`,
content: (
<div className="flex items-center gap-2">
<Avatar name={memeberDetails?.display_name} src={getFileURL(memeberDetails?.avatar_url ?? "")} />
<span className="flex-grow truncate">
{currentUser?.id === userId ? "You" : memeberDetails?.display_name}
</span>
</div>
),
};
})
.filter((option) => option !== undefined);
const filteredOptions =
query === "" ? options : options?.filter((o) => o.query.toLowerCase().includes(query.toLowerCase()));
query === "" ? options : options?.filter((option) => option?.query.toLowerCase().includes(query.toLowerCase()));
return createPortal(
<Combobox.Options data-prevent-outside-click static>
@@ -125,8 +132,8 @@ export const MemberOptions: React.FC<Props> = observer((props: Props) => {
filteredOptions.length > 0 ? (
filteredOptions.map((option) => (
<Combobox.Option
key={option.value}
value={option.value}
key={option?.value}
value={option?.value}
className={({ active, selected }) =>
`flex w-full cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 ${
active ? "bg-custom-background-80" : ""
@@ -135,7 +142,7 @@ export const MemberOptions: React.FC<Props> = observer((props: Props) => {
>
{({ selected }) => (
<>
<span className="flex-grow truncate">{option.content}</span>
<span className="flex-grow truncate">{option?.content}</span>
{selected && <Check className="h-3.5 w-3.5 flex-shrink-0" />}
</>
)}

View File

@@ -30,6 +30,7 @@ interface LiteTextEditorWrapperProps
isSubmitting?: boolean;
showToolbarInitially?: boolean;
uploadFile: (file: File) => Promise<string>;
issueId?: string;
}
export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapperProps>((props, ref) => {
@@ -46,6 +47,7 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
showToolbarInitially = true,
placeholder = "Add comment...",
uploadFile,
issueId,
...rest
} = props;
// states
@@ -58,6 +60,7 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
await workspaceService.searchEntity(workspaceSlug?.toString() ?? "", {
...payload,
project_id: projectId?.toString() ?? "",
issue_id: issueId,
}),
});
// file size

View File

@@ -125,6 +125,7 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
await workspaceService.searchEntity(workspaceSlug?.toString() ?? "", {
...payload,
project_id: projectId?.toString() ?? "",
issue_id: issueId,
})
}
containerClassName={containerClassName}

View File

@@ -46,6 +46,7 @@ export const IssueActivityCommentRoot: FC<TIssueActivityCommentRoot> = observer(
projectId={projectId}
key={activityComment.id}
workspaceSlug={workspaceSlug}
issueId={issueId}
commentId={activityComment.id}
activityOperations={activityOperations}
ends={index === 0 ? "top" : index === filteredActivityComments.length - 1 ? "bottom" : undefined}

View File

@@ -28,12 +28,14 @@ type TIssueCommentCard = {
ends: "top" | "bottom" | undefined;
showAccessSpecifier?: boolean;
disabled?: boolean;
issueId?: string;
};
export const IssueCommentCard: FC<TIssueCommentCard> = observer((props) => {
const {
workspaceSlug,
projectId,
issueId,
commentId,
activityOperations,
ends,
@@ -144,6 +146,7 @@ export const IssueCommentCard: FC<TIssueCommentCard> = observer((props) => {
<LiteTextEditor
workspaceId={workspaceId}
projectId={projectId}
issueId={issueId}
workspaceSlug={workspaceSlug}
ref={editorRef}
id={comment.id}

View File

@@ -96,6 +96,7 @@ export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
value={"<p></p>"}
projectId={projectId}
workspaceSlug={workspaceSlug}
issueId={issueId}
onEnterKeyPress={(e) => {
if (!isEmpty && !isSubmitting) {
handleSubmit(onSubmit)(e);