mirror of
https://github.com/makeplane/plane.git
synced 2026-07-13 05:49:40 +02:00
[WEB-3031] fix: project overview description activity (#2089)
* fix: project overview description activity * fix: project overview metrics * chore: project settings ux updated
This commit is contained in:
committed by
GitHub
parent
73b25bad2e
commit
bc401457c7
@@ -50,7 +50,7 @@ def track_description(
|
||||
project_activities,
|
||||
epoch,
|
||||
):
|
||||
if current_instance.get("description") != requested_data.get("description"):
|
||||
if current_instance.get("description_html") != requested_data.get("description_html"):
|
||||
last_activity = (
|
||||
WorkspaceActivity.objects.filter(project_id=project_id)
|
||||
.order_by("-created_at")
|
||||
@@ -58,7 +58,7 @@ def track_description(
|
||||
)
|
||||
if (
|
||||
last_activity is not None
|
||||
and last_activity.field == "description"
|
||||
and last_activity.field == "description_html"
|
||||
and actor_id == str(last_activity.actor_id)
|
||||
):
|
||||
last_activity.created_at = timezone.now()
|
||||
@@ -68,8 +68,8 @@ def track_description(
|
||||
WorkspaceActivity(
|
||||
actor_id=actor_id,
|
||||
verb="updated",
|
||||
old_value=current_instance.get("description"),
|
||||
new_value=requested_data.get("description"),
|
||||
old_value=current_instance.get("description_html"),
|
||||
new_value=requested_data.get("description_html"),
|
||||
field="description",
|
||||
project_id=project_id,
|
||||
workspace_id=workspace_id,
|
||||
@@ -567,7 +567,7 @@ def update_project_activity(
|
||||
):
|
||||
project_activity_MAPPER = {
|
||||
"name": track_name,
|
||||
"description": track_description,
|
||||
"description_html": track_description,
|
||||
"target_date": track_target_date,
|
||||
"start_date": track_start_date,
|
||||
"priority": track_priority,
|
||||
|
||||
@@ -261,7 +261,7 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
||||
<span className="text-xs text-red-500">{errors?.name?.message}</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<h4 className="text-sm">Description</h4>
|
||||
<h4 className="text-sm">Summary</h4>
|
||||
<Controller
|
||||
name="description"
|
||||
control={control}
|
||||
@@ -270,7 +270,7 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
||||
id="description"
|
||||
name="description"
|
||||
value={value}
|
||||
placeholder="Enter project description"
|
||||
placeholder="Enter project summary"
|
||||
onChange={onChange}
|
||||
className="min-h-[102px] text-sm font-medium"
|
||||
hasError={Boolean(errors?.description)}
|
||||
|
||||
@@ -1,37 +1,15 @@
|
||||
import useSWR from "swr";
|
||||
import { TStateAnalytics } from "@plane/types";
|
||||
import { Loader } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
import { ProgressSection } from "@/plane-web/components/common/layout/main/sections/progress-root";
|
||||
import projectService from "@/plane-web/services/project/project.service";
|
||||
import { TProject } from "@/plane-web/types";
|
||||
import { NoStats } from "./no-data";
|
||||
|
||||
type TStatBlockProp = {
|
||||
title: string;
|
||||
stat: number;
|
||||
color: string;
|
||||
percentage: number;
|
||||
};
|
||||
type TStatsTodayProps = {
|
||||
workspaceSlug: string;
|
||||
project: TProject;
|
||||
};
|
||||
|
||||
const StatBlock = (props: TStatBlockProp) => {
|
||||
const { title, stat, color, percentage } = props;
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex">
|
||||
<div className={`${color} w-[10px] h-[10px] flex mr-2 my-auto rounded-sm`} />
|
||||
<div className="font-medium text-sm">{title}</div>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<div className="text-md font-bold">{stat}</div>
|
||||
<div className="text-sm font-medium text-custom-text-350 my-auto">{percentage}%</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const StatsToday = (props: TStatsTodayProps) => {
|
||||
const { workspaceSlug, project } = props;
|
||||
|
||||
@@ -45,100 +23,13 @@ export const StatsToday = (props: TStatsTodayProps) => {
|
||||
}
|
||||
);
|
||||
|
||||
const stats = [
|
||||
{
|
||||
title: "Overdue",
|
||||
stat: analytics?.overdue_issues,
|
||||
color: "#FF3333",
|
||||
},
|
||||
{
|
||||
title: "Backlog",
|
||||
stat: analytics?.backlog_issues,
|
||||
color: "#EBEDF2",
|
||||
},
|
||||
{
|
||||
title: "Unstarted",
|
||||
stat: analytics?.unstarted_issues,
|
||||
color: "#6E6E6E",
|
||||
},
|
||||
{
|
||||
title: "Started",
|
||||
stat: analytics?.started_issues,
|
||||
color: "#FF9500",
|
||||
},
|
||||
{
|
||||
title: "Completed",
|
||||
stat: analytics?.completed_issues,
|
||||
color: "#26D950",
|
||||
},
|
||||
];
|
||||
|
||||
return isLoading ? (
|
||||
<Loader className="flex flex-col gap-4 py-4">
|
||||
<Loader.Item height="125px" width="100%" />
|
||||
</Loader>
|
||||
) : (
|
||||
<div className="mt-4 mx-2 border-y border-custom-border-200 py-4">
|
||||
<div className="text-base text-custom-text-100 font-medium">Metrics as of today</div>
|
||||
{(!analytics || project.total_issues === 0) && <NoStats workspaceSlug={workspaceSlug} projectId={project?.id} />}
|
||||
{analytics && project.total_issues > 0 && (
|
||||
<div className="text-custom-text-300 mt-4">
|
||||
{/* Progress bar */}
|
||||
<div className="flex w-full h-[14px] rounded gap-[2px]">
|
||||
{stats.map((stat) => (
|
||||
<div
|
||||
key={stat.title}
|
||||
className={cn(`h-full rounded`)}
|
||||
style={{
|
||||
width: `${stat.stat ? Math.round((stat.stat * 100) / project.total_issues) : 0}%`,
|
||||
backgroundColor: `${stat.color}`,
|
||||
opacity: 0.5,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Numbers */}
|
||||
<div className="flex mt-6 w-[90%] justify-between px-4">
|
||||
<StatBlock
|
||||
title="Overdue"
|
||||
stat={analytics?.overdue_issues}
|
||||
color={"bg-[#FF3333]"}
|
||||
percentage={Math.round(analytics?.overdue_issues / project.total_issues) * 100 || 0}
|
||||
/>
|
||||
|
||||
<div className="relative border-l-2 pl-10 flex ">
|
||||
<div className="absolute -left-2 top-[18px] font-medium text-custom-text-350 rotate-[270deg] text-[10px] tracking-widest">
|
||||
STATUS
|
||||
</div>
|
||||
<StatBlock
|
||||
title="Backlog"
|
||||
stat={analytics?.backlog_issues}
|
||||
color={"bg-[#EBEDF2]"}
|
||||
percentage={Math.round(analytics?.backlog_issues / project.total_issues) * 100 || 0}
|
||||
/>
|
||||
</div>
|
||||
<StatBlock
|
||||
title="Unstarted"
|
||||
stat={analytics?.unstarted_issues}
|
||||
color={"bg-[#6E6E6E]"}
|
||||
percentage={Math.round(analytics?.unstarted_issues / project.total_issues) * 100 || 0}
|
||||
/>
|
||||
<StatBlock
|
||||
title="Started"
|
||||
stat={analytics?.started_issues}
|
||||
color={"bg-[#FF9500]"}
|
||||
percentage={Math.round(analytics?.started_issues / project.total_issues) * 100 || 0}
|
||||
/>
|
||||
<StatBlock
|
||||
title="Completed"
|
||||
stat={analytics?.completed_issues}
|
||||
color={"bg-[#26D950]"}
|
||||
percentage={Math.round(analytics?.completed_issues / project.total_issues) * 100 || 0}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<ProgressSection data={analytics as TStateAnalytics} title="Metrics as of today" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user