chore: no estimates option, estimates activity (#838)

This commit is contained in:
Aaryan Khandelwal 2023-04-17 11:30:48 +05:30 committed by GitHub
parent 61761fedc5
commit e23075b7b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 97 additions and 53 deletions

View File

@ -73,6 +73,10 @@ const activityDetails: {
message: "updated the description.", message: "updated the description.",
icon: <ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-gray-500" aria-hidden="true" />, icon: <ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-gray-500" aria-hidden="true" />,
}, },
estimate_point: {
message: "set the estimate point to",
icon: <PlayIcon className="h-3 w-3 text-gray-500 -rotate-90" aria-hidden="true" />,
},
target_date: { target_date: {
message: "set the due date to", message: "set the due date to",
icon: <CalendarDaysIcon className="h-3 w-3 text-gray-500" aria-hidden="true" />, icon: <CalendarDaysIcon className="h-3 w-3 text-gray-500" aria-hidden="true" />,
@ -136,8 +140,6 @@ export const Feeds: React.FC<any> = ({ activities }) => (
action = `${activity.verb} the`; action = `${activity.verb} the`;
} else if (activity.field === "link") { } else if (activity.field === "link") {
action = `${activity.verb} the`; action = `${activity.verb} the`;
} else if (activity.field === "estimate") {
action = "updated the";
} }
// for values that are after the action clause // for values that are after the action clause
let value: any = activity.new_value ? activity.new_value : activity.old_value; let value: any = activity.new_value ? activity.new_value : activity.old_value;
@ -188,8 +190,10 @@ export const Feeds: React.FC<any> = ({ activities }) => (
value = "attachment"; value = "attachment";
} else if (activity.field === "link") { } else if (activity.field === "link") {
value = "link"; value = "link";
} else if (activity.field === "estimate") { } else if (activity.field === "estimate_point") {
value = "estimate"; value = activity.new_value
? activity.new_value + ` Point${parseInt(activity.new_value ?? "", 10) > 1 ? "s" : ""}`
: "None";
} }
if (activity.field === "comment") { if (activity.field === "comment") {

View File

@ -388,36 +388,33 @@ export const IssuesView: React.FC<Props> = ({
handleClose={() => setTransferIssuesModal(false)} handleClose={() => setTransferIssuesModal(false)}
isOpen={transferIssuesModal} isOpen={transferIssuesModal}
/> />
<div> <div className="flex items-center justify-between gap-2 -mt-2">
<div className="flex items-center justify-between gap-2"> <FilterList filters={filters} setFilters={setFilters} />
<FilterList filters={filters} setFilters={setFilters} /> {Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length && (
{Object.keys(filters).length > 0 && <PrimaryButton
nullFilters.length !== Object.keys(filters).length && ( onClick={() => {
<PrimaryButton if (viewId) {
onClick={() => { setFilters({}, true);
if (viewId) { setToastAlert({
setFilters({}, true); title: "View updated",
setToastAlert({ message: "Your view has been updated",
title: "View updated", type: "success",
message: "Your view has been updated", });
type: "success", } else
}); setCreateViewModal({
} else query: filters,
setCreateViewModal({ });
query: filters, }}
}); className="flex items-center gap-2 text-sm"
}} >
className="flex items-center gap-2 text-sm" {!viewId && <PlusIcon className="h-4 w-4" />}
> {viewId ? "Update" : "Save"} view
{!viewId && <PlusIcon className="h-4 w-4" />} </PrimaryButton>
{viewId ? "Update" : "Save"} view )}
</PrimaryButton>
)}
</div>
</div> </div>
{Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length && ( {Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length && (
<div className="mb-5 border-t" /> <div className="my-4 border-t" />
)} )}
<DragDropContext onDragEnd={handleOnDragEnd}> <DragDropContext onDragEnd={handleOnDragEnd}>

View File

@ -29,6 +29,7 @@ import { addSpaceIfCamelCase } from "helpers/string.helper";
// types // types
import { IIssueComment, IIssueLabels } from "types"; import { IIssueComment, IIssueLabels } from "types";
import { PROJECT_ISSUES_ACTIVITY, PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; import { PROJECT_ISSUES_ACTIVITY, PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
import useEstimateOption from "hooks/use-estimate-option";
const activityDetails: { const activityDetails: {
[key: string]: { [key: string]: {
@ -56,6 +57,10 @@ const activityDetails: {
message: "set the cycle to", message: "set the cycle to",
icon: <CyclesIcon height="12" width="12" color="#6b7280" />, icon: <CyclesIcon height="12" width="12" color="#6b7280" />,
}, },
estimate_point: {
message: "set the estimate point to",
icon: <PlayIcon className="h-3 w-3 text-gray-500 -rotate-90" aria-hidden="true" />,
},
labels: { labels: {
icon: <TagIcon height="12" width="12" color="#6b7280" />, icon: <TagIcon height="12" width="12" color="#6b7280" />,
}, },
@ -107,6 +112,8 @@ export const IssueActivitySection: React.FC<Props> = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query; const { workspaceSlug, projectId, issueId } = router.query;
const { isEstimateActive, estimatePoints } = useEstimateOption();
const { data: issueActivities, mutate: mutateIssueActivities } = useSWR( const { data: issueActivities, mutate: mutateIssueActivities } = useSWR(
workspaceSlug && projectId && issueId ? PROJECT_ISSUES_ACTIVITY(issueId as string) : null, workspaceSlug && projectId && issueId ? PROJECT_ISSUES_ACTIVITY(issueId as string) : null,
workspaceSlug && projectId && issueId workspaceSlug && projectId && issueId
@ -278,8 +285,14 @@ export const IssueActivitySection: React.FC<Props> = () => {
value = "attachment"; value = "attachment";
} else if (activityItem.field === "link") { } else if (activityItem.field === "link") {
value = "link"; value = "link";
} else if (activityItem.field === "estimate") { } else if (activityItem.field === "estimate_point") {
value = "estimate"; value = activityItem.new_value
? isEstimateActive
? estimatePoints.find((e) => e.key === parseInt(activityItem.new_value ?? "", 10))
?.value
: activityItem.new_value +
` Point${parseInt(activityItem.new_value ?? "", 10) > 1 ? "s" : ""}`
: "None";
} }
if ("field" in activityItem && activityItem.field !== "updated_by") { if ("field" in activityItem && activityItem.field !== "updated_by") {

View File

@ -48,7 +48,7 @@ const defaultValues: Partial<IIssue> = {
name: "", name: "",
description: "", description: "",
description_html: "<p></p>", description_html: "<p></p>",
estimate_point: 0, estimate_point: null,
state: "", state: "",
cycle: null, cycle: null,
priority: null, priority: null,

View File

@ -8,8 +8,8 @@ import { PlayIcon } from "@heroicons/react/24/outline";
import useEstimateOption from "hooks/use-estimate-option"; import useEstimateOption from "hooks/use-estimate-option";
type Props = { type Props = {
value: number; value: number | null;
onChange: (value: number) => void; onChange: (value: number | null) => void;
}; };
export const IssueEstimateSelect: React.FC<Props> = ({ value, onChange }) => { export const IssueEstimateSelect: React.FC<Props> = ({ value, onChange }) => {
@ -24,18 +24,26 @@ export const IssueEstimateSelect: React.FC<Props> = ({ value, onChange }) => {
<div className="flex items-center gap-2 text-xs"> <div className="flex items-center gap-2 text-xs">
<PlayIcon className="h-4 w-4 text-gray-500 -rotate-90" /> <PlayIcon className="h-4 w-4 text-gray-500 -rotate-90" />
<span className={`${value ? "text-gray-600" : "text-gray-500"}`}> <span className={`${value ? "text-gray-600" : "text-gray-500"}`}>
{estimatePoints?.find((e) => e.key === value)?.value ?? "Estimate points"} {estimatePoints?.find((e) => e.key === value)?.value ?? "Estimate"}
</span> </span>
</div> </div>
} }
onChange={onChange} onChange={onChange}
position="right" position="right"
width="w-full min-w-[6rem]" width="w-full min-w-[8rem]"
noChevron noChevron
> >
<CustomSelect.Option value={null}>
<>
<span>
<PlayIcon className="h-4 w-4 -rotate-90" />
</span>
None
</>
</CustomSelect.Option>
{estimatePoints && {estimatePoints &&
estimatePoints.map((point) => ( estimatePoints.map((point) => (
<CustomSelect.Option className="w-full " key={point.key} value={point.key}> <CustomSelect.Option key={point.key} value={point.key}>
<> <>
<span> <span>
<PlayIcon className="h-4 w-4 -rotate-90" /> <PlayIcon className="h-4 w-4 -rotate-90" />

View File

@ -1,17 +1,17 @@
import React from "react"; import React from "react";
// hooks
import useEstimateOption from "hooks/use-estimate-option";
// ui // ui
import { CustomSelect } from "components/ui"; import { CustomSelect } from "components/ui";
// icons // icons
import { BanknotesIcon, PlayIcon } from "@heroicons/react/24/outline"; import { PlayIcon } from "@heroicons/react/24/outline";
// types // types
import { UserAuth } from "types"; import { UserAuth } from "types";
import useEstimateOption from "hooks/use-estimate-option";
// constants
type Props = { type Props = {
value: number; value: number | null;
onChange: (val: number) => void; onChange: (val: number | null) => void;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -35,7 +35,7 @@ export const SidebarEstimateSelect: React.FC<Props> = ({ value, onChange, userAu
<div className="flex items-center gap-2 text-xs"> <div className="flex items-center gap-2 text-xs">
<PlayIcon className="h-4 w-4 text-gray-700 -rotate-90" /> <PlayIcon className="h-4 w-4 text-gray-700 -rotate-90" />
<span className={`${value ? "text-gray-600" : "text-gray-500"}`}> <span className={`${value ? "text-gray-600" : "text-gray-500"}`}>
{estimatePoints?.find((e) => e.key === value)?.value ?? "Estimate points"} {estimatePoints?.find((e) => e.key === value)?.value ?? "Estimate"}
</span> </span>
</div> </div>
} }
@ -44,9 +44,17 @@ export const SidebarEstimateSelect: React.FC<Props> = ({ value, onChange, userAu
width="w-full" width="w-full"
disabled={isNotAllowed} disabled={isNotAllowed}
> >
<CustomSelect.Option value={null}>
<>
<span>
<PlayIcon className="h-4 w-4 -rotate-90" />
</span>
None
</>
</CustomSelect.Option>
{estimatePoints && {estimatePoints &&
estimatePoints.map((point) => ( estimatePoints.map((point) => (
<CustomSelect.Option className="w-full " key={point.key} value={point.key}> <CustomSelect.Option key={point.key} value={point.key}>
<> <>
<span> <span>
<PlayIcon className="h-4 w-4 -rotate-90" /> <PlayIcon className="h-4 w-4 -rotate-90" />

View File

@ -294,7 +294,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
render={({ field: { value } }) => ( render={({ field: { value } }) => (
<SidebarEstimateSelect <SidebarEstimateSelect
value={value} value={value}
onChange={(val: number) => submitChanges({ estimate_point: val })} onChange={(val: number | null) => submitChanges({ estimate_point: val })}
userAuth={memberRole} userAuth={memberRole}
/> />
)} )}

View File

@ -58,7 +58,7 @@ export const ViewEstimateSelect: React.FC<Props> = ({
<Tooltip tooltipHeading="Estimate" tooltipContent={estimateValue}> <Tooltip tooltipHeading="Estimate" tooltipContent={estimateValue}>
<div className="flex items-center gap-1 text-gray-500"> <div className="flex items-center gap-1 text-gray-500">
<PlayIcon className="h-3.5 w-3.5 -rotate-90" /> <PlayIcon className="h-3.5 w-3.5 -rotate-90" />
{estimateValue} {estimateValue ?? "Estimate"}
</div> </div>
</Tooltip> </Tooltip>
} }
@ -67,11 +67,24 @@ export const ViewEstimateSelect: React.FC<Props> = ({
disabled={isNotAllowed} disabled={isNotAllowed}
position={position} position={position}
selfPositioned={selfPositioned} selfPositioned={selfPositioned}
width="w-full min-w-[6rem]" width="w-full min-w-[8rem]"
> >
<CustomSelect.Option value={null}>
<>
<span>
<PlayIcon className="h-4 w-4 -rotate-90" />
</span>
None
</>
</CustomSelect.Option>
{estimatePoints?.map((estimate) => ( {estimatePoints?.map((estimate) => (
<CustomSelect.Option key={estimate.id} value={estimate.key} className="capitalize"> <CustomSelect.Option key={estimate.id} value={estimate.key}>
<>{estimate.value}</> <>
<span>
<PlayIcon className="h-4 w-4 -rotate-90" />
</span>
{estimate.value}
</>
</CustomSelect.Option> </CustomSelect.Option>
))} ))}
</CustomSelect> </CustomSelect>

View File

@ -13,7 +13,7 @@ import { orderArrayBy } from "helpers/array.helper";
// fetch-keys // fetch-keys
import { ESTIMATE_POINTS_LIST } from "constants/fetch-keys"; import { ESTIMATE_POINTS_LIST } from "constants/fetch-keys";
const useEstimateOption = (estimateKey?: number) => { const useEstimateOption = (estimateKey?: number | null) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;

View File

@ -34,6 +34,7 @@ const defaultValues = {
name: "", name: "",
description: "", description: "",
description_html: "", description_html: "",
estimate_point: null,
state: "", state: "",
assignees_list: [], assignees_list: [],
priority: "low", priority: "low",

View File

@ -87,7 +87,7 @@ export interface IIssue {
description: any; description: any;
description_html: any; description_html: any;
description_stripped: any; description_stripped: any;
estimate_point: number; estimate_point: number | null;
id: string; id: string;
issue_cycle: IIssueCycle | null; issue_cycle: IIssueCycle | null;
issue_link: { issue_link: {