mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
style: spreadsheet columns (#2554)
* style: spreadsheet columns * fix: build errors
This commit is contained in:
parent
cb533849e8
commit
442c83eea2
@ -144,7 +144,7 @@ export const CommandModal: React.FC<Props> = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
updatedAssignees.push(assignee);
|
updatedAssignees.push(assignee);
|
||||||
}
|
}
|
||||||
updateIssue({ assignees_list: updatedAssignees });
|
updateIssue({ assignees: updatedAssignees });
|
||||||
};
|
};
|
||||||
|
|
||||||
const redirect = (path: string) => {
|
const redirect = (path: string) => {
|
||||||
|
@ -79,7 +79,7 @@ export const ChangeIssueAssignee: FC<Props> = ({ setIsPaletteOpen, issue, user }
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleIssueAssignees = (assignee: string) => {
|
const handleIssueAssignees = (assignee: string) => {
|
||||||
const updatedAssignees = issue.assignees_list ?? [];
|
const updatedAssignees = issue.assignees ?? [];
|
||||||
|
|
||||||
if (updatedAssignees.includes(assignee)) {
|
if (updatedAssignees.includes(assignee)) {
|
||||||
updatedAssignees.splice(updatedAssignees.indexOf(assignee), 1);
|
updatedAssignees.splice(updatedAssignees.indexOf(assignee), 1);
|
||||||
@ -87,7 +87,7 @@ export const ChangeIssueAssignee: FC<Props> = ({ setIsPaletteOpen, issue, user }
|
|||||||
updatedAssignees.push(assignee);
|
updatedAssignees.push(assignee);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateIssue({ assignees_list: updatedAssignees });
|
updateIssue({ assignees: updatedAssignees });
|
||||||
setIsPaletteOpen(false);
|
setIsPaletteOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -198,8 +198,7 @@ export const InlineCreateIssueFormWrapper: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
if (onSuccess) await onSuccess(res);
|
if (onSuccess) await onSuccess(res);
|
||||||
|
|
||||||
if (formData.assignees_list?.some((assignee) => assignee === user?.id))
|
if (formData.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug as string));
|
||||||
mutate(USER_ISSUE(workspaceSlug as string));
|
|
||||||
|
|
||||||
if (formData.parent && formData.parent !== "") mutate(SUB_ISSUES(formData.parent));
|
if (formData.parent && formData.parent !== "") mutate(SUB_ISSUES(formData.parent));
|
||||||
})
|
})
|
||||||
|
@ -22,10 +22,10 @@ import { IInboxIssue, IIssue } from "types";
|
|||||||
const defaultValues: Partial<IInboxIssue> = {
|
const defaultValues: Partial<IInboxIssue> = {
|
||||||
name: "",
|
name: "",
|
||||||
description_html: "",
|
description_html: "",
|
||||||
assignees_list: [],
|
assignees: [],
|
||||||
priority: "low",
|
priority: "low",
|
||||||
target_date: new Date().toString(),
|
target_date: new Date().toString(),
|
||||||
labels_list: [],
|
labels: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InboxMainContent: React.FC = observer(() => {
|
export const InboxMainContent: React.FC = observer(() => {
|
||||||
@ -122,8 +122,8 @@ export const InboxMainContent: React.FC = observer(() => {
|
|||||||
|
|
||||||
reset({
|
reset({
|
||||||
...issueDetails,
|
...issueDetails,
|
||||||
assignees_list: issueDetails.assignees_list ?? (issueDetails.assignee_details ?? []).map((user) => user.id),
|
assignees: issueDetails.assignees ?? (issueDetails.assignee_details ?? []).map((user) => user.id),
|
||||||
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
labels: issueDetails.labels ?? issueDetails.labels,
|
||||||
});
|
});
|
||||||
}, [issueDetails, reset, inboxIssueId]);
|
}, [issueDetails, reset, inboxIssueId]);
|
||||||
|
|
||||||
|
@ -51,9 +51,7 @@ const defaultValues: Partial<IIssue> = {
|
|||||||
parent: null,
|
parent: null,
|
||||||
priority: "none",
|
priority: "none",
|
||||||
assignees: [],
|
assignees: [],
|
||||||
assignees_list: [],
|
|
||||||
labels: [],
|
labels: [],
|
||||||
labels_list: [],
|
|
||||||
start_date: null,
|
start_date: null,
|
||||||
target_date: null,
|
target_date: null,
|
||||||
};
|
};
|
||||||
@ -310,10 +308,7 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
handleClose={() => setLabelModal(false)}
|
handleClose={() => setLabelModal(false)}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
user={user}
|
user={user}
|
||||||
onSuccess={(response) => {
|
onSuccess={(response) => setValue("labels", [...watch("labels"), response.id])}
|
||||||
setValue("labels", [...watch("labels"), response.id]);
|
|
||||||
setValue("labels_list", [...watch("labels_list"), response.id]);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -208,8 +208,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = observer(
|
|||||||
message: "Issue created successfully.",
|
message: "Issue created successfully.",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (payload.assignees_list?.some((assignee) => assignee === user?.id))
|
if (payload.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug as string));
|
||||||
mutate(USER_ISSUE(workspaceSlug as string));
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -325,8 +324,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = observer(
|
|||||||
|
|
||||||
if (!createMore) onClose();
|
if (!createMore) onClose();
|
||||||
|
|
||||||
if (payload.assignees_list?.some((assignee) => assignee === user?.id))
|
if (payload.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug as string));
|
||||||
mutate(USER_ISSUE(workspaceSlug as string));
|
|
||||||
|
|
||||||
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
||||||
})
|
})
|
||||||
@ -347,8 +345,6 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = observer(
|
|||||||
|
|
||||||
const payload: Partial<IIssue> = {
|
const payload: Partial<IIssue> = {
|
||||||
...formData,
|
...formData,
|
||||||
assignees_list: formData.assignees ?? [],
|
|
||||||
labels_list: formData.labels ?? [],
|
|
||||||
description: formData.description ?? "",
|
description: formData.description ?? "",
|
||||||
description_html: formData.description_html ?? "<p></p>",
|
description_html: formData.description_html ?? "<p></p>",
|
||||||
};
|
};
|
||||||
|
@ -41,9 +41,7 @@ const defaultValues: Partial<IIssue> = {
|
|||||||
parent: null,
|
parent: null,
|
||||||
priority: "none",
|
priority: "none",
|
||||||
assignees: [],
|
assignees: [],
|
||||||
assignees_list: [],
|
|
||||||
labels: [],
|
labels: [],
|
||||||
labels_list: [],
|
|
||||||
start_date: null,
|
start_date: null,
|
||||||
target_date: null,
|
target_date: null,
|
||||||
};
|
};
|
||||||
@ -262,10 +260,7 @@ export const IssueForm: FC<IssueFormProps> = observer((props) => {
|
|||||||
handleClose={() => setLabelModal(false)}
|
handleClose={() => setLabelModal(false)}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
user={user ?? undefined}
|
user={user ?? undefined}
|
||||||
onSuccess={(response) => {
|
onSuccess={(response) => setValue("labels", [...watch("labels"), response.id])}
|
||||||
setValue("labels", [...watch("labels"), response.id]);
|
|
||||||
setValue("labels_list", [...watch("labels_list"), response.id]);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -147,18 +147,6 @@ export const CalendarInlineCreateIssueForm: React.FC<Props> = observer((props) =
|
|||||||
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
||||||
...(prePopulatedData ?? {}),
|
...(prePopulatedData ?? {}),
|
||||||
...formData,
|
...formData,
|
||||||
labels_list:
|
|
||||||
formData.labels_list?.length !== 0
|
|
||||||
? formData.labels_list
|
|
||||||
: prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none"
|
|
||||||
? [prePopulatedData.labels as any]
|
|
||||||
: [],
|
|
||||||
assignees_list:
|
|
||||||
formData.assignees_list?.length !== 0
|
|
||||||
? formData.assignees_list
|
|
||||||
: prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none"
|
|
||||||
? [prePopulatedData.assignees as any]
|
|
||||||
: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -113,12 +113,6 @@ export const GanttInlineCreateIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
||||||
...(prePopulatedData ?? {}),
|
...(prePopulatedData ?? {}),
|
||||||
...formData,
|
...formData,
|
||||||
labels_list:
|
|
||||||
formData.labels_list?.length !== 0
|
|
||||||
? formData.labels_list
|
|
||||||
: prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none"
|
|
||||||
? [prePopulatedData.labels as any]
|
|
||||||
: [],
|
|
||||||
start_date: renderDateFormat(new Date()),
|
start_date: renderDateFormat(new Date()),
|
||||||
target_date: renderDateFormat(new Date(new Date().getTime() + 24 * 60 * 60 * 1000)),
|
target_date: renderDateFormat(new Date(new Date().getTime() + 24 * 60 * 60 * 1000)),
|
||||||
});
|
});
|
||||||
|
@ -65,9 +65,9 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = (props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-sm rounded p-2 px-3 shadow-custom-shadow-2xs space-y-[8px] border transition-all bg-custom-background-100 hover:cursor-grab ${
|
className={`text-sm rounded p-2 px-3 shadow-custom-shadow-2xs space-y-[8px] border transition-all bg-custom-background-100 ${
|
||||||
snapshot.isDragging ? `border-custom-primary-100` : `border-transparent`
|
isDragDisabled ? "" : "hover:cursor-grab"
|
||||||
}`}
|
} ${snapshot.isDragging ? `border-custom-primary-100` : `border-transparent`}`}
|
||||||
>
|
>
|
||||||
{displayProperties && displayProperties?.key && (
|
{displayProperties && displayProperties?.key && (
|
||||||
<div className="text-xs line-clamp-1 text-custom-text-300">
|
<div className="text-xs line-clamp-1 text-custom-text-300">
|
||||||
|
@ -117,18 +117,6 @@ export const BoardInlineCreateIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
||||||
...(prePopulatedData ?? {}),
|
...(prePopulatedData ?? {}),
|
||||||
...formData,
|
...formData,
|
||||||
labels_list:
|
|
||||||
formData.labels_list && formData.labels_list.length !== 0
|
|
||||||
? formData.labels_list
|
|
||||||
: prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none"
|
|
||||||
? [prePopulatedData.labels as any]
|
|
||||||
: [],
|
|
||||||
assignees_list:
|
|
||||||
formData.assignees_list && formData.assignees_list.length !== 0
|
|
||||||
? formData.assignees_list
|
|
||||||
: prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none"
|
|
||||||
? [prePopulatedData.assignees as any]
|
|
||||||
: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -65,7 +65,7 @@ export const KanBanProperties: React.FC<IKanBanProperties> = observer((props) =>
|
|||||||
handleIssues(
|
handleIssues(
|
||||||
!sub_group_id && sub_group_id === "null" ? null : sub_group_id,
|
!sub_group_id && sub_group_id === "null" ? null : sub_group_id,
|
||||||
!group_id && group_id === "null" ? null : group_id,
|
!group_id && group_id === "null" ? null : group_id,
|
||||||
{ ...issue, labels_list: ids }
|
{ ...issue, labels: ids }
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ export const KanBanProperties: React.FC<IKanBanProperties> = observer((props) =>
|
|||||||
handleIssues(
|
handleIssues(
|
||||||
!sub_group_id && sub_group_id === "null" ? null : sub_group_id,
|
!sub_group_id && sub_group_id === "null" ? null : sub_group_id,
|
||||||
!group_id && group_id === "null" ? null : group_id,
|
!group_id && group_id === "null" ? null : group_id,
|
||||||
{ ...issue, assignees_list: ids }
|
{ ...issue, assignees: ids }
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,18 +116,6 @@ export const ListInlineCreateIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
||||||
...(prePopulatedData ?? {}),
|
...(prePopulatedData ?? {}),
|
||||||
...formData,
|
...formData,
|
||||||
labels_list:
|
|
||||||
formData.labels_list?.length !== 0
|
|
||||||
? formData.labels_list
|
|
||||||
: prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none"
|
|
||||||
? [prePopulatedData.labels as any]
|
|
||||||
: [],
|
|
||||||
assignees_list:
|
|
||||||
formData.assignees_list?.length !== 0
|
|
||||||
? formData.assignees_list
|
|
||||||
: prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none"
|
|
||||||
? [prePopulatedData.assignees as any]
|
|
||||||
: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -36,11 +36,11 @@ export const KanBanProperties: FC<IKanBanProperties> = observer((props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleLabel = (ids: string[]) => {
|
const handleLabel = (ids: string[]) => {
|
||||||
handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, labels_list: ids });
|
handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, labels: ids });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAssignee = (ids: string[]) => {
|
const handleAssignee = (ids: string[]) => {
|
||||||
handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, assignees_list: ids });
|
handleIssues(!group_id && group_id === "null" ? null : group_id, { ...issue, assignees: ids });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartDate = (date: string) => {
|
const handleStartDate = (date: string) => {
|
||||||
|
@ -21,12 +21,12 @@ export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ issue, members, onC
|
|||||||
const { subIssues, isLoading } = useSubIssue(issue.project_detail.id, issue.id, isExpanded);
|
const { subIssues, isLoading } = useSubIssue(issue.project_detail.id, issue.id, isExpanded);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="flex items-center h-full px-4">
|
||||||
<MembersSelect
|
<MembersSelect
|
||||||
value={issue.assignees}
|
value={issue.assignees}
|
||||||
onChange={(data) => onChange({ assignees_list: data })}
|
onChange={(data) => onChange({ assignees: data })}
|
||||||
members={members ?? []}
|
members={members ?? []}
|
||||||
buttonClassName="!p-0 !rounded-none !shadow-none !border-0"
|
buttonClassName="!p-0 !rounded-none !border-0"
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
multiple
|
multiple
|
||||||
@ -46,6 +46,6 @@ export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ issue, members, onC
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// components
|
// components
|
||||||
import { ViewEstimateSelect } from "components/issues";
|
import { EstimateSelect } from "components/estimates";
|
||||||
// hooks
|
// hooks
|
||||||
import useSubIssue from "hooks/use-sub-issue";
|
import useSubIssue from "hooks/use-sub-issue";
|
||||||
// types
|
// types
|
||||||
@ -21,7 +21,15 @@ export const SpreadsheetEstimateColumn: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewEstimateSelect issue={issue} onChange={(data) => onChange({ estimate_point: data })} disabled={disabled} />
|
<EstimateSelect
|
||||||
|
value={issue.estimate_point}
|
||||||
|
onChange={(data) => onChange({ estimate_point: data })}
|
||||||
|
className="h-full"
|
||||||
|
buttonClassName="!border-0 !h-full !w-full !rounded-none px-4"
|
||||||
|
estimatePoints={undefined}
|
||||||
|
disabled={disabled}
|
||||||
|
hideDropdownArrow
|
||||||
|
/>
|
||||||
|
|
||||||
{isExpanded &&
|
{isExpanded &&
|
||||||
!isLoading &&
|
!isLoading &&
|
||||||
|
@ -5,13 +5,12 @@ import { MoreHorizontal, Pencil, Trash2, ChevronRight, Link } from "lucide-react
|
|||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IIssueDisplayProperties } from "types";
|
import { IIssue, IIssueDisplayProperties } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
projectId: string;
|
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
handleToggleExpand: (issueId: string) => void;
|
handleToggleExpand: (issueId: string) => void;
|
||||||
properties: IIssueDisplayProperties;
|
properties: IIssueDisplayProperties;
|
||||||
@ -23,7 +22,6 @@ type Props = {
|
|||||||
|
|
||||||
export const IssueColumn: React.FC<Props> = ({
|
export const IssueColumn: React.FC<Props> = ({
|
||||||
issue,
|
issue,
|
||||||
projectId,
|
|
||||||
expanded,
|
expanded,
|
||||||
handleToggleExpand,
|
handleToggleExpand,
|
||||||
properties,
|
properties,
|
||||||
@ -50,8 +48,7 @@ export const IssueColumn: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
copyUrlToClipboard(`${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => {
|
||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => {
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
|
@ -9,7 +9,6 @@ import { IIssue, IIssueDisplayProperties } from "types";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
projectId: string;
|
|
||||||
expandedIssues: string[];
|
expandedIssues: string[];
|
||||||
setExpandedIssues: React.Dispatch<React.SetStateAction<string[]>>;
|
setExpandedIssues: React.Dispatch<React.SetStateAction<string[]>>;
|
||||||
properties: IIssueDisplayProperties;
|
properties: IIssueDisplayProperties;
|
||||||
@ -20,7 +19,6 @@ type Props = {
|
|||||||
|
|
||||||
export const SpreadsheetIssuesColumn: React.FC<Props> = ({
|
export const SpreadsheetIssuesColumn: React.FC<Props> = ({
|
||||||
issue,
|
issue,
|
||||||
projectId,
|
|
||||||
expandedIssues,
|
expandedIssues,
|
||||||
setExpandedIssues,
|
setExpandedIssues,
|
||||||
properties,
|
properties,
|
||||||
@ -48,7 +46,6 @@ export const SpreadsheetIssuesColumn: React.FC<Props> = ({
|
|||||||
<>
|
<>
|
||||||
<IssueColumn
|
<IssueColumn
|
||||||
issue={issue}
|
issue={issue}
|
||||||
projectId={projectId}
|
|
||||||
expanded={isExpanded}
|
expanded={isExpanded}
|
||||||
handleToggleExpand={handleToggleExpand}
|
handleToggleExpand={handleToggleExpand}
|
||||||
properties={properties}
|
properties={properties}
|
||||||
@ -66,7 +63,6 @@ export const SpreadsheetIssuesColumn: React.FC<Props> = ({
|
|||||||
<SpreadsheetIssuesColumn
|
<SpreadsheetIssuesColumn
|
||||||
key={subIssue.id}
|
key={subIssue.id}
|
||||||
issue={subIssue}
|
issue={subIssue}
|
||||||
projectId={subIssue.project_detail.id}
|
|
||||||
expandedIssues={expandedIssues}
|
expandedIssues={expandedIssues}
|
||||||
setExpandedIssues={setExpandedIssues}
|
setExpandedIssues={setExpandedIssues}
|
||||||
properties={properties}
|
properties={properties}
|
||||||
|
@ -26,8 +26,10 @@ export const SpreadsheetLabelColumn: React.FC<Props> = (props) => {
|
|||||||
<>
|
<>
|
||||||
<LabelSelect
|
<LabelSelect
|
||||||
value={issue.labels}
|
value={issue.labels}
|
||||||
onChange={(data) => onChange({ labels_list: data })}
|
onChange={(data) => onChange({ labels: data })}
|
||||||
labels={labels ?? []}
|
labels={labels ?? []}
|
||||||
|
className="h-full"
|
||||||
|
buttonClassName="!border-0 !h-full !w-full !rounded-none"
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
maxRender={1}
|
maxRender={1}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -20,11 +20,14 @@ export const SpreadsheetPriorityColumn: React.FC<Props> = ({ issue, onChange, ex
|
|||||||
const { subIssues, isLoading } = useSubIssue(issue.project_detail.id, issue.id, isExpanded);
|
const { subIssues, isLoading } = useSubIssue(issue.project_detail.id, issue.id, isExpanded);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<PrioritySelect
|
<PrioritySelect
|
||||||
value={issue.priority}
|
value={issue.priority}
|
||||||
onChange={(data) => onChange({ priority: data })}
|
onChange={(data) => onChange({ priority: data })}
|
||||||
buttonClassName="!p-0 !rounded-none !shadow-none !border-0"
|
className="h-full"
|
||||||
|
buttonClassName="!border-0 !h-full !w-full !rounded-none px-4"
|
||||||
|
showTitle
|
||||||
|
highlightUrgentPriority={false}
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
@ -42,6 +45,6 @@ export const SpreadsheetPriorityColumn: React.FC<Props> = ({ issue, onChange, ex
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -32,7 +32,8 @@ export const SpreadsheetStateColumn: React.FC<Props> = (props) => {
|
|||||||
value={issue.state_detail}
|
value={issue.state_detail}
|
||||||
onChange={(data) => onChange({ state: data.id, state_detail: data })}
|
onChange={(data) => onChange({ state: data.id, state_detail: data })}
|
||||||
states={statesList}
|
states={statesList}
|
||||||
buttonClassName="!shadow-none !border-0"
|
className="h-full"
|
||||||
|
buttonClassName="!border-0 !h-full !w-full !rounded-none"
|
||||||
hideDropdownArrow
|
hideDropdownArrow
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
|
@ -120,18 +120,6 @@ export const SpreadsheetInlineCreateIssueForm: React.FC<Props> = observer((props
|
|||||||
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
const payload = createIssuePayload(workspaceDetail!, projectDetails!, {
|
||||||
...(prePopulatedData ?? {}),
|
...(prePopulatedData ?? {}),
|
||||||
...formData,
|
...formData,
|
||||||
labels_list:
|
|
||||||
formData.labels_list && formData.labels_list?.length !== 0
|
|
||||||
? formData.labels_list
|
|
||||||
: prePopulatedData?.labels && prePopulatedData?.labels.toString() !== "none"
|
|
||||||
? [prePopulatedData.labels as any]
|
|
||||||
: [],
|
|
||||||
assignees_list:
|
|
||||||
formData.assignees_list && formData.assignees_list?.length !== 0
|
|
||||||
? formData.assignees_list
|
|
||||||
: prePopulatedData?.assignees && prePopulatedData?.assignees.toString() !== "none"
|
|
||||||
? [prePopulatedData.assignees as any]
|
|
||||||
: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -100,6 +100,7 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
width="xl"
|
width="xl"
|
||||||
|
placement="bottom-end"
|
||||||
>
|
>
|
||||||
<CustomMenu.MenuItem onClick={() => handleOrderBy(propertyDetails.ascendingOrderKey, property)}>
|
<CustomMenu.MenuItem onClick={() => handleOrderBy(propertyDetails.ascendingOrderKey, property)}>
|
||||||
<div
|
<div
|
||||||
@ -163,7 +164,9 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
|
|||||||
{issues?.map((issue) => (
|
{issues?.map((issue) => (
|
||||||
<div
|
<div
|
||||||
key={`${property}-${issue.id}`}
|
key={`${property}-${issue.id}`}
|
||||||
className="h-11 flex items-center px-4 py-2.5 border-b-[0.5px] border-custom-border-200"
|
className={`h-11 border-b-[0.5px] border-custom-border-200 ${
|
||||||
|
disableUserActions ? "" : "cursor-pointer hover:bg-custom-background-80"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{property === "state" ? (
|
{property === "state" ? (
|
||||||
<SpreadsheetStateColumn
|
<SpreadsheetStateColumn
|
||||||
|
@ -99,11 +99,10 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
|||||||
<span className="flex items-center px-4 py-2.5 h-full w-full flex-grow">Issue</span>
|
<span className="flex items-center px-4 py-2.5 h-full w-full flex-grow">Issue</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{issues.map((issue: IIssue, index) => (
|
{issues.map((issue, index) => (
|
||||||
<SpreadsheetIssuesColumn
|
<SpreadsheetIssuesColumn
|
||||||
key={`${issue.id}_${index}`}
|
key={`${issue.id}_${index}`}
|
||||||
issue={issue}
|
issue={issue}
|
||||||
projectId={issue.project_detail.id}
|
|
||||||
expandedIssues={expandedIssues}
|
expandedIssues={expandedIssues}
|
||||||
setExpandedIssues={setExpandedIssues}
|
setExpandedIssues={setExpandedIssues}
|
||||||
properties={displayProperties}
|
properties={displayProperties}
|
||||||
|
@ -229,8 +229,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
setFormDirtyState(null);
|
setFormDirtyState(null);
|
||||||
setShowConfirmDiscard(false);
|
setShowConfirmDiscard(false);
|
||||||
|
|
||||||
if (payload.assignees_list?.some((assignee) => assignee === user?.id))
|
if (payload.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug as string));
|
||||||
mutate(USER_ISSUE(workspaceSlug as string));
|
|
||||||
|
|
||||||
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
||||||
})
|
})
|
||||||
@ -271,8 +270,6 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
|
|
||||||
const payload: Partial<IIssue> = {
|
const payload: Partial<IIssue> = {
|
||||||
...formData,
|
...formData,
|
||||||
assignees_list: formData.assignees ?? [],
|
|
||||||
labels_list: formData.labels ?? [],
|
|
||||||
description: formData.description ?? "",
|
description: formData.description ?? "",
|
||||||
description_html: formData.description_html ?? "<p></p>",
|
description_html: formData.description_html ?? "<p></p>",
|
||||||
};
|
};
|
||||||
|
@ -93,7 +93,7 @@ export const PeekOverviewIssueProperties: FC<Props> = (props) => {
|
|||||||
<div className="w-3/4">
|
<div className="w-3/4">
|
||||||
<SidebarAssigneeSelect
|
<SidebarAssigneeSelect
|
||||||
value={issue.assignees}
|
value={issue.assignees}
|
||||||
onChange={(val: string[]) => handleUpdateIssue({ assignees_list: val })}
|
onChange={(val: string[]) => handleUpdateIssue({ assignees: val })}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,7 +77,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
|
|
||||||
issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false);
|
issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false);
|
||||||
|
|
||||||
submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] });
|
submitChanges({ labels: [...(issueDetails?.labels ?? []), res.id] });
|
||||||
|
|
||||||
setCreateLabelForm(false);
|
setCreateLabelForm(false);
|
||||||
});
|
});
|
||||||
@ -99,7 +99,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="basis-1/2">
|
<div className="basis-1/2">
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{watchIssue("labels_list")?.map((labelId) => {
|
{watchIssue("labels")?.map((labelId) => {
|
||||||
const label = issueLabels?.find((l) => l.id === labelId);
|
const label = issueLabels?.find((l) => l.id === labelId);
|
||||||
|
|
||||||
if (label)
|
if (label)
|
||||||
@ -108,9 +108,9 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
key={label.id}
|
key={label.id}
|
||||||
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-100 px-1 py-0.5 text-xs hover:border-red-500/20 hover:bg-red-500/20"
|
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-100 px-1 py-0.5 text-xs hover:border-red-500/20 hover:bg-red-500/20"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const updatedLabels = watchIssue("labels_list")?.filter((l) => l !== labelId);
|
const updatedLabels = watchIssue("labels")?.filter((l) => l !== labelId);
|
||||||
submitChanges({
|
submitChanges({
|
||||||
labels_list: updatedLabels,
|
labels: updatedLabels,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -127,12 +127,12 @@ export const SidebarLabelSelect: React.FC<Props> = ({
|
|||||||
})}
|
})}
|
||||||
<Controller
|
<Controller
|
||||||
control={issueControl}
|
control={issueControl}
|
||||||
name="labels_list"
|
name="labels"
|
||||||
render={({ field: { value } }) => (
|
render={({ field: { value } }) => (
|
||||||
<Listbox
|
<Listbox
|
||||||
as="div"
|
as="div"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val: any) => submitChanges({ labels_list: val })}
|
onChange={(val: any) => submitChanges({ labels: val })}
|
||||||
className="flex-shrink-0"
|
className="flex-shrink-0"
|
||||||
multiple
|
multiple
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={isNotAllowed || uneditable}
|
||||||
|
@ -357,11 +357,11 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
<div className="sm:basis-1/2">
|
<div className="sm:basis-1/2">
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="assignees_list"
|
name="assignees"
|
||||||
render={({ field: { value } }) => (
|
render={({ field: { value } }) => (
|
||||||
<SidebarAssigneeSelect
|
<SidebarAssigneeSelect
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val: string[]) => submitChanges({ assignees_list: val })}
|
onChange={(val: string[]) => submitChanges({ assignees: val })}
|
||||||
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -72,7 +72,7 @@ export const IssueProperty: React.FC<IIssueProperty> = observer((props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleAssigneeChange = (data: string[]) => {
|
const handleAssigneeChange = (data: string[]) => {
|
||||||
partialUpdateIssue({ assignees_list: data, assignees: data });
|
partialUpdateIssue({ assignees: data });
|
||||||
|
|
||||||
trackEventService.trackIssuePartialPropertyUpdateEvent(
|
trackEventService.trackIssuePartialPropertyUpdateEvent(
|
||||||
{
|
{
|
||||||
|
@ -90,7 +90,7 @@ export const ViewAssigneeSelect: React.FC<Props> = ({
|
|||||||
if (newData.includes(data)) newData.splice(newData.indexOf(data), 1);
|
if (newData.includes(data)) newData.splice(newData.indexOf(data), 1);
|
||||||
else newData.push(data);
|
else newData.push(data);
|
||||||
|
|
||||||
partialUpdateIssue({ assignees_list: data }, issue);
|
partialUpdateIssue({ assignees: data }, issue);
|
||||||
|
|
||||||
trackEventService.trackIssuePartialPropertyUpdateEvent(
|
trackEventService.trackIssuePartialPropertyUpdateEvent(
|
||||||
{
|
{
|
||||||
|
@ -139,7 +139,7 @@ export const ViewLabelSelect: FC<Props> = ({
|
|||||||
<CustomSearchSelect
|
<CustomSearchSelect
|
||||||
value={issue.labels}
|
value={issue.labels}
|
||||||
onChange={(data: string[]) => {
|
onChange={(data: string[]) => {
|
||||||
partialUpdateIssue({ labels_list: data }, issue);
|
partialUpdateIssue({ labels: data }, issue);
|
||||||
}}
|
}}
|
||||||
options={options}
|
options={options}
|
||||||
{...(customButton ? { customButton: labelsLabel } : { label: labelsLabel })}
|
{...(customButton ? { customButton: labelsLabel } : { label: labelsLabel })}
|
||||||
|
@ -23,7 +23,7 @@ const defaultValues: Partial<IModule> = {
|
|||||||
description: "",
|
description: "",
|
||||||
status: "backlog",
|
status: "backlog",
|
||||||
lead: null,
|
lead: null,
|
||||||
members_list: [],
|
members: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModuleForm: React.FC<Props> = ({
|
export const ModuleForm: React.FC<Props> = ({
|
||||||
@ -47,7 +47,7 @@ export const ModuleForm: React.FC<Props> = ({
|
|||||||
description: data?.description || "",
|
description: data?.description || "",
|
||||||
status: data?.status || "backlog",
|
status: data?.status || "backlog",
|
||||||
lead: data?.lead || null,
|
lead: data?.lead || null,
|
||||||
members_list: data?.members_list || [],
|
members: data?.members || [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ const defaultValues: Partial<IModule> = {
|
|||||||
description: "",
|
description: "",
|
||||||
status: "backlog",
|
status: "backlog",
|
||||||
lead: null,
|
lead: null,
|
||||||
members_list: [],
|
members: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
|
export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
|
||||||
@ -98,7 +98,6 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const payload: Partial<IModule> = {
|
const payload: Partial<IModule> = {
|
||||||
...formData,
|
...formData,
|
||||||
members_list: formData.members,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!data) await createModule(payload);
|
if (!data) await createModule(payload);
|
||||||
|
@ -32,7 +32,7 @@ import { MODULE_STATUS } from "constants/module";
|
|||||||
|
|
||||||
const defaultValues: Partial<IModule> = {
|
const defaultValues: Partial<IModule> = {
|
||||||
lead: "",
|
lead: "",
|
||||||
members_list: [],
|
members: [],
|
||||||
start_date: null,
|
start_date: null,
|
||||||
target_date: null,
|
target_date: null,
|
||||||
status: "backlog",
|
status: "backlog",
|
||||||
@ -186,7 +186,6 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
if (moduleDetails)
|
if (moduleDetails)
|
||||||
reset({
|
reset({
|
||||||
...moduleDetails,
|
...moduleDetails,
|
||||||
members_list: moduleDetails.members_list ?? moduleDetails.members_detail?.map((m) => m.id),
|
|
||||||
});
|
});
|
||||||
}, [moduleDetails, reset]);
|
}, [moduleDetails, reset]);
|
||||||
|
|
||||||
@ -301,12 +300,12 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
/>
|
/>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="members_list"
|
name="members"
|
||||||
render={({ field: { value } }) => (
|
render={({ field: { value } }) => (
|
||||||
<SidebarMembersSelect
|
<SidebarMembersSelect
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val: string[]) => {
|
onChange={(val: string[]) => {
|
||||||
submitChanges({ members_list: val });
|
submitChanges({ members: val });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
import { Placement } from "@popperjs/core";
|
import { Placement } from "@popperjs/core";
|
||||||
import { Combobox } from "@headlessui/react";
|
import { Combobox } from "@headlessui/react";
|
||||||
import { Check, ChevronDown, PlusIcon, Search } from "lucide-react";
|
import { Check, ChevronDown, Search } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Tooltip } from "components/ui";
|
import { Tooltip } from "components/ui";
|
||||||
// types
|
// types
|
||||||
@ -21,18 +21,20 @@ type Props = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LabelSelect: React.FC<Props> = ({
|
export const LabelSelect: React.FC<Props> = (props) => {
|
||||||
value,
|
const {
|
||||||
onChange,
|
value,
|
||||||
labels,
|
onChange,
|
||||||
className = "",
|
labels,
|
||||||
buttonClassName = "",
|
className = "",
|
||||||
optionsClassName = "",
|
buttonClassName = "",
|
||||||
maxRender = 2,
|
optionsClassName = "",
|
||||||
placement,
|
maxRender = 2,
|
||||||
hideDropdownArrow = false,
|
placement,
|
||||||
disabled = false,
|
hideDropdownArrow = false,
|
||||||
}) => {
|
disabled = false,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||||
@ -79,63 +81,57 @@ export const LabelSelect: React.FC<Props> = ({
|
|||||||
multiple
|
multiple
|
||||||
>
|
>
|
||||||
<Combobox.Button as={React.Fragment}>
|
<Combobox.Button as={React.Fragment}>
|
||||||
<button
|
<button ref={setReferenceElement} type="button" className="h-full w-full">
|
||||||
ref={setReferenceElement}
|
{value.length > 0 ? (
|
||||||
type="button"
|
value.length <= maxRender ? (
|
||||||
className={`flex items-center justify-between gap-1 w-full text-xs ${
|
<div className="flex items-center gap-2 px-4 overflow-x-scroll">
|
||||||
disabled
|
{labels
|
||||||
? "cursor-not-allowed text-custom-text-200"
|
?.filter((l) => value.includes(l.id))
|
||||||
: value.length <= maxRender
|
.map((label) => (
|
||||||
? "cursor-pointer"
|
<div
|
||||||
: "cursor-pointer hover:bg-custom-background-80"
|
key={label.id}
|
||||||
} ${buttonClassName}`}
|
className="flex items-center flex-shrink-0 rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 text-xs h-full"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-custom-text-200 h-full">
|
<div className="flex items-center gap-1.5 text-custom-text-200">
|
||||||
{value.length > 0 ? (
|
<span
|
||||||
value.length <= maxRender ? (
|
className="h-2 w-2 flex-shrink-0 rounded-full"
|
||||||
<>
|
style={{
|
||||||
{labels
|
backgroundColor: label?.color ?? "#000000",
|
||||||
?.filter((l) => value.includes(l.id))
|
}}
|
||||||
.map((label) => (
|
/>
|
||||||
<div
|
{label.name}
|
||||||
key={label.id}
|
|
||||||
className="flex cursor-default items-center flex-shrink-0 rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 text-xs h-full"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-1.5 text-custom-text-200">
|
|
||||||
<span
|
|
||||||
className="h-2 w-2 flex-shrink-0 rounded-full"
|
|
||||||
style={{
|
|
||||||
backgroundColor: label?.color ?? "#000000",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{label.name}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="h-full flex cursor-default items-center flex-shrink-0 rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 text-xs">
|
|
||||||
<Tooltip
|
|
||||||
position="top"
|
|
||||||
tooltipHeading="Labels"
|
|
||||||
tooltipContent={labels
|
|
||||||
?.filter((l) => value.includes(l.id))
|
|
||||||
.map((l) => l.name)
|
|
||||||
.join(", ")}
|
|
||||||
>
|
|
||||||
<div className="h-full flex items-center gap-1.5 text-custom-text-200">
|
|
||||||
<span className="h-2 w-2 flex-shrink-0 rounded-full bg-custom-primary" />
|
|
||||||
{`${value.length} Labels`}
|
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
))}
|
||||||
</div>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<div className="h-full flex items-center justify-center text-xs rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 hover:bg-custom-background-80">
|
|
||||||
Select labels
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : (
|
||||||
</div>
|
<div
|
||||||
|
className={`h-full flex items-center flex-shrink-0 rounded border-[0.5px] border-custom-border-300 px-4 text-xs ${buttonClassName}`}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
position="top"
|
||||||
|
tooltipHeading="Labels"
|
||||||
|
tooltipContent={labels
|
||||||
|
?.filter((l) => value.includes(l.id))
|
||||||
|
.map((l) => l.name)
|
||||||
|
.join(", ")}
|
||||||
|
>
|
||||||
|
<div className="h-full flex items-center gap-1.5 text-custom-text-200">
|
||||||
|
<span className="h-2 w-2 flex-shrink-0 rounded-full bg-custom-primary" />
|
||||||
|
{`${value.length} Labels`}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className={`flex items-center justify-between gap-1 w-full text-xs px-4 ${
|
||||||
|
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
||||||
|
} ${buttonClassName}`}
|
||||||
|
>
|
||||||
|
Select labels
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
||||||
</button>
|
</button>
|
||||||
</Combobox.Button>
|
</Combobox.Button>
|
||||||
|
@ -20,6 +20,8 @@ type Props = {
|
|||||||
buttonClassName?: string;
|
buttonClassName?: string;
|
||||||
optionsClassName?: string;
|
optionsClassName?: string;
|
||||||
placement?: Placement;
|
placement?: Placement;
|
||||||
|
showTitle?: boolean;
|
||||||
|
highlightUrgentPriority?: boolean;
|
||||||
hideDropdownArrow?: boolean;
|
hideDropdownArrow?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
@ -31,6 +33,8 @@ export const PrioritySelect: React.FC<Props> = ({
|
|||||||
buttonClassName = "",
|
buttonClassName = "",
|
||||||
optionsClassName = "",
|
optionsClassName = "",
|
||||||
placement,
|
placement,
|
||||||
|
showTitle = false,
|
||||||
|
highlightUrgentPriority = true,
|
||||||
hideDropdownArrow = false,
|
hideDropdownArrow = false,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
}) => {
|
}) => {
|
||||||
@ -69,20 +73,21 @@ export const PrioritySelect: React.FC<Props> = ({
|
|||||||
|
|
||||||
const label = (
|
const label = (
|
||||||
<Tooltip tooltipHeading="Priority" tooltipContent={selectedOption} position="top">
|
<Tooltip tooltipHeading="Priority" tooltipContent={selectedOption} position="top">
|
||||||
<PriorityIcon
|
<div className="flex items-center gap-2">
|
||||||
priority={value}
|
<PriorityIcon
|
||||||
className={`h-3.5 w-3.5 ${
|
priority={value}
|
||||||
value === "urgent"
|
className={`h-3.5 w-3.5 ${
|
||||||
? "text-white"
|
value === "high"
|
||||||
: value === "high"
|
? "text-orange-500"
|
||||||
? "text-orange-500"
|
: value === "medium"
|
||||||
: value === "medium"
|
? "text-yellow-500"
|
||||||
? "text-yellow-500"
|
: value === "low"
|
||||||
: value === "low"
|
? "text-green-500"
|
||||||
? "text-green-500"
|
: "text-custom-text-200"
|
||||||
: "text-custom-text-200"
|
} ${value === "urgent" && highlightUrgentPriority ? "text-white" : "text-red-500"}`}
|
||||||
}`}
|
/>
|
||||||
/>
|
{showTitle && <span className="capitalize text-xs">{value}</span>}
|
||||||
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -99,9 +104,13 @@ export const PrioritySelect: React.FC<Props> = ({
|
|||||||
ref={setReferenceElement}
|
ref={setReferenceElement}
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex items-center justify-between gap-1 h-full w-full text-xs rounded border-[0.5px] ${
|
className={`flex items-center justify-between gap-1 h-full w-full text-xs rounded border-[0.5px] ${
|
||||||
value === "urgent" ? "border-red-500/20 bg-red-500" : "border-custom-border-300"
|
value === "urgent"
|
||||||
} ${
|
? highlightUrgentPriority
|
||||||
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
|
? "border-red-500/20 bg-red-500"
|
||||||
|
: "border-custom-border-300"
|
||||||
|
: "border-custom-border-300"
|
||||||
|
} ${!disabled ? "hover:bg-custom-background-80" : ""} ${
|
||||||
|
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer"
|
||||||
} ${buttonClassName}`}
|
} ${buttonClassName}`}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
@ -144,7 +144,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
|
|||||||
<div>
|
<div>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="assignees_list"
|
name="assignees"
|
||||||
render={({ field: { value } }) => (
|
render={({ field: { value } }) => (
|
||||||
<AssigneeSelect
|
<AssigneeSelect
|
||||||
value={value}
|
value={value}
|
||||||
@ -152,7 +152,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
|
|||||||
onChange={(val: string) => {
|
onChange={(val: string) => {
|
||||||
const assignees = value?.includes(val) ? value?.filter((i) => i !== val) : [...(value ?? []), val];
|
const assignees = value?.includes(val) ? value?.filter((i) => i !== val) : [...(value ?? []), val];
|
||||||
|
|
||||||
submitChanges({ assignees_list: assignees });
|
submitChanges({ assignees: assignees });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -232,7 +232,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
issue_id: relation.issue_detail?.id,
|
issue_id: relation.issue_detail?.id,
|
||||||
project_id: relation.issue_detail?.project_detail.id,
|
project_id: relation.issue_detail?.project_detail.id,
|
||||||
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`
|
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -295,7 +295,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
issue_id: relation.issue_detail?.id,
|
issue_id: relation.issue_detail?.id,
|
||||||
project_id: relation.issue_detail?.project_detail.id,
|
project_id: relation.issue_detail?.project_detail.id,
|
||||||
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`
|
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -358,7 +358,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
issue_id: relation.issue_detail?.id,
|
issue_id: relation.issue_detail?.id,
|
||||||
project_id: relation.issue_detail?.project_detail.id,
|
project_id: relation.issue_detail?.project_detail.id,
|
||||||
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`
|
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -421,7 +421,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
issue_id: relation.issue_detail?.id,
|
issue_id: relation.issue_detail?.id,
|
||||||
project_id: relation.issue_detail?.project_detail.id,
|
project_id: relation.issue_detail?.project_detail.id,
|
||||||
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`
|
issue_identifier: `${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -437,7 +437,6 @@ export const createIssuePayload: (
|
|||||||
archived_at: null,
|
archived_at: null,
|
||||||
assignees: [],
|
assignees: [],
|
||||||
assignee_details: [],
|
assignee_details: [],
|
||||||
assignees_list: [],
|
|
||||||
attachment_count: 0,
|
attachment_count: 0,
|
||||||
attachments: [],
|
attachments: [],
|
||||||
issue_relations: [],
|
issue_relations: [],
|
||||||
@ -459,7 +458,6 @@ export const createIssuePayload: (
|
|||||||
labels: [],
|
labels: [],
|
||||||
label_details: [],
|
label_details: [],
|
||||||
is_draft: false,
|
is_draft: false,
|
||||||
labels_list: [],
|
|
||||||
links_list: [],
|
links_list: [],
|
||||||
link_count: 0,
|
link_count: 0,
|
||||||
module: null,
|
module: null,
|
||||||
|
@ -37,8 +37,6 @@ export const handleIssuesMutation: THandleIssuesMutation = (
|
|||||||
const updatedIssue = {
|
const updatedIssue = {
|
||||||
...prevData[issueIndex],
|
...prevData[issueIndex],
|
||||||
...formData,
|
...formData,
|
||||||
assignees: formData?.assignees_list ?? prevData[issueIndex]?.assignees,
|
|
||||||
labels: formData?.labels_list ?? prevData[issueIndex]?.labels,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
prevData.splice(issueIndex, 1, updatedIssue);
|
prevData.splice(issueIndex, 1, updatedIssue);
|
||||||
@ -55,8 +53,6 @@ export const handleIssuesMutation: THandleIssuesMutation = (
|
|||||||
const updatedIssue = {
|
const updatedIssue = {
|
||||||
...oldGroup[issueIndex],
|
...oldGroup[issueIndex],
|
||||||
...formData,
|
...formData,
|
||||||
assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees,
|
|
||||||
labels: formData?.labels_list ?? oldGroup[issueIndex]?.labels,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (selectedGroupBy !== Object.keys(formData)[0])
|
if (selectedGroupBy !== Object.keys(formData)[0])
|
||||||
|
@ -32,12 +32,10 @@ const defaultValues: Partial<IIssue> = {
|
|||||||
description_html: "",
|
description_html: "",
|
||||||
estimate_point: null,
|
estimate_point: null,
|
||||||
state: "",
|
state: "",
|
||||||
assignees_list: [],
|
|
||||||
priority: "low",
|
priority: "low",
|
||||||
target_date: new Date().toString(),
|
target_date: new Date().toString(),
|
||||||
issue_cycle: null,
|
issue_cycle: null,
|
||||||
issue_module: null,
|
issue_module: null,
|
||||||
labels_list: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// services
|
// services
|
||||||
@ -109,9 +107,6 @@ const ArchivedIssueDetailsPage: NextPage = () => {
|
|||||||
mutate(PROJECT_ISSUES_ACTIVITY(archivedIssueId as string));
|
mutate(PROJECT_ISSUES_ACTIVITY(archivedIssueId as string));
|
||||||
reset({
|
reset({
|
||||||
...issueDetails,
|
...issueDetails,
|
||||||
assignees_list: issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id),
|
|
||||||
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
|
||||||
labels: issueDetails.labels_list ?? issueDetails.labels,
|
|
||||||
});
|
});
|
||||||
}, [issueDetails, reset, archivedIssueId]);
|
}, [issueDetails, reset, archivedIssueId]);
|
||||||
|
|
||||||
|
@ -27,13 +27,11 @@ import { PROJECT_ISSUES_ACTIVITY, ISSUE_DETAILS } from "constants/fetch-keys";
|
|||||||
// helper
|
// helper
|
||||||
|
|
||||||
const defaultValues: Partial<IIssue> = {
|
const defaultValues: Partial<IIssue> = {
|
||||||
assignees_list: [],
|
|
||||||
description: "",
|
description: "",
|
||||||
description_html: "",
|
description_html: "",
|
||||||
estimate_point: null,
|
estimate_point: null,
|
||||||
issue_cycle: null,
|
issue_cycle: null,
|
||||||
issue_module: null,
|
issue_module: null,
|
||||||
labels_list: [],
|
|
||||||
name: "",
|
name: "",
|
||||||
priority: "low",
|
priority: "low",
|
||||||
start_date: null,
|
start_date: null,
|
||||||
@ -109,9 +107,6 @@ const IssueDetailsPage: NextPage = () => {
|
|||||||
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
reset({
|
reset({
|
||||||
...issueDetails,
|
...issueDetails,
|
||||||
assignees_list: issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id),
|
|
||||||
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
|
||||||
labels: issueDetails.labels_list ?? issueDetails.labels,
|
|
||||||
});
|
});
|
||||||
}, [issueDetails, reset, issueId]);
|
}, [issueDetails, reset, issueId]);
|
||||||
|
|
||||||
|
@ -133,7 +133,6 @@ const SinglePage: NextPage = () => {
|
|||||||
(prevData) => ({
|
(prevData) => ({
|
||||||
...(prevData as IPage),
|
...(prevData as IPage),
|
||||||
...formData,
|
...formData,
|
||||||
labels: formData.labels_list ? formData.labels_list : (prevData as IPage).labels,
|
|
||||||
}),
|
}),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
@ -361,7 +360,7 @@ const SinglePage: NextPage = () => {
|
|||||||
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-200 px-2 py-0.5 text-xs hover:border-red-500 hover:bg-red-50"
|
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-200 px-2 py-0.5 text-xs hover:border-red-500 hover:bg-red-50"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const updatedLabels = pageDetails.labels.filter((l) => l !== labelId);
|
const updatedLabels = pageDetails.labels.filter((l) => l !== labelId);
|
||||||
partialUpdatePage({ labels_list: updatedLabels });
|
partialUpdatePage({ labels: updatedLabels });
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${label?.color && label.color !== "" ? label.color : "#000000"}20`,
|
backgroundColor: `${label?.color && label.color !== "" ? label.color : "#000000"}20`,
|
||||||
@ -402,7 +401,7 @@ const SinglePage: NextPage = () => {
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
onChange={(val: string[]) => partialUpdatePage({ labels_list: val })}
|
onChange={(val: string[]) => partialUpdatePage({ labels: val })}
|
||||||
options={options}
|
options={options}
|
||||||
multiple
|
multiple
|
||||||
noChevron
|
noChevron
|
||||||
@ -606,7 +605,7 @@ const SinglePage: NextPage = () => {
|
|||||||
user={user}
|
user={user}
|
||||||
onSuccess={(response) => {
|
onSuccess={(response) => {
|
||||||
partialUpdatePage({
|
partialUpdatePage({
|
||||||
labels_list: [...(pageDetails.labels ?? []), response.id],
|
labels: [...(pageDetails.labels ?? []), response.id],
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -69,15 +69,13 @@ const MobileWebViewIssueDetail_ = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!issueDetails) return;
|
if (!issueDetails) return;
|
||||||
|
|
||||||
reset({
|
reset({
|
||||||
...issueDetails,
|
...issueDetails,
|
||||||
name: issueDetails.name,
|
name: issueDetails.name,
|
||||||
description: issueDetails.description,
|
description: issueDetails.description,
|
||||||
description_html: issueDetails.description_html,
|
description_html: issueDetails.description_html,
|
||||||
state: issueDetails.state,
|
state: issueDetails.state,
|
||||||
assignees_list: issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id),
|
|
||||||
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
|
||||||
labels: issueDetails.labels_list ?? issueDetails.labels,
|
|
||||||
});
|
});
|
||||||
}, [issueDetails, reset]);
|
}, [issueDetails, reset]);
|
||||||
|
|
||||||
|
@ -122,7 +122,6 @@ export class DraftIssuesStore {
|
|||||||
|
|
||||||
// immediately update the issue in the store
|
// immediately update the issue in the store
|
||||||
const updatedIssue = { ...this.issues[issueId], ...issueForm };
|
const updatedIssue = { ...this.issues[issueId], ...issueForm };
|
||||||
if (updatedIssue.assignees_list) updatedIssue.assignees = updatedIssue.assignees_list;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
|
2
web/types/issues.d.ts
vendored
2
web/types/issues.d.ts
vendored
@ -80,7 +80,6 @@ export interface IIssue {
|
|||||||
archived_at: string;
|
archived_at: string;
|
||||||
assignees: string[];
|
assignees: string[];
|
||||||
assignee_details: IUser[];
|
assignee_details: IUser[];
|
||||||
assignees_list: string[];
|
|
||||||
attachment_count: number;
|
attachment_count: number;
|
||||||
attachments: any[];
|
attachments: any[];
|
||||||
issue_relations: IssueRelation[];
|
issue_relations: IssueRelation[];
|
||||||
@ -105,7 +104,6 @@ export interface IIssue {
|
|||||||
labels: string[];
|
labels: string[];
|
||||||
label_details: any[];
|
label_details: any[];
|
||||||
is_draft: boolean;
|
is_draft: boolean;
|
||||||
labels_list: string[];
|
|
||||||
links_list: IIssueLink[];
|
links_list: IIssueLink[];
|
||||||
link_count: number;
|
link_count: number;
|
||||||
module: string | null;
|
module: string | null;
|
||||||
|
13
web/types/modules.d.ts
vendored
13
web/types/modules.d.ts
vendored
@ -10,13 +10,7 @@ import type {
|
|||||||
linkDetails,
|
linkDetails,
|
||||||
} from "types";
|
} from "types";
|
||||||
|
|
||||||
export type TModuleStatus =
|
export type TModuleStatus = "backlog" | "planned" | "in-progress" | "paused" | "completed" | "cancelled";
|
||||||
| "backlog"
|
|
||||||
| "planned"
|
|
||||||
| "in-progress"
|
|
||||||
| "paused"
|
|
||||||
| "completed"
|
|
||||||
| "cancelled";
|
|
||||||
|
|
||||||
export interface IModule {
|
export interface IModule {
|
||||||
backlog_issues: number;
|
backlog_issues: number;
|
||||||
@ -38,7 +32,6 @@ export interface IModule {
|
|||||||
link_module: linkDetails[];
|
link_module: linkDetails[];
|
||||||
links_list: ModuleLink[];
|
links_list: ModuleLink[];
|
||||||
members: string[];
|
members: string[];
|
||||||
members_list: string[];
|
|
||||||
members_detail: IUserLite[];
|
members_detail: IUserLite[];
|
||||||
is_favorite: boolean;
|
is_favorite: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
@ -80,8 +73,6 @@ export type ModuleLink = {
|
|||||||
url: string;
|
url: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SelectModuleType =
|
export type SelectModuleType = (IModule & { actionType: "edit" | "delete" | "create-issue" }) | undefined;
|
||||||
| (IModule & { actionType: "edit" | "delete" | "create-issue" })
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
export type SelectIssue = (IIssue & { actionType: "edit" | "delete" | "create" }) | undefined;
|
export type SelectIssue = (IIssue & { actionType: "edit" | "delete" | "create" }) | undefined;
|
||||||
|
1
web/types/pages.d.ts
vendored
1
web/types/pages.d.ts
vendored
@ -14,7 +14,6 @@ export interface IPage {
|
|||||||
is_favorite: boolean;
|
is_favorite: boolean;
|
||||||
label_details: IIssueLabels[];
|
label_details: IIssueLabels[];
|
||||||
labels: string[];
|
labels: string[];
|
||||||
labels_list: string[];
|
|
||||||
name: string;
|
name: string;
|
||||||
owned_by: string;
|
owned_by: string;
|
||||||
project: string;
|
project: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user