From 7acd4ef1af709dd10384da88036077aa98f6c048 Mon Sep 17 00:00:00 2001 From: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com> Date: Sat, 24 Jun 2023 17:52:12 +0530 Subject: [PATCH 01/11] fix: issue duplication when ordering by labels and assignee (#1388) --- apiserver/plane/api/views/issue.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index dba7a7a2f..36b3411fc 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -15,6 +15,7 @@ from django.db.models import ( Value, CharField, When, + Max, ) from django.core.serializers.json import DjangoJSONEncoder from django.utils.decorators import method_decorator @@ -195,7 +196,7 @@ class IssueViewSet(BaseViewSet): output_field=CharField(), ) ).order_by("priority_order") - + # State Ordering elif order_by_param in [ "state__name", @@ -218,6 +219,22 @@ class IssueViewSet(BaseViewSet): output_field=CharField(), ) ).order_by("state_order") + # assignee and label ordering + elif order_by_param in [ + "labels__name", + "-labels__name", + "assignees__first_name", + "-assignees__first_name", + ]: + issue_queryset = issue_queryset.annotate( + max_values=Max( + order_by_param[1::] + if order_by_param.startswith("-") + else order_by_param + ) + ).order_by( + "-max_values" if order_by_param.startswith("-") else "max_values" + ) else: issue_queryset = issue_queryset.order_by(order_by_param) @@ -239,7 +256,7 @@ class IssueViewSet(BaseViewSet): return Response(issues, status=status.HTTP_200_OK) except Exception as e: - print(e) + capture_exception(e) return Response( {"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST, From fd30ea9a20a679d9b1608b51b325b0f16705f556 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Sat, 24 Jun 2023 18:09:06 +0530 Subject: [PATCH 02/11] feat: editable label option added in all view , fix: view page list and kanban view mutation fix, chore: code refactor (#1390) * feat: editable label select component added in spreadsheet view * feat: editable label select option added in all view, chore: code refactor * fix: view page list and kanban view mutation fix and sub issue mutation, chore: refactor partial update issue function * fix: build fix --- .../core/board-view/single-issue.tsx | 139 ++++++++-------- .../core/calendar-view/single-issue.tsx | 94 ++++++----- .../core/list-view/single-issue.tsx | 113 ++++++------- .../core/spreadsheet-view/single-issue.tsx | 100 +++++++----- .../components/issues/my-issues-list-item.tsx | 6 +- .../issues/view-select/assignee.tsx | 4 +- .../issues/view-select/due-date.tsx | 4 +- .../issues/view-select/estimate.tsx | 4 +- .../components/issues/view-select/index.ts | 1 + .../components/issues/view-select/label.tsx | 148 ++++++++++++++++++ .../issues/view-select/priority.tsx | 4 +- .../components/issues/view-select/state.tsx | 4 +- 12 files changed, 390 insertions(+), 231 deletions(-) create mode 100644 apps/app/components/issues/view-select/label.tsx diff --git a/apps/app/components/core/board-view/single-issue.tsx b/apps/app/components/core/board-view/single-issue.tsx index 5c0cc5102..cde1b2e38 100644 --- a/apps/app/components/core/board-view/single-issue.tsx +++ b/apps/app/components/core/board-view/single-issue.tsx @@ -23,6 +23,7 @@ import { ViewAssigneeSelect, ViewDueDateSelect, ViewEstimateSelect, + ViewLabelSelect, ViewPrioritySelect, ViewStateSelect, } from "components/issues"; @@ -44,7 +45,14 @@ import { LayerDiagonalIcon } from "components/icons"; import { handleIssuesMutation } from "constants/issue"; import { copyTextToClipboard, truncateText } from "helpers/string.helper"; // types -import { ICurrentUserResponse, IIssue, Properties, TIssueGroupByOptions, UserAuth } from "types"; +import { + ICurrentUserResponse, + IIssue, + ISubIssueResponse, + Properties, + TIssueGroupByOptions, + UserAuth, +} from "types"; // fetch-keys import { CYCLE_DETAILS, @@ -52,6 +60,8 @@ import { MODULE_DETAILS, MODULE_ISSUES_WITH_PARAMS, PROJECT_ISSUES_LIST_WITH_PARAMS, + SUB_ISSUES, + VIEW_ISSUES, } from "constants/fetch-keys"; type Props = { @@ -101,86 +111,68 @@ export const SingleBoardIssue: React.FC = ({ const { orderBy, params } = useIssuesView(); const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId } = router.query; + const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; const { setToastAlert } = useToast(); const partialUpdateIssue = useCallback( - (formData: Partial, issueId: string) => { + (formData: Partial, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - if (cycleId) - mutate< - | { - [key: string]: IIssue[]; - } - | IIssue[] - >( - CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params), - (prevData) => - handleIssuesMutation( - formData, - groupTitle ?? "", - selectedGroup, - index, - orderBy, - prevData - ), - false - ); - else if (moduleId) - mutate< - | { - [key: string]: IIssue[]; - } - | IIssue[] - >( - MODULE_ISSUES_WITH_PARAMS(moduleId as string), - (prevData) => - handleIssuesMutation( - formData, - groupTitle ?? "", - selectedGroup, - index, - orderBy, - prevData - ), - false - ); - else { - mutate< - | { - [key: string]: IIssue[]; - } - | IIssue[] - >( - PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params), + const fetchKey = cycleId + ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params) + : moduleId + ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) + : viewId + ? VIEW_ISSUES(viewId.toString(), params) + : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params); + + if (issue.parent) { + mutate( + SUB_ISSUES(issue.parent.toString()), (prevData) => { if (!prevData) return prevData; - return handleIssuesMutation( + return { + ...prevData, + sub_issues: (prevData.sub_issues ?? []).map((i) => { + if (i.id === issue.id) { + return { + ...i, + ...formData, + }; + } + return i; + }), + }; + }, + false + ); + } else { + mutate< + | { + [key: string]: IIssue[]; + } + | IIssue[] + >( + fetchKey, + (prevData) => + handleIssuesMutation( formData, groupTitle ?? "", selectedGroup, index, orderBy, prevData - ); - }, + ), false ); } issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user) + .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData, user) .then(() => { - if (cycleId) { - mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); - mutate(CYCLE_DETAILS(cycleId as string)); - } else if (moduleId) { - mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); - mutate(MODULE_DETAILS(moduleId as string)); - } else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params)); + mutate(fetchKey); }); }, [ @@ -188,6 +180,7 @@ export const SingleBoardIssue: React.FC = ({ projectId, cycleId, moduleId, + viewId, groupTitle, index, selectedGroup, @@ -370,23 +363,15 @@ export const SingleBoardIssue: React.FC = ({ isNotAllowed={isNotAllowed} /> )} - {properties.labels && issue.label_details.length > 0 && ( -
- {issue.label_details.map((label) => ( -
- - {label.name} -
- ))} -
+ {properties.labels && ( + )} {properties.assignee && ( = ({ const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string); const partialUpdateIssue = useCallback( - (formData: Partial, issueId: string) => { + (formData: Partial, issue: IIssue) => { if (!workspaceSlug || !projectId) return; const fetchKey = cycleId @@ -79,25 +81,54 @@ export const SingleCalendarIssue: React.FC = ({ ? VIEW_ISSUES(viewId.toString(), params) : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params); - mutate( - fetchKey, - (prevData) => - (prevData ?? []).map((p) => { - if (p.id === issueId) { - return { - ...p, - ...formData, - assignees: formData?.assignees_list ?? p.assignees, - }; - } + if (issue.parent) { + mutate( + SUB_ISSUES(issue.parent.toString()), + (prevData) => { + if (!prevData) return prevData; - return p; - }), - false - ); + return { + ...prevData, + sub_issues: (prevData.sub_issues ?? []).map((i) => { + if (i.id === issue.id) { + return { + ...i, + ...formData, + }; + } + return i; + }), + }; + }, + false + ); + } else { + mutate( + fetchKey, + (prevData) => + (prevData ?? []).map((p) => { + if (p.id === issue.id) { + return { + ...p, + ...formData, + assignees: formData?.assignees_list ?? p.assignees, + }; + } + + return p; + }), + false + ); + } issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, formData, user) + .patchIssue( + workspaceSlug as string, + projectId as string, + issue.id as string, + formData, + user + ) .then(() => { mutate(fetchKey); }) @@ -207,25 +238,14 @@ export const SingleCalendarIssue: React.FC = ({ isNotAllowed={isNotAllowed} /> )} - {properties.labels && issue.label_details.length > 0 ? ( -
- {issue.label_details.map((label) => ( - - - {label.name} - - ))} -
- ) : ( - "" + {properties.labels && ( + )} {properties.assignee && ( = ({ const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 }); const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId } = router.query; + const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; const { setToastAlert } = useToast(); const { groupByProperty: selectedGroup, orderBy, params } = useIssueView(); const partialUpdateIssue = useCallback( - (formData: Partial, issueId: string) => { + (formData: Partial, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - if (cycleId) + const fetchKey = cycleId + ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params) + : moduleId + ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) + : viewId + ? VIEW_ISSUES(viewId.toString(), params) + : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params); + + if (issue.parent) { + mutate( + SUB_ISSUES(issue.parent.toString()), + (prevData) => { + if (!prevData) return prevData; + + return { + ...prevData, + sub_issues: (prevData.sub_issues ?? []).map((i) => { + if (i.id === issue.id) { + return { + ...i, + ...formData, + }; + } + return i; + }), + }; + }, + false + ); + } else { mutate< | { [key: string]: IIssue[]; } | IIssue[] >( - CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params), + fetchKey, (prevData) => handleIssuesMutation( formData, @@ -109,49 +141,12 @@ export const SingleListIssue: React.FC = ({ ), false ); - - if (moduleId) - mutate< - | { - [key: string]: IIssue[]; - } - | IIssue[] - >( - MODULE_ISSUES_WITH_PARAMS(moduleId as string, params), - (prevData) => - handleIssuesMutation( - formData, - groupTitle ?? "", - selectedGroup, - index, - orderBy, - prevData - ), - false - ); - - mutate< - | { - [key: string]: IIssue[]; - } - | IIssue[] - >( - PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params), - (prevData) => - handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, orderBy, prevData), - false - ); + } issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user) + .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData, user) .then(() => { - if (cycleId) { - mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); - mutate(CYCLE_DETAILS(cycleId as string)); - } else if (moduleId) { - mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); - mutate(MODULE_DETAILS(moduleId as string)); - } else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params)); + mutate(fetchKey); }); }, [ @@ -159,6 +154,7 @@ export const SingleListIssue: React.FC = ({ projectId, cycleId, moduleId, + viewId, groupTitle, index, selectedGroup, @@ -275,25 +271,14 @@ export const SingleListIssue: React.FC = ({ isNotAllowed={isNotAllowed} /> )} - {properties.labels && issue.label_details.length > 0 ? ( -
- {issue.label_details.map((label) => ( - - - {label.name} - - ))} -
- ) : ( - "" + {properties.labels && ( + )} {properties.assignee && ( = ({ const { setToastAlert } = useToast(); const partialUpdateIssue = useCallback( - (formData: Partial, issueId: string) => { + (formData: Partial, issue: IIssue) => { if (!workspaceSlug || !projectId) return; const fetchKey = cycleId @@ -78,23 +80,52 @@ export const SingleSpreadsheetIssue: React.FC = ({ ? VIEW_ISSUES(viewId.toString(), params) : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params); - mutate( - fetchKey, - (prevData) => - (prevData ?? []).map((p) => { - if (p.id === issueId) { - return { - ...p, - ...formData, - }; - } - return p; - }), - false - ); + if (issue.parent) { + mutate( + SUB_ISSUES(issue.parent.toString()), + (prevData) => { + if (!prevData) return prevData; + + return { + ...prevData, + sub_issues: (prevData.sub_issues ?? []).map((i) => { + if (i.id === issue.id) { + return { + ...i, + ...formData, + }; + } + return i; + }), + }; + }, + false + ); + } else { + mutate( + fetchKey, + (prevData) => + (prevData ?? []).map((p) => { + if (p.id === issue.id) { + return { + ...p, + ...formData, + }; + } + return p; + }), + false + ); + } issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, formData, user) + .patchIssue( + workspaceSlug as string, + projectId as string, + issue.id as string, + formData, + user + ) .then(() => { mutate(fetchKey); }) @@ -191,30 +222,19 @@ export const SingleSpreadsheetIssue: React.FC = ({ /> )} - {properties.labels ? ( - issue.label_details.length > 0 ? ( -
- {issue.label_details.slice(0, 4).map((label, index) => ( -
- -
- ))} - {issue.label_details.length > 4 ? +{issue.label_details.length - 4} : null} -
- ) : ( -
- No Labels -
- ) - ) : ( - "" + {properties.labels && ( +
+ +
)} + {properties.due_date && (
= ({ issue, properties, projectId const { setToastAlert } = useToast(); const partialUpdateIssue = useCallback( - (formData: Partial, issueId: string) => { + (formData: Partial, issue: IIssue) => { if (!workspaceSlug) return; mutate( USER_ISSUE(workspaceSlug as string), (prevData) => prevData?.map((p) => { - if (p.id === issueId) return { ...p, ...formData }; + if (p.id === issue.id) return { ...p, ...formData }; return p; }), @@ -59,7 +59,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId ); issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user) + .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData, user) .then((res) => { mutate(USER_ISSUE(workspaceSlug as string)); }) diff --git a/apps/app/components/issues/view-select/assignee.tsx b/apps/app/components/issues/view-select/assignee.tsx index 1dbfbabba..8bfa797fe 100644 --- a/apps/app/components/issues/view-select/assignee.tsx +++ b/apps/app/components/issues/view-select/assignee.tsx @@ -18,7 +18,7 @@ import { PROJECT_MEMBERS } from "constants/fetch-keys"; type Props = { issue: IIssue; - partialUpdateIssue: (formData: Partial, issueId: string) => void; + partialUpdateIssue: (formData: Partial, issue: IIssue) => void; position?: "left" | "right"; selfPositioned?: boolean; tooltipPosition?: "left" | "right"; @@ -108,7 +108,7 @@ export const ViewAssigneeSelect: React.FC = ({ if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); else newData.push(data); - partialUpdateIssue({ assignees_list: data }, issue.id); + partialUpdateIssue({ assignees_list: data }, issue); trackEventServices.trackIssuePartialPropertyUpdateEvent( { diff --git a/apps/app/components/issues/view-select/due-date.tsx b/apps/app/components/issues/view-select/due-date.tsx index f74b62689..163816a99 100644 --- a/apps/app/components/issues/view-select/due-date.tsx +++ b/apps/app/components/issues/view-select/due-date.tsx @@ -11,7 +11,7 @@ import { ICurrentUserResponse, IIssue } from "types"; type Props = { issue: IIssue; - partialUpdateIssue: (formData: Partial, issueId: string) => void; + partialUpdateIssue: (formData: Partial, issue: IIssue) => void; noBorder?: boolean; user: ICurrentUserResponse | undefined; isNotAllowed: boolean; @@ -48,7 +48,7 @@ export const ViewDueDateSelect: React.FC = ({ priority: issue.priority, state: issue.state, }, - issue.id + issue ); trackEventServices.trackIssuePartialPropertyUpdateEvent( { diff --git a/apps/app/components/issues/view-select/estimate.tsx b/apps/app/components/issues/view-select/estimate.tsx index 02a3e0710..0f932405f 100644 --- a/apps/app/components/issues/view-select/estimate.tsx +++ b/apps/app/components/issues/view-select/estimate.tsx @@ -15,7 +15,7 @@ import { ICurrentUserResponse, IIssue } from "types"; type Props = { issue: IIssue; - partialUpdateIssue: (formData: Partial, issueId: string) => void; + partialUpdateIssue: (formData: Partial, issue: IIssue) => void; position?: "left" | "right"; selfPositioned?: boolean; customButton?: boolean; @@ -54,7 +54,7 @@ export const ViewEstimateSelect: React.FC = ({ { - partialUpdateIssue({ estimate_point: val }, issue.id); + partialUpdateIssue({ estimate_point: val }, issue); trackEventServices.trackIssuePartialPropertyUpdateEvent( { workspaceSlug, diff --git a/apps/app/components/issues/view-select/index.ts b/apps/app/components/issues/view-select/index.ts index 55ecfcbdb..a05cf61b6 100644 --- a/apps/app/components/issues/view-select/index.ts +++ b/apps/app/components/issues/view-select/index.ts @@ -3,3 +3,4 @@ export * from "./due-date"; export * from "./estimate"; export * from "./priority"; export * from "./state"; +export * from "./label"; diff --git a/apps/app/components/issues/view-select/label.tsx b/apps/app/components/issues/view-select/label.tsx new file mode 100644 index 000000000..33df5cf9f --- /dev/null +++ b/apps/app/components/issues/view-select/label.tsx @@ -0,0 +1,148 @@ +import React, { useState } from "react"; + +import { useRouter } from "next/router"; + +import useSWR from "swr"; + +// services +import issuesService from "services/issues.service"; +// component +import { CreateLabelModal } from "components/labels"; +// ui +import { CustomSearchSelect, Tooltip } from "components/ui"; +// icons +import { PlusIcon, TagIcon } from "@heroicons/react/24/outline"; +// types +import { ICurrentUserResponse, IIssue, IIssueLabels } from "types"; +// fetch-keys +import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; + +type Props = { + issue: IIssue; + partialUpdateIssue: (formData: Partial, issue: IIssue) => void; + position?: "left" | "right"; + selfPositioned?: boolean; + tooltipPosition?: "left" | "right"; + customButton?: boolean; + user: ICurrentUserResponse | undefined; + isNotAllowed: boolean; +}; + +export const ViewLabelSelect: React.FC = ({ + issue, + partialUpdateIssue, + position = "left", + selfPositioned = false, + tooltipPosition = "right", + user, + isNotAllowed, + customButton = false, +}) => { + const [labelModal, setLabelModal] = useState(false); + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { data: issueLabels } = useSWR( + projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null, + workspaceSlug && projectId + ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) + : null + ); + + const options = issueLabels?.map((label) => ({ + value: label.id, + query: label.name, + content: ( +
+ + {label.name} +
+ ), + })); + + const labelsLabel = ( + 0 + ? issue.label_details.map((label) => label.name ?? "").join(", ") + : "No Label" + } + > +
+ {issue.label_details.length > 0 ? ( + <> + {issue.label_details.slice(0, 4).map((label, index) => ( +
+ +
+ ))} + {issue.label_details.length > 4 ? +{issue.label_details.length - 4} : null} + + ) : ( + <> + + + )} +
+
+ ); + + const footerOption = ( + + ); + + return ( + <> + {projectId && ( + setLabelModal(false)} + projectId={projectId.toString()} + user={user} + /> + )} + { + partialUpdateIssue({ labels_list: data }, issue); + }} + options={options} + {...(customButton ? { customButton: labelsLabel } : { label: labelsLabel })} + multiple + noChevron + position={position} + disabled={isNotAllowed} + selfPositioned={selfPositioned} + footerOption={footerOption} + dropdownWidth="w-full min-w-[12rem]" + /> + + ); +}; diff --git a/apps/app/components/issues/view-select/priority.tsx b/apps/app/components/issues/view-select/priority.tsx index 499546931..0afd2dd98 100644 --- a/apps/app/components/issues/view-select/priority.tsx +++ b/apps/app/components/issues/view-select/priority.tsx @@ -17,7 +17,7 @@ import { capitalizeFirstLetter } from "helpers/string.helper"; type Props = { issue: IIssue; - partialUpdateIssue: (formData: Partial, issueId: string) => void; + partialUpdateIssue: (formData: Partial, issue: IIssue) => void; position?: "left" | "right"; selfPositioned?: boolean; noBorder?: boolean; @@ -41,7 +41,7 @@ export const ViewPrioritySelect: React.FC = ({ { - partialUpdateIssue({ priority: data }, issue.id); + partialUpdateIssue({ priority: data }, issue); trackEventServices.trackIssuePartialPropertyUpdateEvent( { workspaceSlug, diff --git a/apps/app/components/issues/view-select/state.tsx b/apps/app/components/issues/view-select/state.tsx index c097c7326..5ec0f71c7 100644 --- a/apps/app/components/issues/view-select/state.tsx +++ b/apps/app/components/issues/view-select/state.tsx @@ -19,7 +19,7 @@ import { STATES_LIST } from "constants/fetch-keys"; type Props = { issue: IIssue; - partialUpdateIssue: (formData: Partial, issueId: string) => void; + partialUpdateIssue: (formData: Partial, issue: IIssue) => void; position?: "left" | "right"; selfPositioned?: boolean; customButton?: boolean; @@ -83,7 +83,7 @@ export const ViewStateSelect: React.FC = ({ priority: issue.priority, target_date: issue.target_date, }, - issue.id + issue ); trackEventServices.trackIssuePartialPropertyUpdateEvent( { From 06ce89a03ab5f98623659fef4ab4086788129926 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Sat, 24 Jun 2023 18:12:11 +0530 Subject: [PATCH 03/11] fix: sidebar toggle button on workspace dashboard (#1389) --- apps/app/layouts/app-layout/app-header.tsx | 9 +++++++-- .../auth-layout/project-authorization-wrapper.tsx | 15 +++++++-------- .../workspace-authorization-wrapper.tsx | 15 +++++++-------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/app/layouts/app-layout/app-header.tsx b/apps/app/layouts/app-layout/app-header.tsx index 95f998dec..1f99e044e 100644 --- a/apps/app/layouts/app-layout/app-header.tsx +++ b/apps/app/layouts/app-layout/app-header.tsx @@ -6,10 +6,15 @@ type Props = { left?: JSX.Element; right?: JSX.Element; setToggleSidebar: React.Dispatch>; + noHeader: boolean; }; -const Header: React.FC = ({ breadcrumbs, left, right, setToggleSidebar }) => ( -
+const Header: React.FC = ({ breadcrumbs, left, right, setToggleSidebar, noHeader }) => ( +
+ +
) : ( diff --git a/apps/app/components/ui/multi-level-dropdown.tsx b/apps/app/components/ui/multi-level-dropdown.tsx index b0997972f..ee096774f 100644 --- a/apps/app/components/ui/multi-level-dropdown.tsx +++ b/apps/app/components/ui/multi-level-dropdown.tsx @@ -3,7 +3,7 @@ import { Fragment, useState } from "react"; // headless ui import { Menu, Transition } from "@headlessui/react"; // icons -import { ChevronDownIcon } from "@heroicons/react/24/outline"; +import { CheckIcon, ChevronDownIcon } from "@heroicons/react/24/outline"; import { ChevronRightIcon, ChevronLeftIcon } from "@heroicons/react/20/solid"; type MultiLevelDropdownProps = { @@ -127,9 +127,14 @@ export const MultiLevelDropdown: React.FC = ({ }} className={`${ child.selected ? "bg-brand-surface-2" : "" - } flex w-full items-center whitespace-nowrap break-words rounded px-1 py-1.5 text-left capitalize text-brand-secondary hover:bg-brand-surface-2`} + } flex w-full items-center justify-between whitespace-nowrap break-words rounded px-1 py-1.5 text-left capitalize text-brand-secondary hover:bg-brand-surface-2`} > {child.label} + ))}
From c70fe91886682f04dcbe0e5b4fc6481f9e23616f Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:25:19 +0530 Subject: [PATCH 05/11] fix: create issue modal not working on workspace level (#1393) --- apps/app/components/issues/form.tsx | 8 ------- apps/app/components/issues/modal.tsx | 32 +++++++++++++++++----------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/apps/app/components/issues/form.tsx b/apps/app/components/issues/form.tsx index e7be252b4..8bf64e6ff 100644 --- a/apps/app/components/issues/form.tsx +++ b/apps/app/components/issues/form.tsx @@ -23,7 +23,6 @@ import { IssueStateSelect, } from "components/issues/select"; import { CreateStateModal } from "components/states"; -import { CreateUpdateCycleModal } from "components/cycles"; import { CreateLabelModal } from "components/labels"; // ui import { @@ -73,7 +72,6 @@ const defaultValues: Partial = { description_html: "

", estimate_point: null, state: "", - cycle: null, priority: null, assignees: [], assignees_list: [], @@ -122,7 +120,6 @@ export const IssueForm: FC = ({ }) => { // states const [mostSimilarIssue, setMostSimilarIssue] = useState(); - const [cycleModal, setCycleModal] = useState(false); const [stateModal, setStateModal] = useState(false); const [labelModal, setLabelModal] = useState(false); const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false); @@ -252,11 +249,6 @@ export const IssueForm: FC = ({ projectId={projectId} user={user} /> - setCycleModal(false)} - user={user} - /> setLabelModal(false)} diff --git a/apps/app/components/issues/modal.tsx b/apps/app/components/issues/modal.tsx index dd5262453..b83bbc480 100644 --- a/apps/app/components/issues/modal.tsx +++ b/apps/app/components/issues/modal.tsx @@ -82,12 +82,17 @@ export const CreateUpdateIssueModal: React.FC = ({ const { params: inboxParams } = useInboxView(); const { params: spreadsheetParams } = useSpreadsheetIssuesView(); - if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string }; - if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string }; - const { user } = useUser(); const { setToastAlert } = useToast(); + if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string }; + if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string }; + if (router.asPath.includes("my-issues")) + prePopulateData = { + ...prePopulateData, + assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""], + }; + const { data: issues } = useSWR( workspaceSlug && activeProject ? PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? "") @@ -121,7 +126,7 @@ export const CreateUpdateIssueModal: React.FC = ({ }, [handleClose]); const addIssueToCycle = async (issueId: string, cycleId: string) => { - if (!workspaceSlug || !projectId) return; + if (!workspaceSlug || !activeProject) return; await issuesService .addIssueToCycle( @@ -142,7 +147,7 @@ export const CreateUpdateIssueModal: React.FC = ({ }; const addIssueToModule = async (issueId: string, moduleId: string) => { - if (!workspaceSlug || !projectId) return; + if (!workspaceSlug || !activeProject) return; await modulesService .addIssuesToModule( @@ -163,7 +168,7 @@ export const CreateUpdateIssueModal: React.FC = ({ }; const addIssueToInbox = async (formData: Partial) => { - if (!workspaceSlug || !projectId || !inboxId) return; + if (!workspaceSlug || !activeProject || !inboxId) return; const payload = { issue: { @@ -178,7 +183,7 @@ export const CreateUpdateIssueModal: React.FC = ({ await inboxServices .createInboxIssue( workspaceSlug.toString(), - projectId.toString(), + activeProject.toString(), inboxId.toString(), payload, user @@ -191,7 +196,7 @@ export const CreateUpdateIssueModal: React.FC = ({ }); router.push( - `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}?inboxIssueId=${res.issue_inbox[0].id}` + `/${workspaceSlug}/projects/${activeProject}/inbox/${inboxId}?inboxIssueId=${res.issue_inbox[0].id}` ); mutate(INBOX_ISSUES(inboxId.toString(), inboxParams)); @@ -211,7 +216,7 @@ export const CreateUpdateIssueModal: React.FC = ({ ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), calendarParams) : viewId ? VIEW_ISSUES(viewId.toString(), calendarParams) - : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId?.toString() ?? "", calendarParams); + : PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? "", calendarParams); const spreadsheetFetchKey = cycleId ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), spreadsheetParams) @@ -219,7 +224,7 @@ export const CreateUpdateIssueModal: React.FC = ({ ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), spreadsheetParams) : viewId ? VIEW_ISSUES(viewId.toString(), spreadsheetParams) - : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId?.toString() ?? "", spreadsheetParams); + : PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? "", spreadsheetParams); const ganttFetchKey = cycleId ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString()) @@ -227,10 +232,10 @@ export const CreateUpdateIssueModal: React.FC = ({ ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString()) : viewId ? VIEW_ISSUES(viewId.toString(), viewGanttParams) - : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId?.toString() ?? ""); + : PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? ""); const createIssue = async (payload: Partial) => { - if (!workspaceSlug || !projectId) return; + if (!workspaceSlug || !activeProject) return; if (inboxId) await addIssueToInbox(payload); else @@ -252,7 +257,8 @@ export const CreateUpdateIssueModal: React.FC = ({ message: "Issue created successfully.", }); - if (payload.assignees_list?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE); + if (payload.assignees_list?.some((assignee) => assignee === user?.id)) + mutate(USER_ISSUE(workspaceSlug as string)); if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent)); }) From c89592d5872dbde6d0dd7c7c3335a011db896af5 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:26:38 +0530 Subject: [PATCH 06/11] chore: add tooltip to line graphs (#1392) * chore: workspace dashboard line graph tooltip * chore: burndown chart and analytics line graph tooltip added --- .../analytics/scope-and-demand/year-wise-issues.tsx | 8 ++++++++ apps/app/components/core/sidebar/progress-chart.tsx | 8 ++++++++ apps/app/components/workspace/completed-issues-graph.tsx | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx b/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx index 863eb664b..a37518cba 100644 --- a/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx +++ b/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx @@ -41,6 +41,14 @@ export const AnalyticsYearWiseIssues: React.FC = ({ defaultAnalytics }) = colors={(datum) => datum.color} curve="monotoneX" margin={{ top: 20 }} + enableSlices="x" + sliceTooltip={(datum) => ( +
+ {datum.slice.points[0].data.yFormatted} + issues closed in + {datum.slice.points[0].data.xFormatted} +
+ )} theme={{ background: "rgb(var(--color-bg-base))", }} diff --git a/apps/app/components/core/sidebar/progress-chart.tsx b/apps/app/components/core/sidebar/progress-chart.tsx index 8c7dba11e..e4a1ce4fb 100644 --- a/apps/app/components/core/sidebar/progress-chart.tsx +++ b/apps/app/components/core/sidebar/progress-chart.tsx @@ -117,6 +117,14 @@ const ProgressChart: React.FC = ({ distribution, startDate, endDate, tota colors={(datum) => datum.color ?? "#3F76FF"} customYAxisTickValues={[0, totalIssues]} gridXValues={chartData.map((item, index) => (index % 2 === 0 ? item.currentDate : ""))} + enableSlices="x" + sliceTooltip={(datum) => ( +
+ {datum.slice.points[0].data.yFormatted} + issues pending on + {datum.slice.points[0].data.xFormatted} +
+ )} theme={{ background: "transparent", axis: { diff --git a/apps/app/components/workspace/completed-issues-graph.tsx b/apps/app/components/workspace/completed-issues-graph.tsx index 9a1ada618..4c7e1edb6 100644 --- a/apps/app/components/workspace/completed-issues-graph.tsx +++ b/apps/app/components/workspace/completed-issues-graph.tsx @@ -60,6 +60,14 @@ export const CompletedIssuesGraph: React.FC = ({ month, issues, setMonth margin={{ top: 20, right: 20, bottom: 20, left: 20 }} customYAxisTickValues={data.map((item) => item.completed_count)} colors={(datum) => datum.color} + enableSlices="x" + sliceTooltip={(datum) => ( +
+ {datum.slice.points[0].data.yFormatted} + issues closed in + {datum.slice.points[0].data.xFormatted} +
+ )} theme={{ background: "rgb(var(--color-bg-base))", }} From ae051b28af55e1cc0396fe2a9e069b978166db77 Mon Sep 17 00:00:00 2001 From: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com> Date: Mon, 26 Jun 2023 17:59:17 +0530 Subject: [PATCH 07/11] fix: priority filtering (#1398) --- apiserver/plane/utils/issue_filters.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index f348f642a..74acb2044 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -1,7 +1,6 @@ from django.utils.timezone import make_aware from django.utils.dateparse import parse_datetime - def filter_state(params, filter, method): if method == "GET": states = params.get("state").split(",") @@ -26,12 +25,27 @@ def filter_estimate_point(params, filter, method): def filter_priority(params, filter, method): if method == "GET": - priorties = params.get("priority").split(",") - if len(priorties) and "" not in priorties: - filter["priority__in"] = priorties + priorities = params.get("priority").split(",") + if len(priorities) and "" not in priorities: + if len(priorities) == 1 and "null" in priorities: + filter["priority__isnull"] = True + elif len(priorities) > 1 and "null" in priorities: + filter["priority__isnull"] = True + filter["priority__in"] = [p for p in priorities if p != "null"] + else: + filter["priority__in"] = [p for p in priorities if p != "null"] + else: if params.get("priority", None) and len(params.get("priority")): - filter["priority__in"] = params.get("priority") + priorities = params.get("priority") + if len(priorities) == 1 and "null" in priorities: + filter["priority__isnull"] = True + elif len(priorities) > 1 and "null" in priorities: + filter["priority__isnull"] = True + filter["priority__in"] = [p for p in priorities if p != "null"] + else: + filter["priority__in"] = [p for p in priorities if p != "null"] + return filter From ad3411284bfa30c3bac8b484558c3beb04600f35 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:01:28 +0530 Subject: [PATCH 08/11] feat: add existing issue option added in spreadsheet view (#1397) --- apps/app/components/core/issues-view.tsx | 3 + .../spreadsheet-view/spreadsheet-view.tsx | 62 +++++++++++++++---- apps/app/components/ui/custom-menu.tsx | 4 +- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/apps/app/components/core/issues-view.tsx b/apps/app/components/core/issues-view.tsx index ffd49e506..7a8c8960f 100644 --- a/apps/app/components/core/issues-view.tsx +++ b/apps/app/components/core/issues-view.tsx @@ -572,8 +572,11 @@ export const IssuesView: React.FC = ({ /> ) : issueView === "spreadsheet" ? ( diff --git a/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx b/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx index 5a9d2aad5..eeef42750 100644 --- a/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx +++ b/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; // components import { SpreadsheetColumns, SpreadsheetIssues } from "components/core"; -import { Icon, Spinner } from "components/ui"; +import { CustomMenu, Icon, Spinner } from "components/ui"; // hooks import useIssuesProperties from "hooks/use-issue-properties"; import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; @@ -17,15 +17,21 @@ import { SPREADSHEET_COLUMN } from "constants/spreadsheet"; import { PlusIcon } from "@heroicons/react/24/outline"; type Props = { + type: "issue" | "cycle" | "module"; handleEditIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void; + openIssuesListModal?: (() => void) | null; + isCompleted?: boolean; user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; export const SpreadsheetView: React.FC = ({ + type, handleEditIssue, handleDeleteIssue, + openIssuesListModal, + isCompleted = false, user, userAuth, }) => { @@ -79,16 +85,50 @@ export const SpreadsheetView: React.FC = ({ className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-brand-surface-2 border-b border-brand-base w-full min-w-max" style={{ gridTemplateColumns }} > - + {type === "issue" ? ( + + ) : ( + !isCompleted && ( + + + Add Issue + + } + position="left" + menuItemsClassName="left-5 !w-36" + noBorder + > + { + const e = new KeyboardEvent("keydown", { key: "c" }); + document.dispatchEvent(e); + }} + > + Create new + + {openIssuesListModal && ( + + Add an existing issue + + )} + + ) + )}
) : ( diff --git a/apps/app/components/ui/custom-menu.tsx b/apps/app/components/ui/custom-menu.tsx index 006802b79..958453b28 100644 --- a/apps/app/components/ui/custom-menu.tsx +++ b/apps/app/components/ui/custom-menu.tsx @@ -19,6 +19,7 @@ type Props = { noChevron?: boolean; position?: "left" | "right"; verticalPosition?: "top" | "bottom"; + menuItemsClassName?: string; customButton?: JSX.Element; menuItemsWhiteBg?: boolean; }; @@ -44,6 +45,7 @@ const CustomMenu = ({ noChevron = false, position = "right", verticalPosition = "bottom", + menuItemsClassName = "", customButton, menuItemsWhiteBg = false, }: Props) => ( @@ -133,7 +135,7 @@ const CustomMenu = ({ menuItemsWhiteBg ? "border-brand-surface-1 bg-brand-base" : "border-brand-base bg-brand-surface-1" - }`} + } ${menuItemsClassName}`} >
{children}
From 3f22ccc52857971ea5a66a6ca57ac936725ccb9f Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:08:49 +0530 Subject: [PATCH 09/11] fix: filter none updated (#1399) --- apps/app/components/views/select-filters.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/app/components/views/select-filters.tsx b/apps/app/components/views/select-filters.tsx index 3351be667..164c4f58c 100644 --- a/apps/app/components/views/select-filters.tsx +++ b/apps/app/components/views/select-filters.tsx @@ -70,7 +70,7 @@ export const SelectFilters: React.FC = ({ value: PRIORITIES, children: [ ...PRIORITIES.map((priority) => ({ - id: priority ?? "none", + id: priority === null ? "null" : priority, label: (
{getPriorityIcon(priority)} {priority ?? "None"} @@ -78,9 +78,9 @@ export const SelectFilters: React.FC = ({ ), value: { key: "priority", - value: priority, + value: priority === null ? "null" : priority, }, - selected: filters?.priority?.includes(priority ?? "none"), + selected: filters?.priority?.includes(priority === null ? "null" : priority), })), ], }, From 5914240290577998320d88d134c1834a191e6ee1 Mon Sep 17 00:00:00 2001 From: "M. Palanikannan" <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:28:12 +0530 Subject: [PATCH 10/11] fix: cannot change the state if it's the only state in group (#1358) * fixed loohole with groups and added tooltip * muted text when dropdown disabled --- .../states/create-update-state-inline.tsx | 46 +++++++++++-------- apps/app/components/ui/custom-select.tsx | 2 +- .../projects/[projectId]/settings/states.tsx | 2 + 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/apps/app/components/states/create-update-state-inline.tsx b/apps/app/components/states/create-update-state-inline.tsx index 8a9d81968..94062878f 100644 --- a/apps/app/components/states/create-update-state-inline.tsx +++ b/apps/app/components/states/create-update-state-inline.tsx @@ -15,7 +15,7 @@ import stateService from "services/state.service"; // hooks import useToast from "hooks/use-toast"; // ui -import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui"; +import { CustomSelect, Input, PrimaryButton, SecondaryButton, Tooltip } from "components/ui"; // types import type { ICurrentUserResponse, IState, IStateResponse } from "types"; // fetch-keys @@ -28,6 +28,7 @@ type Props = { onClose: () => void; selectedGroup: StateGroup | null; user: ICurrentUserResponse | undefined; + groupLength: number; }; export type StateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled" | null; @@ -43,6 +44,7 @@ export const CreateUpdateStateInline: React.FC = ({ onClose, selectedGroup, user, + groupLength, }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -174,9 +176,8 @@ export const CreateUpdateStateInline: React.FC = ({ {({ open }) => ( <> {watch("color") && watch("color") !== "" && ( = ({ name="group" control={control} render={({ field: { value, onChange } }) => ( - k === value.toString()) - ? GROUP_CHOICES[value.toString() as keyof typeof GROUP_CHOICES] - : "Select group" - } - input - > - {Object.keys(GROUP_CHOICES).map((key) => ( - - {GROUP_CHOICES[key as keyof typeof GROUP_CHOICES]} - - ))} - + +
+ k === value.toString()) + ? GROUP_CHOICES[value.toString() as keyof typeof GROUP_CHOICES] + : "Select group" + } + input + > + {Object.keys(GROUP_CHOICES).map((key) => ( + + {GROUP_CHOICES[key as keyof typeof GROUP_CHOICES]} + + ))} + +
+
)} /> )} diff --git a/apps/app/components/ui/custom-select.tsx b/apps/app/components/ui/custom-select.tsx index 86196a63e..ec55bf29a 100644 --- a/apps/app/components/ui/custom-select.tsx +++ b/apps/app/components/ui/custom-select.tsx @@ -54,7 +54,7 @@ const CustomSelect = ({ ) : ( {
{key === activeGroup && ( { setActiveGroup(null); setSelectedState(null); @@ -128,6 +129,7 @@ const StatesSettings: NextPage = () => { setActiveGroup(null); setSelectedState(null); }} + groupLength={orderedStateGroups[key].length} data={ statesList?.find((state) => state.id === selectedState) ?? null } From b01afdf3006ba7700b1954f90136b69a09a74b2c Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Tue, 27 Jun 2023 15:49:19 +0530 Subject: [PATCH 11/11] fix: spreadsheet quick action menu fix (#1404) --- .../core/spreadsheet-view/single-issue.tsx | 116 ++++++++++++------ .../spreadsheet-view/spreadsheet-columns.tsx | 2 +- .../spreadsheet-view/spreadsheet-view.tsx | 2 +- apps/app/styles/globals.css | 5 + 4 files changed, 84 insertions(+), 41 deletions(-) diff --git a/apps/app/components/core/spreadsheet-view/single-issue.tsx b/apps/app/components/core/spreadsheet-view/single-issue.tsx index 8b66f90b7..2aabbef93 100644 --- a/apps/app/components/core/spreadsheet-view/single-issue.tsx +++ b/apps/app/components/core/spreadsheet-view/single-issue.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from "react"; +import React, { useCallback, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; @@ -14,9 +14,15 @@ import { ViewPrioritySelect, ViewStateSelect, } from "components/issues"; +import { Popover2 } from "@blueprintjs/popover2"; // icons -import { CustomMenu, Icon } from "components/ui"; -import { LinkIcon, PencilIcon, TrashIcon, XMarkIcon } from "@heroicons/react/24/outline"; +import { Icon } from "components/ui"; +import { + EllipsisHorizontalIcon, + LinkIcon, + PencilIcon, + TrashIcon, +} from "@heroicons/react/24/outline"; // hooks import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; import useToast from "hooks/use-toast"; @@ -60,6 +66,7 @@ export const SingleSpreadsheetIssue: React.FC = ({ userAuth, nestingLevel, }) => { + const [isOpen, setIsOpen] = useState(false); const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; @@ -163,27 +170,87 @@ export const SingleSpreadsheetIssue: React.FC = ({ className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-brand-surface-2 border-b border-brand-base w-full min-w-max" style={{ gridTemplateColumns }} > -
- -
+
+
+
{properties.key && ( - + {issue.project_detail?.identifier}-{issue.sequence_id} )} + {!isNotAllowed && ( +
+ setIsOpen(nextOpenState)} + content={ +
+ + + + + +
+ } + placement="bottom-start" + > + +
+
+ )}
-
+
{issue.sub_issues_count > 0 && ( )}
- +
+ {issue.name} @@ -261,35 +328,6 @@ export const SingleSpreadsheetIssue: React.FC = ({ />
)} -
- {!isNotAllowed && ( - - handleEditIssue(issue)}> -
- - Edit issue -
-
- handleDeleteIssue(issue)}> -
- - Delete issue -
-
- -
- - Copy issue link -
-
-
- )} -
); }; diff --git a/apps/app/components/core/spreadsheet-view/spreadsheet-columns.tsx b/apps/app/components/core/spreadsheet-view/spreadsheet-columns.tsx index 85d05a288..a0f404fba 100644 --- a/apps/app/components/core/spreadsheet-view/spreadsheet-columns.tsx +++ b/apps/app/components/core/spreadsheet-view/spreadsheet-columns.tsx @@ -40,7 +40,7 @@ export const SpreadsheetColumns: React.FC = ({ columnData, gridTemplateCo return (
{col.propertyName === "title" ? ( diff --git a/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx b/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx index eeef42750..5655d11de 100644 --- a/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx +++ b/apps/app/components/core/spreadsheet-view/spreadsheet-view.tsx @@ -62,7 +62,7 @@ export const SpreadsheetView: React.FC = ({ return (
-
+
{spreadsheetIssues ? ( diff --git a/apps/app/styles/globals.css b/apps/app/styles/globals.css index 22d060c86..2e997caea 100644 --- a/apps/app/styles/globals.css +++ b/apps/app/styles/globals.css @@ -225,3 +225,8 @@ body { -webkit-box-orient: vertical; -webkit-line-clamp: 1; } + +/* popover2 styling */ +.bp4-popover2-transition-container { + z-index: 20 !important; +}