diff --git a/apiserver/plane/app/views/issue/base.py b/apiserver/plane/app/views/issue/base.py index 9b97096d17..b98464c1e1 100644 --- a/apiserver/plane/app/views/issue/base.py +++ b/apiserver/plane/app/views/issue/base.py @@ -481,7 +481,38 @@ class IssueViewSet(BaseViewSet): return Response(serializer.data, status=status.HTTP_200_OK) def partial_update(self, request, slug, project_id, pk=None): - issue = self.get_queryset().filter(pk=pk).first() + issue = ( + self.get_queryset() + .annotate( + label_ids=Coalesce( + ArrayAgg( + "labels__id", + distinct=True, + filter=~Q(labels__id__isnull=True), + ), + Value([], output_field=ArrayField(UUIDField())), + ), + assignee_ids=Coalesce( + ArrayAgg( + "assignees__id", + distinct=True, + filter=~Q(assignees__id__isnull=True) + & Q(assignees__member_project__is_active=True), + ), + Value([], output_field=ArrayField(UUIDField())), + ), + module_ids=Coalesce( + ArrayAgg( + "issue_module__module_id", + distinct=True, + filter=~Q(issue_module__module_id__isnull=True), + ), + Value([], output_field=ArrayField(UUIDField())), + ), + ) + .filter(pk=pk) + .first() + ) if not issue: return Response( diff --git a/apiserver/plane/bgtasks/page_version_task.py b/apiserver/plane/bgtasks/page_version_task.py index e29d28a85b..d8be197432 100644 --- a/apiserver/plane/bgtasks/page_version_task.py +++ b/apiserver/plane/bgtasks/page_version_task.py @@ -30,7 +30,7 @@ def page_version( workspace_id=page.workspace_id, description_html=page.description_html, description_binary=page.description_binary, - ownned_by_id=user_id, + owned_by_id=user_id, last_saved_at=page.updated_at, ) diff --git a/packages/types/src/issues/issue.d.ts b/packages/types/src/issues/issue.d.ts index f6cab799e2..7ab1e74cec 100644 --- a/packages/types/src/issues/issue.d.ts +++ b/packages/types/src/issues/issue.d.ts @@ -97,3 +97,9 @@ export type TBulkOperationsPayload = { issue_ids: string[]; properties: Partial; }; + +export type TIssueDetailWidget = + | "sub-issues" + | "relations" + | "links" + | "attachments"; diff --git a/packages/ui/src/collapsible/collapsible-button.tsx b/packages/ui/src/collapsible/collapsible-button.tsx index 92b7ef90ac..a56a724b4c 100644 --- a/packages/ui/src/collapsible/collapsible-button.tsx +++ b/packages/ui/src/collapsible/collapsible-button.tsx @@ -13,7 +13,7 @@ type Props = { export const CollapsibleButton: FC = (props) => { const { isOpen, title, hideChevron = false, indicatorElement, actionItemElement } = props; return ( -
+
{!hideChevron && ( diff --git a/space/core/components/views/auth.tsx b/space/core/components/views/auth.tsx index fb68d8fbab..2c5a8a2f4d 100644 --- a/space/core/components/views/auth.tsx +++ b/space/core/components/views/auth.tsx @@ -30,7 +30,7 @@ export const AuthView = observer(() => { />
-
+
Plane logo diff --git a/web/app/[workspaceSlug]/(projects)/notifications/page.tsx b/web/app/[workspaceSlug]/(projects)/notifications/page.tsx index 5fa81a8e1e..c6003c2590 100644 --- a/web/app/[workspaceSlug]/(projects)/notifications/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/notifications/page.tsx @@ -6,9 +6,11 @@ import useSWR from "swr"; // components import { LogoSpinner } from "@/components/common"; import { PageHead } from "@/components/core"; +import { EmptyState } from "@/components/empty-state"; import { InboxContentRoot } from "@/components/inbox"; import { IssuePeekOverview } from "@/components/issues"; // constants +import { EmptyStateType } from "@/constants/empty-state"; import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification"; // hooks import { useIssueDetail, useUser, useWorkspace, useWorkspaceNotifications } from "@/hooks/store"; @@ -62,36 +64,44 @@ const WorkspaceDashboardPage = observer(() => { setCurrentSelectedNotificationId(undefined); setPeekIssue(undefined); }, - [] + [setCurrentSelectedNotificationId, setPeekIssue] ); return ( <>
- {is_inbox_issue === true && workspace_slug && project_id && issue_id ? ( + {!currentSelectedNotificationId ? ( +
+ +
+ ) : ( <> - {projectMemberInfoLoader ? ( -
- -
+ {is_inbox_issue === true && workspace_slug && project_id && issue_id ? ( + <> + {projectMemberInfoLoader ? ( +
+ +
+ ) : ( + {}} + isMobileSidebar={false} + workspaceSlug={workspace_slug} + projectId={project_id} + inboxIssueId={issue_id} + isNotificationEmbed + embedRemoveCurrentNotification={() => setCurrentSelectedNotificationId(undefined)} + /> + )} + ) : ( - {}} - isMobileSidebar={false} - workspaceSlug={workspace_slug} - projectId={project_id} - inboxIssueId={issue_id} - isNotificationEmbed + setCurrentSelectedNotificationId(undefined)} /> )} - ) : ( - setCurrentSelectedNotificationId(undefined)} - /> )}
diff --git a/web/app/accounts/forgot-password/page.tsx b/web/app/accounts/forgot-password/page.tsx index 0e203a1f88..3e86e8eff5 100644 --- a/web/app/accounts/forgot-password/page.tsx +++ b/web/app/accounts/forgot-password/page.tsx @@ -104,7 +104,7 @@ export default function ForgotPasswordPage() { />
-
+
Plane logo diff --git a/web/app/accounts/reset-password/page.tsx b/web/app/accounts/reset-password/page.tsx index 43f001abe9..4d5303b985 100644 --- a/web/app/accounts/reset-password/page.tsx +++ b/web/app/accounts/reset-password/page.tsx @@ -116,7 +116,7 @@ export default function ResetPasswordPage() { />
-
+
Plane logo diff --git a/web/app/accounts/set-password/page.tsx b/web/app/accounts/set-password/page.tsx index e74b506e60..df1b5d5675 100644 --- a/web/app/accounts/set-password/page.tsx +++ b/web/app/accounts/set-password/page.tsx @@ -118,7 +118,7 @@ const SetPasswordPage = observer(() => { />
-
+
Plane logo diff --git a/web/app/page.tsx b/web/app/page.tsx index 4982f40825..63ef855cab 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -46,7 +46,7 @@ const HomePage = observer(() => { />
-
+
Plane logo diff --git a/web/app/sign-up/page.tsx b/web/app/sign-up/page.tsx index 8bd2e87991..f08ccbae7b 100644 --- a/web/app/sign-up/page.tsx +++ b/web/app/sign-up/page.tsx @@ -41,7 +41,7 @@ const SignInPage = observer(() => { />
-
+
Plane logo diff --git a/web/core/components/analytics/custom-analytics/select/project.tsx b/web/core/components/analytics/custom-analytics/select/project.tsx index 5eb209d0e1..1d34ed7b92 100644 --- a/web/core/components/analytics/custom-analytics/select/project.tsx +++ b/web/core/components/analytics/custom-analytics/select/project.tsx @@ -23,7 +23,7 @@ export const SelectProject: React.FC = observer((props) => { value: projectDetails?.id, query: `${projectDetails?.name} ${projectDetails?.identifier}`, content: ( -
+
{projectDetails?.identifier} {projectDetails?.name}
@@ -44,6 +44,7 @@ export const SelectProject: React.FC = observer((props) => { .join(", ") : "All projects" } + optionsClassName={"w-48"} multiple /> ); diff --git a/web/core/components/issues/issue-detail-widgets/attachments/quick-action-button.tsx b/web/core/components/issues/issue-detail-widgets/attachments/quick-action-button.tsx index fe2cfde308..2d7a5de86f 100644 --- a/web/core/components/issues/issue-detail-widgets/attachments/quick-action-button.tsx +++ b/web/core/components/issues/issue-detail-widgets/attachments/quick-action-button.tsx @@ -8,7 +8,7 @@ import { MAX_FILE_SIZE } from "@/constants/common"; // helper import { generateFileName } from "@/helpers/attachment.helper"; // hooks -import { useInstance } from "@/hooks/store"; +import { useInstance, useIssueDetail } from "@/hooks/store"; import { useAttachmentOperations } from "./helper"; @@ -22,11 +22,16 @@ type Props = { export const IssueAttachmentActionButton: FC = observer((props) => { const { workspaceSlug, projectId, issueId, customButton, disabled = false } = props; - // helper + // state const [isLoading, setIsLoading] = useState(false); + // store hooks const { config } = useInstance(); + const { setLastWidgetAction } = useIssueDetail(); + + // operations const handleAttachmentOperations = useAttachmentOperations(workspaceSlug, projectId, issueId); + // handlers const onDrop = useCallback( (acceptedFiles: File[]) => { const currentFile: File = acceptedFiles[0]; @@ -45,7 +50,10 @@ export const IssueAttachmentActionButton: FC = observer((props) => { }) ); setIsLoading(true); - handleAttachmentOperations.create(formData).finally(() => setIsLoading(false)); + handleAttachmentOperations.create(formData).finally(() => { + setLastWidgetAction("attachments"); + setIsLoading(false); + }); }, [handleAttachmentOperations, workspaceSlug] ); diff --git a/web/core/components/issues/issue-detail-widgets/attachments/root.tsx b/web/core/components/issues/issue-detail-widgets/attachments/root.tsx index 2c564f8149..3c7529cecc 100644 --- a/web/core/components/issues/issue-detail-widgets/attachments/root.tsx +++ b/web/core/components/issues/issue-detail-widgets/attachments/root.tsx @@ -1,11 +1,14 @@ "use client"; -import React, { FC, useState } from "react"; +import React, { FC } from "react"; +import { observer } from "mobx-react"; import { Collapsible } from "@plane/ui"; // components import { IssueAttachmentsCollapsibleContent, IssueAttachmentsCollapsibleTitle, } from "@/components/issues/issue-detail-widgets"; +// hooks +import { useIssueDetail } from "@/hooks/store"; type Props = { workspaceSlug: string; @@ -14,17 +17,21 @@ type Props = { disabled?: boolean; }; -export const AttachmentsCollapsible: FC = (props) => { +export const AttachmentsCollapsible: FC = observer((props) => { const { workspaceSlug, projectId, issueId, disabled = false } = props; - // state - const [isOpen, setIsOpen] = useState(false); + // store hooks + const { activeIssueDetailWidgets, toggleActiveIssueDetailWidget } = useIssueDetail(); + + // derived values + const isCollapsibleOpen = activeIssueDetailWidgets.includes("attachments"); + return ( setIsOpen((prev) => !prev)} + isOpen={isCollapsibleOpen} + onToggle={() => toggleActiveIssueDetailWidget("attachments")} title={ = (props) => { /> ); -}; +}); diff --git a/web/core/components/issues/issue-detail-widgets/links/quick-action-button.tsx b/web/core/components/issues/issue-detail-widgets/links/quick-action-button.tsx index 99c1ccf4d1..981005d78b 100644 --- a/web/core/components/issues/issue-detail-widgets/links/quick-action-button.tsx +++ b/web/core/components/issues/issue-detail-widgets/links/quick-action-button.tsx @@ -23,7 +23,7 @@ export const IssueLinksActionButton: FC = observer((props) => { const [isIssueLinkModal, setIsIssueLinkModal] = useState(false); // store hooks - const { toggleIssueLinkModal: toggleIssueLinkModalStore } = useIssueDetail(); + const { toggleIssueLinkModal: toggleIssueLinkModalStore, setLastWidgetAction } = useIssueDetail(); // helper const handleLinkOperations = useLinkOperations(workspaceSlug, projectId, issueId); @@ -43,11 +43,16 @@ export const IssueLinksActionButton: FC = observer((props) => { toggleIssueLinkModal(true); }; + const handleOnClose = () => { + toggleIssueLinkModal(false); + setLastWidgetAction("links"); + }; + return ( <>