Merge pull request #863 from makeplane/sync/ce-ee

sync: community changes
This commit is contained in:
Satish Gandham
2024-08-19 13:56:27 +05:30
committed by GitHub
55 changed files with 269 additions and 158 deletions
+1
View File
@@ -140,6 +140,7 @@ export interface IIssueActivity {
name: string;
priority: string | null;
sequence_id: string;
type_id: string;
} | null;
new_identifier: string | null;
new_value: string | null;
+5
View File
@@ -60,4 +60,9 @@ export type TIssueActivityComment =
id: string;
activity_type: "WORKLOG";
created_at?: string;
}
| {
id: string;
activity_type: "ISSUE_ADDITIONAL_PROPERTIES_ACTIVITY";
created_at?: string;
};
+1
View File
@@ -144,4 +144,5 @@ export interface ISearchIssueResponse {
state__group: TStateGroups;
state__name: string;
workspace__slug: string;
type_id: string;
}
+1
View File
@@ -118,6 +118,7 @@ export interface IWorkspaceIssueSearchResult {
project_id: string;
sequence_id: number;
workspace__slug: string;
type_id: string;
}
export interface IWorkspacePageSearchResult {
+4 -7
View File
@@ -5,7 +5,6 @@ import useFontFaceObserver from "use-font-face-observer";
import { LUCIDE_ICONS_LIST } from "./icons";
// helpers
import { emojiCodeToUnicode } from "./helpers";
import { cn } from "../../helpers";
type TLogoProps = {
in_use: "emoji" | "icon";
@@ -23,11 +22,10 @@ type Props = {
logo: TLogoProps;
size?: number;
type?: "lucide" | "material";
customColor?: string;
};
export const Logo: FC<Props> = (props) => {
const { logo, size = 16, customColor, type = "material" } = props;
const { logo, size = 16, type = "material" } = props;
// destructuring the logo object
const { in_use, emoji, icon } = logo;
@@ -74,20 +72,19 @@ export const Logo: FC<Props> = (props) => {
{lucideIcon && (
<lucideIcon.element
style={{
color: !customColor ? color : undefined,
color: color,
height: size,
width: size,
}}
className={cn(customColor)}
/>
)}
</>
) : (
<span
className={cn("material-symbols-rounded", customColor)}
className="material-symbols-rounded"
style={{
fontSize: size,
color: !customColor ? color : undefined,
color: color,
scale: "115%",
}}
>
@@ -1 +1,2 @@
export * from "./issue-identifier";
export * from "./issue-properties-activity";
@@ -4,29 +4,41 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useIssueDetail, useProject } from "@/hooks/store";
type TIssueIdentifierProps = {
issueId: string;
type TIssueIdentifierBaseProps = {
projectId: string;
iconSize?: number;
iconContainerSize?: number;
size?: "xs" | "sm" | "md" | "lg";
textContainerClassName?: string;
};
type TIssueIdentifierFromStore = TIssueIdentifierBaseProps & {
issueId: string;
};
type TIssueIdentifierWithDetails = TIssueIdentifierBaseProps & {
issueTypeId?: string | null;
projectIdentifier: string;
issueSequenceId: string | number;
};
type TIssueIdentifierProps = TIssueIdentifierFromStore | TIssueIdentifierWithDetails;
export const IssueIdentifier: React.FC<TIssueIdentifierProps> = observer((props) => {
const { issueId, projectId, textContainerClassName } = props;
const { projectId, textContainerClassName } = props;
// store hooks
const { getProjectById } = useProject();
const { getProjectIdentifierById } = useProject();
const {
issue: { getIssueById },
} = useIssueDetail();
// Determine if the component is using store data or not
const isUsingStoreData = "issueId" in props;
// derived values
const issue = getIssueById(issueId);
const projectDetails = getProjectById(projectId);
const issue = isUsingStoreData ? getIssueById(props.issueId) : null;
const projectIdentifier = isUsingStoreData ? getProjectIdentifierById(projectId) : props.projectIdentifier;
const issueSequenceId = isUsingStoreData ? issue?.sequence_id : props.issueSequenceId;
return (
<div className="flex items-center space-x-2">
<span className={cn("text-xs font-medium text-custom-text-300", textContainerClassName)}>
{projectDetails?.identifier}-{issue?.sequence_id}
<span className={cn("text-base font-medium text-custom-text-300", textContainerClassName)}>
{projectIdentifier}-{issueSequenceId}
</span>
</div>
);
@@ -0,0 +1 @@
export * from "./root";
@@ -0,0 +1,8 @@
import { FC } from "react";
type TIssueAdditionalPropertiesActivity = {
activityId: string;
ends: "top" | "bottom" | undefined;
};
export const IssueAdditionalPropertiesActivity: FC<TIssueAdditionalPropertiesActivity> = () => <></>;
@@ -7,10 +7,11 @@ import { useParams } from "next/navigation";
import useSWR from "swr";
import { FolderPlus, Search, Settings } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
// icons
// types
import { IWorkspaceSearchResults } from "@plane/types";
// hooks
// ui
import { LayersIcon, Loader, ToggleSwitch, Tooltip } from "@plane/ui";
// components
import {
ChangeIssueAssignee,
ChangeIssuePriority,
@@ -23,8 +24,11 @@ import {
CommandPaletteWorkspaceSettingsActions,
} from "@/components/command-palette";
import { EmptyState } from "@/components/empty-state";
// constants
import { EmptyStateType } from "@/constants/empty-state";
// fetch-keys
import { ISSUE_DETAILS } from "@/constants/fetch-keys";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
import useDebounce from "@/hooks/use-debounce";
@@ -36,12 +40,6 @@ import { WorkspaceService } from "@/plane-web/services";
// services
import { IssueService } from "@/services/issue";
// ui
// components
// types
// fetch-keys
// constants
const workspaceService = new WorkspaceService();
const issueService = new IssueService();
@@ -9,6 +9,7 @@ import {
IWorkspaceProjectSearchResult,
IWorkspaceSearchResult,
} from "@plane/types";
// ui
import { ContrastIcon, DiceIcon } from "@plane/ui";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
@@ -37,10 +38,10 @@ export const commandGroups: {
itemName: (issue: IWorkspaceIssueSearchResult) => (
<div className="flex gap-2">
<IssueIdentifier
issueId={issue.id}
projectId={issue.project_id}
iconSize={10}
iconContainerSize={16}
issueTypeId={issue.type_id}
projectIdentifier={issue.project__identifier}
issueSequenceId={issue.sequence_id}
textContainerClassName="text-xs"
/>{" "}
{issue.name}
+22 -22
View File
@@ -165,7 +165,7 @@ const activityDetails: {
</>
);
},
icon: <Users2Icon size={12} color="#6b7280" aria-hidden="true" />,
icon: <Users2Icon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
archived_at: {
message: (activity) => {
@@ -182,7 +182,7 @@ const activityDetails: {
</>
);
},
icon: <ArchiveIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <ArchiveIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
attachment: {
message: (activity, showIssue) => {
@@ -219,7 +219,7 @@ const activityDetails: {
</>
);
},
icon: <PaperclipIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <PaperclipIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
description: {
message: (activity, showIssue) => (
@@ -233,7 +233,7 @@ const activityDetails: {
)}
</>
),
icon: <MessageSquareIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <MessageSquareIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
estimate_point: {
message: (activity, showIssue) => {
@@ -262,7 +262,7 @@ const activityDetails: {
</>
);
},
icon: <TriangleIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <TriangleIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
issue: {
message: (activity) => {
@@ -279,7 +279,7 @@ const activityDetails: {
</>
);
},
icon: <LayersIcon width={12} height={12} color="#6b7280" aria-hidden="true" />,
icon: <LayersIcon width={12} height={12} className="text-custom-text-200" aria-hidden="true" />,
},
labels: {
message: (activity, showIssue, workspaceSlug) => {
@@ -320,7 +320,7 @@ const activityDetails: {
</>
);
},
icon: <TagIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <TagIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
link: {
message: (activity, showIssue) => {
@@ -385,7 +385,7 @@ const activityDetails: {
</>
);
},
icon: <Link2Icon size={12} color="#6b7280" aria-hidden="true" />,
icon: <Link2Icon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
cycles: {
message: (activity, showIssue, workspaceSlug) => {
@@ -435,7 +435,7 @@ const activityDetails: {
</>
);
},
icon: <ContrastIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <ContrastIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
modules: {
message: (activity, showIssue, workspaceSlug) => {
@@ -482,7 +482,7 @@ const activityDetails: {
</>
);
},
icon: <DiceIcon className="h-3 w-3 !text-[#6b7280]" aria-hidden="true" />,
icon: <DiceIcon className="h-3 w-3 !text-custom-text-200" aria-hidden="true" />,
},
name: {
message: (activity, showIssue) => (
@@ -496,7 +496,7 @@ const activityDetails: {
)}
</>
),
icon: <MessageSquareIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <MessageSquareIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
parent: {
message: (activity, showIssue) => {
@@ -527,7 +527,7 @@ const activityDetails: {
</>
);
},
icon: <UsersIcon className="h-3 w-3 !text-[#6b7280]" aria-hidden="true" />,
icon: <UsersIcon className="h-3 w-3 !text-custom-text-200" aria-hidden="true" />,
},
priority: {
message: (activity, showIssue) => (
@@ -544,7 +544,7 @@ const activityDetails: {
)}
</>
),
icon: <SignalMediumIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <SignalMediumIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
relates_to: {
message: (activity, showIssue) => {
@@ -563,7 +563,7 @@ const activityDetails: {
</>
);
},
icon: <RelatedIcon height="12" width="12" color="#6b7280" />,
icon: <RelatedIcon height="12" width="12" className="text-custom-text-200" />,
},
blocking: {
message: (activity, showIssue) => {
@@ -582,7 +582,7 @@ const activityDetails: {
</>
);
},
icon: <BlockerIcon height="12" width="12" color="#6b7280" />,
icon: <BlockerIcon height="12" width="12" className="text-custom-text-200" />,
},
blocked_by: {
message: (activity, showIssue) => {
@@ -601,7 +601,7 @@ const activityDetails: {
</>
);
},
icon: <BlockedIcon height="12" width="12" color="#6b7280" />,
icon: <BlockedIcon height="12" width="12" className="text-custom-text-200" />,
},
duplicate: {
message: (activity, showIssue) => {
@@ -620,7 +620,7 @@ const activityDetails: {
</>
);
},
icon: <CopyPlus size={12} color="#6b7280" />,
icon: <CopyPlus size={12} className="text-custom-text-200" />,
},
state: {
message: (activity, showIssue) => (
@@ -634,7 +634,7 @@ const activityDetails: {
)}
</>
),
icon: <LayoutGridIcon size={12} color="#6b7280" aria-hidden="true" />,
icon: <LayoutGridIcon size={12} className="text-custom-text-200" aria-hidden="true" />,
},
start_date: {
message: (activity, showIssue) => {
@@ -666,7 +666,7 @@ const activityDetails: {
</>
);
},
icon: <Calendar size={12} color="#6b7280" aria-hidden="true" />,
icon: <Calendar size={12} className="text-custom-text-200" aria-hidden="true" />,
},
target_date: {
message: (activity, showIssue) => {
@@ -697,7 +697,7 @@ const activityDetails: {
</>
);
},
icon: <Calendar size={12} color="#6b7280" aria-hidden="true" />,
icon: <Calendar size={12} className="text-custom-text-200" aria-hidden="true" />,
},
inbox: {
message: (activity, showIssue) => (
@@ -712,7 +712,7 @@ const activityDetails: {
{activity.verb === "2" && ` from intake by marking a duplicate issue.`}
</>
),
icon: <Intake className="size-3" color="#6b7280" aria-hidden="true" />,
icon: <Intake className="size-3 text-custom-text-200" aria-hidden="true" />,
},
};
@@ -734,7 +734,7 @@ export const ActivityMessage = ({ activity, showIssue = false }: ActivityMessage
{activityDetails[activity.field as keyof typeof activityDetails]?.message(
activity,
showIssue,
workspaceSlug ? workspaceSlug.toString() : activity.workspace_detail?.slug ?? ""
workspaceSlug ? workspaceSlug.toString() : (activity.workspace_detail?.slug ?? "")
)}
</>
);
@@ -2,6 +2,7 @@ import { observer } from "mobx-react";
import { Combobox } from "@headlessui/react";
// hooks
import { ISearchIssueResponse } from "@plane/types";
// plane web hooks
import { IssueIdentifier } from "@/plane-web/components/issues";
interface Props {
@@ -20,7 +21,7 @@ export const BulkDeleteIssuesModalItem: React.FC<Props> = observer((props: Props
as="div"
value={issue.id}
className={({ active }) =>
`flex cursor-pointer select-none items-center justify-between rounded-md px-3 py-2 ${
`flex cursor-pointer select-none items-center justify-between rounded-md px-3 py-2 my-0.5 ${
active ? "bg-custom-background-80 text-custom-text-100" : ""
}`
}
@@ -6,22 +6,21 @@ import { useParams } from "next/navigation";
import { SubmitHandler, useForm } from "react-hook-form";
import { Search } from "lucide-react";
import { Combobox, Dialog, Transition } from "@headlessui/react";
//plane
// types
import { ISearchIssueResponse, IUser } from "@plane/types";
// ui
import { Button, Loader, TOAST_TYPE, setToast } from "@plane/ui";
//components
// components
import { EmptyState } from "@/components/empty-state";
//constants
// constants
import { EmptyStateType } from "@/constants/empty-state";
import { EIssuesStoreType } from "@/constants/issue";
//hooks
// hooks
import { useIssues } from "@/hooks/store";
import useDebounce from "@/hooks/use-debounce";
// services
import { ProjectService } from "@/services/project";
// ui
// icons
// components
// local components
import { BulkDeleteIssuesModalItem } from "./bulk-delete-issues-modal-item";
type FormInput = {
@@ -10,6 +10,8 @@ import { Button, Loader, ToggleSwitch, Tooltip, TOAST_TYPE, setToast } from "@pl
// hooks
import useDebounce from "@/hooks/use-debounce";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// services
import { ProjectService } from "@/services/project";
// components
@@ -149,7 +151,13 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
key={issue.id}
className="flex items-center gap-1 whitespace-nowrap rounded-md border border-custom-border-200 bg-custom-background-80 py-1 pl-2 text-xs text-custom-text-100"
>
{issue.project__identifier}-{issue.sequence_id}
<IssueIdentifier
projectId={issue.project_id}
issueTypeId={issue.type_id}
projectIdentifier={issue.project__identifier}
issueSequenceId={issue.sequence_id}
textContainerClassName="text-xs text-custom-text-200"
/>
<button
type="button"
className="group p-1"
@@ -232,7 +240,7 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
htmlFor={`issue-${issue.id}`}
value={issue}
className={({ active }) =>
`group flex w-full cursor-pointer select-none items-center justify-between gap-2 rounded-md px-3 py-2 text-custom-text-200 ${
`group flex w-full cursor-pointer select-none items-center justify-between gap-2 rounded-md px-3 py-2 my-0.5 text-custom-text-200 ${
active ? "bg-custom-background-80 text-custom-text-100" : ""
} ${selected ? "text-custom-text-100" : ""}`
}
@@ -245,8 +253,14 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
backgroundColor: issue.state__color,
}}
/>
<span className="flex-shrink-0 text-xs">
{issue.project__identifier}-{issue.sequence_id}
<span className="flex-shrink-0">
<IssueIdentifier
projectId={issue.project_id}
issueTypeId={issue.type_id}
projectIdentifier={issue.project__identifier}
issueSequenceId={issue.sequence_id}
textContainerClassName="text-xs text-custom-text-200"
/>
</span>
{issue.name}
</div>
@@ -2,16 +2,16 @@
import isToday from "date-fns/isToday";
import { observer } from "mobx-react";
// types
import { TIssue, TWidgetIssue } from "@plane/types";
// hooks
// ui
import { Avatar, AvatarGroup, ControlLink, PriorityIcon } from "@plane/ui";
// helpers
import { findTotalDaysInRange, getDate, renderFormattedDate } from "@/helpers/date-time.helper";
// hooks
import { useIssueDetail, useMember, useProject } from "@/hooks/store";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// types
export type IssueListItemProps = {
issueId: string;
@@ -67,12 +67,12 @@ export const AssignedUpcomingIssueListItem: React.FC<IssueListItemProps> = obser
? blockedByIssues.length > 1
? `${blockedByIssues.length} blockers`
: blockedByIssueProjectDetails && (
<IssueIdentifier
issueId={blockedByIssues[0]?.id}
projectId={blockedByIssueProjectDetails?.id}
textContainerClassName="text-xs text-custom-text-200 font-medium"
/>
)
<IssueIdentifier
issueId={blockedByIssues[0]?.id}
projectId={blockedByIssueProjectDetails?.id}
textContainerClassName="text-xs text-custom-text-200 font-medium"
/>
)
: "-"}
</div>
</ControlLink>
@@ -126,12 +126,12 @@ export const AssignedOverdueIssueListItem: React.FC<IssueListItemProps> = observ
? blockedByIssues.length > 1
? `${blockedByIssues.length} blockers`
: blockedByIssueProjectDetails && (
<IssueIdentifier
issueId={blockedByIssues[0]?.id}
projectId={blockedByIssueProjectDetails?.id}
textContainerClassName="text-xs text-custom-text-200 font-medium"
/>
)
<IssueIdentifier
issueId={blockedByIssues[0]?.id}
projectId={blockedByIssueProjectDetails?.id}
textContainerClassName="text-xs text-custom-text-200 font-medium"
/>
)
: "-"}
</div>
</ControlLink>
@@ -74,23 +74,23 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
</Loader>
) : issuesList.length > 0 ? (
<>
<div className="mt-7 mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-12 gap-1 text-xs text-custom-text-300 pb-1">
<div className="mt-7 mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-12 gap-1 text-xs text-custom-text-300 pb-1">
<h6
className={cn("pl-1 flex items-center gap-1 col-span-7", {
"col-span-11": type === "assigned" && tab === "completed",
"col-span-9": type === "created" && tab === "completed",
className={cn("pl-1 flex items-center gap-1 col-span-7", {
"col-span-11": type === "assigned" && tab === "completed",
"col-span-9": type === "created" && tab === "completed",
})}
>
Issues
<span className="flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-medium rounded-xl px-2 flex items-center text-center justify-center">
<span className="flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-medium rounded-xl px-2 flex items-center text-center justify-center">
{widgetStats.count}
</span>
</h6>
<h6 className="text-center col-span-1">Priority</h6>
{["upcoming", "pending"].includes(tab) && <h6 className="text-center col-span-2">Due date</h6>}
{tab === "overdue" && <h6 className="text-center col-span-2">Due by</h6>}
{type === "assigned" && tab !== "completed" && <h6 className="text-center col-span-2">Blocked by</h6>}
{type === "created" && <h6 className="text-center col-span-2">Assigned to</h6>}
<h6 className="text-center col-span-1">Priority</h6>
{["upcoming", "pending"].includes(tab) && <h6 className="text-center col-span-2">Due date</h6>}
{tab === "overdue" && <h6 className="text-center col-span-2">Due by</h6>}
{type === "assigned" && tab !== "completed" && <h6 className="text-center col-span-2">Blocked by</h6>}
{type === "created" && <h6 className="text-center col-span-2">Assigned to</h6>}
</div>
<div className="px-4 pb-3 mt-2">
{issuesList.map((issue) => {
@@ -2,7 +2,8 @@ import { FC } from "react";
import { observer } from "mobx-react";
// hooks
import { useIssueDetail } from "@/hooks/store";
// plane wev components
// plane web components
import { IssueAdditionalPropertiesActivity } from "@/plane-web/components/issues";
import { IssueActivityWorklog } from "@/plane-web/components/issues/worklog/activity/root";
// plane web constants
import { TActivityFilters, filterActivityOnSelectedFilters } from "@/plane-web/constants/issues";
@@ -56,6 +57,11 @@ export const IssueActivityCommentRoot: FC<TIssueActivityCommentRoot> = observer(
activityId={activityComment.id}
ends={index === 0 ? "top" : index === filteredActivityComments.length - 1 ? "bottom" : undefined}
/>
) : activityComment.activity_type === "ISSUE_ADDITIONAL_PROPERTIES_ACTIVITY" ? (
<IssueAdditionalPropertiesActivity
activityId={activityComment.id}
ends={index === 0 ? "top" : index === filteredActivityComments.length - 1 ? "bottom" : undefined}
/>
) : activityComment.activity_type === "WORKLOG" ? (
<IssueActivityWorklog
workspaceSlug={workspaceSlug}
@@ -27,9 +27,9 @@ export const IssueArchivedAtActivity: FC<TIssueArchivedAtActivity> = observer((p
<IssueActivityBlockComponent
icon={
activity.new_value === "restore" ? (
<RotateCcw className="h-3.5 w-3.5" color="#6b7280" aria-hidden="true" />
<RotateCcw className="h-3.5 w-3.5 text-custom-text-200" aria-hidden="true" />
) : (
<ArchiveIcon className="h-3.5 w-3.5" color="#6b7280" aria-hidden="true" />
<ArchiveIcon className="h-3.5 w-3.5 text-custom-text-200" aria-hidden="true" />
)
}
activityId={activityId}
@@ -21,7 +21,7 @@ export const IssueAssigneeActivity: FC<TIssueAssigneeActivity> = observer((props
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<Users className="h-3 w-3 flex-shrink-0" />}
icon={<Users className="h-3.5 w-3.5 flex-shrink-0 text-custom-text-200" />}
activityId={activityId}
ends={ends}
>
@@ -20,7 +20,7 @@ export const IssueAttachmentActivity: FC<TIssueAttachmentActivity> = observer((p
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<Paperclip size={14} color="#6b7280" aria-hidden="true" />}
icon={<Paperclip size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -23,7 +23,7 @@ export const IssueCycleActivity: FC<TIssueCycleActivity> = observer((props) => {
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<ContrastIcon className="h-4 w-4 flex-shrink-0 text-[#6b7280]" />}
icon={<ContrastIcon className="h-4 w-4 flex-shrink-0 text-custom-text-200" />}
activityId={activityId}
ends={ends}
>
@@ -24,7 +24,7 @@ export const IssueDefaultActivity: FC<TIssueDefaultActivity> = observer((props)
return (
<IssueActivityBlockComponent
activityId={activityId}
icon={<LayersIcon width={12} height={12} color="#6b7280" aria-hidden="true" />}
icon={<LayersIcon width={14} height={14} className="text-custom-text-200" aria-hidden="true" />}
ends={ends}
>
<>{activity.verb === "created" ? " created the issue." : " deleted an issue."}</>
@@ -20,7 +20,7 @@ export const IssueDescriptionActivity: FC<TIssueDescriptionActivity> = observer(
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<MessageSquare size={14} color="#6b7280" aria-hidden="true" />}
icon={<MessageSquare size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -21,7 +21,7 @@ export const IssueEstimateActivity: FC<TIssueEstimateActivity> = observer((props
return (
<IssueActivityBlockComponent
icon={<Triangle size={14} color="#6b7280" aria-hidden="true" />}
icon={<Triangle size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -36,7 +36,7 @@ export const IssueInboxActivity: FC<TIssueInboxActivity> = observer((props) => {
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<Intake className="h-4 w-4 flex-shrink-0" />}
icon={<Intake className="h-4 w-4 flex-shrink-0 text-custom-text-200" />}
activityId={activityId}
ends={ends}
>
@@ -21,7 +21,7 @@ export const IssueLabelActivity: FC<TIssueLabelActivity> = observer((props) => {
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<Tag size={14} color="#6b7280" aria-hidden="true" />}
icon={<Tag size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -20,7 +20,7 @@ export const IssueLinkActivity: FC<TIssueLinkActivity> = observer((props) => {
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<MessageSquare size={14} color="#6b7280" aria-hidden="true" />}
icon={<MessageSquare size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -23,7 +23,7 @@ export const IssueModuleActivity: FC<TIssueModuleActivity> = observer((props) =>
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<DiceIcon className="h-4 w-4 flex-shrink-0 text-[#6b7280]" />}
icon={<DiceIcon className="h-4 w-4 flex-shrink-0 text-custom-text-200" />}
activityId={activityId}
ends={ends}
>
@@ -20,7 +20,7 @@ export const IssueNameActivity: FC<TIssueNameActivity> = observer((props) => {
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<MessageSquare size={14} color="#6b7280" aria-hidden="true" />}
icon={<MessageSquare size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -20,7 +20,7 @@ export const IssueParentActivity: FC<TIssueParentActivity> = observer((props) =>
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<LayoutPanelTop size={14} color="#6b7280" aria-hidden="true" />}
icon={<LayoutPanelTop size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -20,7 +20,7 @@ export const IssuePriorityActivity: FC<TIssuePriorityActivity> = observer((props
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<Signal size={14} color="#6b7280" aria-hidden="true" />}
icon={<Signal size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -22,7 +22,7 @@ export const IssueStartDateActivity: FC<TIssueStartDateActivity> = observer((pro
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<CalendarDays size={14} color="#6b7280" aria-hidden="true" />}
icon={<CalendarDays size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -23,7 +23,7 @@ export const IssueStateActivity: FC<TIssueStateActivity> = observer((props) => {
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<DoubleCircleIcon className="h-4 w-4 flex-shrink-0" />}
icon={<DoubleCircleIcon className="h-4 w-4 flex-shrink-0 text-custom-text-200" />}
activityId={activityId}
ends={ends}
>
@@ -22,7 +22,7 @@ export const IssueTargetDateActivity: FC<TIssueTargetDateActivity> = observer((p
if (!activity) return <></>;
return (
<IssueActivityBlockComponent
icon={<CalendarDays size={14} color="#6b7280" aria-hidden="true" />}
icon={<CalendarDays size={14} className="text-custom-text-200" aria-hidden="true" />}
activityId={activityId}
ends={ends}
>
@@ -45,7 +45,7 @@ export const IssueCommentBlock: FC<TIssueCommentBlock> = observer((props) => {
</>
)}
<div className="absolute top-2 left-4 w-5 h-5 rounded-full overflow-hidden flex justify-center items-center bg-custom-background-80">
<MessageCircle className="w-3 h-3" color="#6b7280" />
<MessageCircle className="w-3 h-3 text-custom-text-200" />
</div>
</div>
<div className="w-full truncate relative flex ">
@@ -67,7 +67,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
)}
<div className="mb-2.5 flex items-center gap-4">
<IssueIdentifier issueId={issueId} projectId={issue.project_id} iconSize={14} iconContainerSize={20} />
<IssueIdentifier issueId={issueId} projectId={issue.project_id} size="md" />
<IssueUpdateStatus isSubmitting={isSubmitting} />
</div>
@@ -4,15 +4,17 @@ import React from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { Pencil, X } from "lucide-react";
// hooks
// components
import { TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
import { ParentIssuesListModal } from "@/components/issues";
// ui
import { TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
// components
import { ParentIssuesListModal } from "@/components/issues";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useIssueDetail, useProject } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// types
import { TIssueOperations } from "./root";
@@ -102,16 +104,23 @@ export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props)
disabled={disabled}
>
{issue.parent_id && parentIssue ? (
<div className="flex items-center gap-1 bg-green-500/20 text-green-700 rounded px-1.5 py-1">
<div className="flex items-center gap-1 bg-green-500/20 rounded px-1.5 py-1">
<Tooltip tooltipHeading="Title" tooltipContent={parentIssue.name} isMobile={isMobile}>
<Link
href={`/${workspaceSlug}/projects/${parentIssue.project_id}/issues/${parentIssue?.id}`}
target="_blank"
rel="noopener noreferrer"
className="text-xs font-medium"
onClick={(e) => e.stopPropagation()}
>
{parentIssueProjectDetails?.identifier}-{parentIssue.sequence_id}
{parentIssue?.project_id && parentIssueProjectDetails && (
<IssueIdentifier
projectId={parentIssue.project_id}
issueTypeId={parentIssue.type_id}
projectIdentifier={parentIssueProjectDetails?.identifier}
issueSequenceId={parentIssue.sequence_id}
textContainerClassName="text-xs font-medium text-green-700"
/>
)}
</Link>
</Tooltip>
@@ -9,7 +9,9 @@ import { TIssue } from "@plane/types";
// ui
import { CustomMenu } from "@plane/ui";
// hooks
import { useIssues, useProject, useProjectState } from "@/hooks/store";
import { useIssues, useProjectState } from "@/hooks/store";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// types
import { TIssueOperations } from "../root";
import { IssueParentSiblings } from "./siblings";
@@ -26,7 +28,6 @@ export const IssueParentDetail: FC<TIssueParentDetail> = observer((props) => {
const { workspaceSlug, projectId, issueId, issue, issueOperations } = props;
// hooks
const { issueMap } = useIssues();
const { getProjectById } = useProject();
const { getProjectStates } = useProjectState();
const parentIssue = issueMap?.[issue.parent_id || ""] || undefined;
@@ -42,12 +43,16 @@ export const IssueParentDetail: FC<TIssueParentDetail> = observer((props) => {
<>
<div className="mb-5 flex w-min items-center gap-3 whitespace-nowrap rounded-md border border-custom-border-300 bg-custom-background-80 px-2.5 py-1 text-xs">
<Link href={`/${workspaceSlug}/projects/${parentIssue?.project_id}/issues/${parentIssue.id}`}>
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
<div className="flex items-center gap-2.5">
<span className="block h-2 w-2 rounded-full" style={{ backgroundColor: stateColor }} />
<span className="flex-shrink-0 text-custom-text-200">
{getProjectById(parentIssue.project_id)?.identifier}-{parentIssue?.sequence_id}
</span>
{parentIssue.project_id && (
<IssueIdentifier
projectId={parentIssue.project_id}
issueId={parentIssue.id}
textContainerClassName="text-xs text-custom-text-200"
/>
)}
</div>
<span className="truncate text-custom-text-100">{(parentIssue?.name ?? "").substring(0, 50)}</span>
</div>
@@ -4,9 +4,11 @@ import { FC } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
// ui
import { CustomMenu, LayersIcon } from "@plane/ui";
import { CustomMenu } from "@plane/ui";
// hooks
import { useIssueDetail, useProject } from "@/hooks/store";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
type TIssueParentSiblingItem = {
workspaceSlug: string;
@@ -31,10 +33,17 @@ export const IssueParentSiblingItem: FC<TIssueParentSiblingItem> = observer((pro
<CustomMenu.MenuItem key={issueDetail.id}>
<Link
href={`/${workspaceSlug}/projects/${issueDetail?.project_id as string}/issues/${issueDetail.id}`}
className="flex items-center gap-2 py-2"
className="flex items-center gap-2 py-0.5"
>
<LayersIcon className="h-4 w-4" />
{projectDetails?.identifier}-{issueDetail.sequence_id}
{issueDetail.project_id && projectDetails?.identifier && (
<IssueIdentifier
projectId={issueDetail.project_id}
issueTypeId={issueDetail.type_id}
projectIdentifier={projectDetails?.identifier}
issueSequenceId={issueDetail.sequence_id}
textContainerClassName="text-xs"
/>
)}
</Link>
</CustomMenu.MenuItem>
</>
@@ -34,7 +34,7 @@ export const IssueParentSiblings: FC<TIssueParentSiblings> = observer((props) =>
const subIssueIds = (parentIssue && subIssuesByIssueId(parentIssue.id)) || undefined;
return (
<div>
<div className="my-1">
{isLoading ? (
<div className="flex items-center gap-2 whitespace-nowrap px-1 py-1 text-left text-xs text-custom-text-200">
Loading
@@ -21,22 +21,22 @@ export type TRelationObject = { className: string; icon: (size: number) => React
export const issueRelationObject: Record<TIssueRelationTypes, TRelationObject> = {
relates_to: {
className: "bg-custom-background-80 text-custom-text-200",
icon: (size) => <RelatedIcon height={size} width={size} />,
icon: (size) => <RelatedIcon height={size} width={size} className="text-custom-text-200" />,
placeholder: "Add related issues",
},
blocking: {
className: "bg-yellow-500/20 text-yellow-700",
icon: (size) => <XCircle size={size} />,
icon: (size) => <XCircle size={size} className="text-custom-text-200" />,
placeholder: "None",
},
blocked_by: {
className: "bg-red-500/20 text-red-700",
icon: (size) => <CircleDot size={size} />,
icon: (size) => <CircleDot size={size} className="text-custom-text-200" />,
placeholder: "None",
},
duplicate: {
className: "bg-custom-background-80 text-custom-text-200",
icon: (size) => <CopyPlus size={size} />,
icon: (size) => <CopyPlus size={size} className="text-custom-text-200" />,
placeholder: "None",
},
};
@@ -5,17 +5,19 @@ import { useState, useRef, forwardRef } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { MoreHorizontal } from "lucide-react";
// types
import { TIssue } from "@plane/types";
// components
// ui
import { Tooltip, ControlLink } from "@plane/ui";
// hooks
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useIssueDetail, useProjectState } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
// helpers
// types
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues/issue-details";
// local components
import { TRenderQuickActions } from "../list/list-view-types";
type Props = {
@@ -2,13 +2,14 @@
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// hooks
// ui
import { Tooltip, ControlLink } from "@plane/ui";
// helpers
import { renderFormattedDate } from "@/helpers/date-time.helper";
// hooks
import { useIssueDetail, useProjectState } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
type Props = {
@@ -5,25 +5,26 @@ import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// types
import { TIssue, IIssueDisplayProperties, IIssueMap } from "@plane/types";
// hooks
// ui
import { ControlLink, DropIndicator, TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
// components
import RenderIfVisible from "@/components/core/render-if-visible-HOC";
import { HIGHLIGHT_CLASS } from "@/components/issues/issue-layouts/utils";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useIssueDetail, useKanbanView } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// components
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// local components
import { TRenderQuickActions } from "../list/list-view-types";
import { IssueProperties } from "../properties/all-properties";
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
import { getIssueBlockId } from "../utils";
// ui
// types
// helper
interface IssueBlockProps {
issueId: string;
@@ -19,6 +19,8 @@ import { cn } from "@/helpers/common.helper";
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
import { TSelectionHelper } from "@/hooks/use-multiple-select";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// types
import { IssueIdentifier } from "@/plane-web/components/issues";
import { TRenderQuickActions } from "./list-view-types";
@@ -20,6 +20,8 @@ import { useIssueDetail, useProject } from "@/hooks/store";
import { TSelectionHelper } from "@/hooks/use-multiple-select";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// local components
import { IssueIdentifier } from "@/plane-web/components/issues";
import { TRenderQuickActions } from "../list/list-view-types";
@@ -2,21 +2,23 @@
import React, { useEffect, useState } from "react";
import { useParams } from "next/navigation";
// headless ui
// icons
import { Rocket, Search } from "lucide-react";
// headless ui
import { Combobox, Dialog, Transition } from "@headlessui/react";
// services
// types
import { ISearchIssueResponse } from "@plane/types";
// ui
import { Loader, ToggleSwitch, Tooltip } from "@plane/ui";
// components
import { IssueSearchModalEmptyState } from "@/components/core";
// hooks
import useDebounce from "@/hooks/use-debounce";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// services
import { ProjectService } from "@/services/project";
// hooks
// components
// ui
// icons
// types
type Props = {
isOpen: boolean;
@@ -182,7 +184,7 @@ export const ParentIssuesListModal: React.FC<Props> = ({
key={issue.id}
value={issue}
className={({ active, selected }) =>
`group flex w-full cursor-pointer select-none items-center justify-between gap-2 rounded-md px-3 py-2 text-custom-text-200 ${
`group flex w-full cursor-pointer select-none items-center justify-between gap-2 rounded-md px-3 py-2 my-0.5 text-custom-text-200 ${
active ? "bg-custom-background-80 text-custom-text-100" : ""
} ${selected ? "text-custom-text-100" : ""}`
}
@@ -194,8 +196,14 @@ export const ParentIssuesListModal: React.FC<Props> = ({
backgroundColor: issue.state__color,
}}
/>
<span className="flex-shrink-0 text-xs">
{issue.project__identifier}-{issue.sequence_id}
<span className="flex-shrink-0">
<IssueIdentifier
projectId={issue.project_id}
issueTypeId={issue.type_id}
projectIdentifier={issue.project__identifier}
issueSequenceId={issue.sequence_id}
textContainerClassName="text-xs text-custom-text-200"
/>
</span>{" "}
<span className="truncate">{issue.name}</span>
</div>
@@ -56,7 +56,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = observer(
return (
<div className="space-y-2">
<IssueIdentifier issueId={issueId} projectId={issue.project_id} iconSize={14} iconContainerSize={20} />
<IssueIdentifier issueId={issueId} projectId={issue.project_id} size="md" />
<IssueTitleInput
workspaceSlug={workspaceSlug}
projectId={issue.project_id}
@@ -241,7 +241,7 @@ export const IssueView: FC<IIssueView> = observer((props) => {
</div>
</div>
<div
className={`h-full !w-[400px] flex-shrink-0 border-l border-custom-border-200 p-4 py-5 overflow-hidden vertical-scrollbar scrollbar-sm ${
className={`h-full !w-[400px] flex-shrink-0 border-l border-custom-border-200 p-4 py-5 overflow-hidden vertical-scrollbar scrollbar-sm ${
is_archived ? "pointer-events-none" : ""
}`}
>
@@ -10,6 +10,8 @@ import { RelationIssueProperty } from "@/components/issues/relations";
// hooks
import { useIssueDetail, useProject, useProjectState } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// types
import { TRelationIssueOperations } from "../issue-detail-widgets/relations/helper";
@@ -91,15 +93,23 @@ export const RelationIssueListItem: FC<Props> = observer((props) => {
{issue && (
<div className="group relative flex min-h-11 h-full w-full items-center gap-3 px-1.5 py-1 transition-all hover:bg-custom-background-90">
<span className="size-5 flex-shrink-0" />
<div className="flex w-full cursor-pointer items-center gap-2">
<div className="flex w-full cursor-pointer items-center gap-3">
<div
className="h-2 w-2 flex-shrink-0 rounded-full"
style={{
backgroundColor: currentIssueStateDetail?.color ?? "#737373",
}}
/>
<div className="flex-shrink-0 text-xs text-custom-text-200">
{projectDetail?.identifier}-{issue?.sequence_id}
<div className="flex-shrink-0">
{projectDetail && (
<IssueIdentifier
projectId={projectDetail.id}
issueTypeId={issue.type_id}
projectIdentifier={projectDetail.identifier}
issueSequenceId={issue.sequence_id}
textContainerClassName="text-xs text-custom-text-200"
/>
)}
</div>
<ControlLink
@@ -4,11 +4,16 @@ import React from "react";
import { observer } from "mobx-react";
import { ChevronRight, X, Pencil, Trash, Link as LinkIcon, Loader } from "lucide-react";
import { TIssue } from "@plane/types";
// components
// ui
import { ControlLink, CustomMenu, Tooltip } from "@plane/ui";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useIssueDetail, useProject, useProjectState } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
// local components
import { IssueList } from "./issues-list";
import { IssueProperty } from "./properties";
// ui
@@ -117,15 +122,23 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
)}
</div>
<div className="flex w-full cursor-pointer items-center gap-2">
<div className="flex w-full cursor-pointer items-center gap-3">
<div
className="h-2 w-2 flex-shrink-0 rounded-full"
style={{
backgroundColor: currentIssueStateDetail?.color ?? "#737373",
}}
/>
<div className="flex-shrink-0 text-xs text-custom-text-200">
{projectDetail?.identifier}-{issue?.sequence_id}
<div className="flex-shrink-0">
{projectDetail && (
<IssueIdentifier
projectId={projectDetail.id}
issueTypeId={issue.type_id}
projectIdentifier={projectDetail.identifier}
issueSequenceId={issue.sequence_id}
textContainerClassName="text-xs text-custom-text-200"
/>
)}
</div>
<ControlLink
@@ -1 +1,2 @@
export * from "./issue-identifier";
export * from "./issue-properties-activity";
@@ -0,0 +1 @@
export * from "./root";
@@ -0,0 +1 @@
export * from "ce/components/issues/issue-details/issue-properties-activity/root";