mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: no estimates option, estimates activity (#838)
This commit is contained in:
parent
61761fedc5
commit
e23075b7b9
@ -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") {
|
||||||
|
@ -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}>
|
||||||
|
@ -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") {
|
||||||
|
@ -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,
|
||||||
|
@ -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" />
|
||||||
|
@ -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" />
|
||||||
|
@ -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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
2
apps/app/types/issues.d.ts
vendored
2
apps/app/types/issues.d.ts
vendored
@ -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: {
|
||||||
|
Loading…
Reference in New Issue
Block a user