snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:14:58 +05:00
commit 23059a1de3
5252 changed files with 573834 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { FC, ReactNode } from "react";
import { HierarchyOutline } from "@makeplane/propel/icons";
// types
import { Tooltip } from "@makeplane/propel/components/tooltip";
import type { TWorkspaceBaseActivity } from "@plane/types";
// ui
// helpers
import { renderFormattedTime, renderFormattedDate, calculateTimeAgo } from "@plane/utils";
// hooks
import { usePlatformOS } from "@/hooks/use-platform-os";
// local components
import { User } from "./user";
type TActivityBlockComponent = {
icon?: FC<{ className?: string }>;
activity: TWorkspaceBaseActivity;
ends: "top" | "bottom" | undefined;
children: ReactNode;
customUserName?: string;
};
export function ActivityBlockComponent(props: TActivityBlockComponent) {
const { icon: Icon, activity, ends, children, customUserName } = props;
// hooks
const { isMobile } = usePlatformOS();
if (!activity) return <></>;
return (
<div
className={`relative flex items-start gap-2 text-caption-sm-regular ${
ends === "top" ? `pb-3` : ends === "bottom" ? `pt-3` : `py-3`
}`}
>
<div className="z-[4] mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-lg border border-subtle text-secondary shadow-raised-100">
{Icon ? <Icon className="h-3.5 w-3.5 shrink-0" /> : <HierarchyOutline className="h-3.5 w-3.5 shrink-0" />}
</div>
<div className="w-full text-secondary">
<div className="line-clamp-2">
<User activity={activity} customUserName={customUserName} /> {children}
</div>
<div className="mt-1">
<Tooltip
label={`${renderFormattedDate(activity.created_at)}, ${renderFormattedTime(activity.created_at)}`}
disabled={isMobile}
>
<span className="cursor-help font-medium whitespace-nowrap text-tertiary">
{calculateTimeAgo(activity.created_at)}
</span>
</Tooltip>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { observer } from "mobx-react";
import type { TProjectActivity } from "@plane/types";
import { ActivityBlockComponent } from "./activity-block";
import { iconsMap, messages } from "./helper";
type TActivityItem = {
activity: TProjectActivity;
showProject?: boolean;
ends?: "top" | "bottom" | undefined;
};
export const ActivityItem = observer(function ActivityItem(props: TActivityItem) {
const { activity, ends } = props;
if (!activity) return null;
const activityType = activity.field;
if (!activityType) return null;
const { message, customUserName } = messages(activity);
const icon = iconsMap[activityType] || iconsMap.default;
return (
<ActivityBlockComponent icon={icon} activity={activity} ends={ends} customUserName={customUserName}>
<>{message}</>
</ActivityBlockComponent>
);
});

View File

@@ -0,0 +1,291 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { FC, ReactNode } from "react";
import {
AlignLeftOutline,
ArchiveOutline,
AttachOutline,
ClockOutline,
CyclesOutline,
DocumentationOutline,
DueDateOutline,
EstimateOutline,
GitBranchOutline,
GlobeOutline,
GridOutline,
HashOutline,
HierarchyOutline,
InboxOutline,
IntakeOutline,
LabelsOutline,
LinkOutline,
MembersOutline,
ModuleOutline,
PriorityOutline,
RefreshOutline,
StartDateOutline,
StateOutline,
SubscribeOutline,
TextOutline,
TimeTrackingOutline,
ToDoOutline,
WorkItemsOutline,
} from "@makeplane/propel/icons";
// components
import { store } from "@/lib/store-context";
import type { TProjectActivity } from "@plane/types";
type ActivityIconMap = {
[key: string]: FC<{ className?: string }>;
};
export const iconsMap: ActivityIconMap = {
priority: PriorityOutline,
archived_at: ArchiveOutline,
restored: RefreshOutline,
link: LinkOutline,
start_date: StartDateOutline,
target_date: DueDateOutline,
label: LabelsOutline,
inbox: InboxOutline,
description: AlignLeftOutline,
assignee: MembersOutline,
attachment: AttachOutline,
name: TextOutline,
state: StateOutline,
estimate: EstimateOutline,
cycle: CyclesOutline,
module: ModuleOutline,
page: DocumentationOutline,
network: GlobeOutline,
identifier: HashOutline,
timezone: ClockOutline,
is_project_updates_enabled: SubscribeOutline,
is_epic_enabled: GridOutline,
is_workflow_enabled: GitBranchOutline,
is_time_tracking_enabled: TimeTrackingOutline,
is_issue_type_enabled: ToDoOutline,
default: HierarchyOutline,
module_view: ModuleOutline,
cycle_view: CyclesOutline,
issue_views_view: WorkItemsOutline,
page_view: DocumentationOutline,
intake_view: IntakeOutline,
};
export const messages = (activity: TProjectActivity): { message: string | ReactNode; customUserName?: string } => {
const activityType = activity.field;
const newValue = activity.new_value;
const oldValue = activity.old_value;
const verb = activity.verb;
const workspaceDetail = store.workspaceRoot.getWorkspaceById(activity.workspace);
const getBooleanActionText = (value: string | undefined) => {
if (value === "true") return "enabled";
if (value === "false") return "disabled";
return verb;
};
switch (activityType) {
case "priority":
return {
message: (
<>
set the priority to <span className="font-medium text-primary">{newValue || "none"}</span>
</>
),
};
case "archived_at":
return {
message: newValue === "restore" ? "restored the project" : "archived the project",
customUserName: newValue === "archive" ? "Plane" : undefined,
};
case "name":
return {
message: (
<>
renamed the project to <span className="font-medium text-primary">{newValue}</span>
</>
),
};
case "description":
return {
message: newValue ? "updated the project description" : "removed the project description",
};
case "start_date":
return {
message: (
<>
{newValue ? (
<>
set the start date to <span className="font-medium text-primary">{newValue}</span>
</>
) : (
"removed the start date"
)}
</>
),
};
case "target_date":
return {
message: (
<>
{newValue ? (
<>
set the target date to <span className="font-medium text-primary">{newValue}</span>
</>
) : (
"removed the target date"
)}
</>
),
};
case "state":
return {
message: (
<>
set the state to <span className="font-medium text-primary">{newValue || "none"}</span>
</>
),
};
case "estimate":
return {
message: (
<>
{newValue ? (
<>
set the estimate point to <span className="font-medium text-primary">{newValue}</span>
</>
) : (
<>
removed the estimate point
{oldValue && (
<>
{" "}
<span className="font-medium text-primary">{oldValue}</span>
</>
)}
</>
)}
</>
),
};
case "cycles":
return {
message: (
<>
<span>
{verb} this project {verb === "removed" ? "from" : "to"} the cycle{" "}
</span>
{verb !== "removed" ? (
<a
href={`/${workspaceDetail?.slug}/projects/${activity.project}/cycles/${activity.new_identifier}`}
target="_blank"
rel="noopener noreferrer"
className="inline-flex font-medium text-primary"
>
{activity.new_value}
</a>
) : (
<span className="font-medium text-primary">{activity.old_value || "Unknown cycle"}</span>
)}
</>
),
};
case "modules":
return {
message: (
<>
<span>
{verb} this project {verb === "removed" ? "from" : "to"} the module{" "}
</span>
<span className="font-medium text-primary">
{verb === "removed" ? oldValue : newValue || "Unknown module"}
</span>
</>
),
};
case "labels":
return {
message: (
<>
{verb} the label{" "}
<span className="font-medium text-primary">{newValue || oldValue || "Untitled label"}</span>
</>
),
};
case "inbox":
return {
message: <>{newValue ? "enabled" : "disabled"} inbox</>,
};
case "page":
return {
message: (
<>
{newValue ? "created" : "removed"} the project page{" "}
<span className="font-medium text-primary">{newValue || oldValue || "Untitled page"}</span>
</>
),
};
case "network":
return {
message: <>{newValue ? "enabled" : "disabled"} network access</>,
};
case "identifier":
return {
message: (
<>
updated project identifier to <span className="font-medium text-primary">{newValue || "none"}</span>
</>
),
};
case "timezone":
return {
message: (
<>
changed project timezone to <span className="font-medium text-primary">{newValue || "default"}</span>
</>
),
};
case "module_view":
case "cycle_view":
case "issue_views_view":
case "page_view":
case "intake_view":
return {
message: (
<>
{getBooleanActionText(newValue)} {activityType.replace(/_view$/, "").replace(/_/g, " ")} view
</>
),
};
case "is_project_updates_enabled":
return {
message: <>{getBooleanActionText(newValue)} project updates</>,
};
case "is_epic_enabled":
return {
message: <>{getBooleanActionText(newValue)} epics</>,
};
case "is_workflow_enabled":
return {
message: <>{getBooleanActionText(newValue)} custom workflow</>,
};
case "is_time_tracking_enabled":
return {
message: <>{getBooleanActionText(newValue)} time tracking</>,
};
case "is_issue_type_enabled":
return {
message: <>{getBooleanActionText(newValue)} work item types</>,
};
default:
return {
message: `${verb} ${activityType?.replace(/_/g, " ")} `,
};
}
};

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { observer } from "mobx-react";
import Link from "next/link";
// types
import type { TWorkspaceBaseActivity } from "@plane/types";
// store hooks
import { useMember } from "@/hooks/store/use-member";
import { useWorkspace } from "@/hooks/store/use-workspace";
type TUser = {
activity: TWorkspaceBaseActivity;
customUserName?: string;
};
export const User = observer(function User(props: TUser) {
const { activity, customUserName } = props;
// store hooks
const { getUserDetails } = useMember();
const { getWorkspaceById } = useWorkspace();
// derived values
const actorDetail = getUserDetails(activity.actor);
const workspaceDetail = getWorkspaceById(activity.workspace);
return (
<>
{customUserName || actorDetail?.display_name?.includes("-intake") ? (
<span className="font-medium text-primary">{customUserName || "Plane"}</span>
) : (
<Link
href={`/${workspaceDetail?.slug}/profile/${actorDetail?.id}`}
className="font-medium text-primary hover:underline"
>
{actorDetail?.display_name}
</Link>
)}
</>
);
});