style: issue details page (#911)
This commit is contained in:
parent
73388195ef
commit
165d16e32b
18 changed files with 106 additions and 87 deletions
|
|
@ -66,7 +66,7 @@ export const SingleBoard: React.FC<Props> = ({
|
||||||
}, [currentState]);
|
}, [currentState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`h-full flex-shrink-0 ${!isCollapsed ? "" : "w-96 bg-brand-base"}`}>
|
<div className={`h-full flex-shrink-0 ${!isCollapsed ? "" : "w-96"}`}>
|
||||||
<div className={`${!isCollapsed ? "" : "flex h-full flex-col space-y-3"}`}>
|
<div className={`${!isCollapsed ? "" : "flex h-full flex-col space-y-3"}`}>
|
||||||
<BoardHeader
|
<BoardHeader
|
||||||
addIssueToState={addIssueToState}
|
addIssueToState={addIssueToState}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
// icons
|
// icons
|
||||||
import { LinkIcon, TrashIcon } from "@heroicons/react/24/outline";
|
import { ArrowTopRightOnSquareIcon, LinkIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||||
import { ExternalLinkIcon } from "components/icons";
|
|
||||||
// helpers
|
// helpers
|
||||||
import { timeAgo } from "helpers/date-time.helper";
|
import { timeAgo } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
|
|
@ -33,15 +32,15 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
||||||
<div className="absolute top-1.5 right-1.5 z-[1] flex items-center gap-1">
|
<div className="absolute top-1.5 right-1.5 z-[1] flex items-center gap-1">
|
||||||
<Link href={link.url}>
|
<Link href={link.url}>
|
||||||
<a
|
<a
|
||||||
className="grid h-7 w-7 place-items-center rounded bg-brand-surface-1 p-1 outline-none"
|
className="grid h-7 w-7 place-items-center rounded bg-brand-surface-1 p-1 outline-none hover:bg-brand-surface-2"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<ExternalLinkIcon width="14" height="14" />
|
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-brand-secondary" />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid h-7 w-7 place-items-center rounded bg-brand-surface-1 p-1 text-red-500 outline-none duration-300 hover:bg-red-500/30"
|
className="grid h-7 w-7 place-items-center rounded bg-brand-surface-1 p-1 text-red-500 outline-none duration-300 hover:bg-red-500/20"
|
||||||
onClick={() => handleDeleteLink(link.id)}
|
onClick={() => handleDeleteLink(link.id)}
|
||||||
>
|
>
|
||||||
<TrashIcon className="h-4 w-4" />
|
<TrashIcon className="h-4 w-4" />
|
||||||
|
|
@ -49,7 +48,7 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Link href={link.url}>
|
<Link href={link.url}>
|
||||||
<a className="relative flex gap-2 rounded-md border border-brand-base bg-brand-surface-2 p-2" target="_blank">
|
<a className="relative flex gap-2 rounded-md bg-brand-base p-2" target="_blank">
|
||||||
<div className="mt-0.5">
|
<div className="mt-0.5">
|
||||||
<LinkIcon className="h-3.5 w-3.5" />
|
<LinkIcon className="h-3.5 w-3.5" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ const activityDetails: {
|
||||||
},
|
},
|
||||||
estimate_point: {
|
estimate_point: {
|
||||||
message: "set the estimate point to",
|
message: "set the estimate point to",
|
||||||
icon: <PlayIcon className="h-3 w-3 text-gray-500 -rotate-90" aria-hidden="true" />,
|
icon: <PlayIcon className="h-3 w-3 -rotate-90 text-gray-500" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
labels: {
|
labels: {
|
||||||
icon: <TagIcon height="12" width="12" color="#6b7280" />,
|
icon: <TagIcon height="12" width="12" color="#6b7280" />,
|
||||||
|
|
@ -78,11 +78,15 @@ const activityDetails: {
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
message: "set the name to",
|
message: "set the name to",
|
||||||
icon: <ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: (
|
||||||
|
<ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
message: "updated the description.",
|
message: "updated the description.",
|
||||||
icon: <ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: (
|
||||||
|
<ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
target_date: {
|
target_date: {
|
||||||
message: "set the due date to",
|
message: "set the due date to",
|
||||||
|
|
@ -94,7 +98,7 @@ const activityDetails: {
|
||||||
},
|
},
|
||||||
estimate: {
|
estimate: {
|
||||||
message: "updated the estimate",
|
message: "updated the estimate",
|
||||||
icon: <PlayIcon className="h-3 w-3 text-gray-500 -rotate-90" aria-hidden="true" />,
|
icon: <PlayIcon className="h-3 w-3 -rotate-90 text-gray-500" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
message: "updated the link",
|
message: "updated the link",
|
||||||
|
|
@ -255,7 +259,7 @@ export const IssueActivitySection: React.FC<Props> = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
value = (
|
value = (
|
||||||
<span className="relative inline-flex items-center rounded-full px-2 py-0.5 text-xs border border-brand-base">
|
<span className="relative inline-flex items-center rounded-full border border-brand-base px-2 py-0.5 text-xs">
|
||||||
<span className="absolute flex flex-shrink-0 items-center justify-center">
|
<span className="absolute flex flex-shrink-0 items-center justify-center">
|
||||||
<span
|
<span
|
||||||
className="h-1.5 w-1.5 rounded-full"
|
className="h-1.5 w-1.5 rounded-full"
|
||||||
|
|
@ -298,7 +302,7 @@ export const IssueActivitySection: React.FC<Props> = () => {
|
||||||
<div className="relative pb-1">
|
<div className="relative pb-1">
|
||||||
{issueActivities.length > 1 && activityItemIdx !== issueActivities.length - 1 ? (
|
{issueActivities.length > 1 && activityItemIdx !== issueActivities.length - 1 ? (
|
||||||
<span
|
<span
|
||||||
className="absolute top-5 left-5 -ml-px h-full w-0.5 bg-brand-surface-2"
|
className="absolute top-5 left-5 -ml-px h-full w-0.5 bg-brand-surface-1"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
@ -353,12 +357,13 @@ export const IssueActivitySection: React.FC<Props> = () => {
|
||||||
);
|
);
|
||||||
} else if ("comment_json" in activityItem)
|
} else if ("comment_json" in activityItem)
|
||||||
return (
|
return (
|
||||||
<CommentCard
|
<div key={activityItem.id} className="mt-4">
|
||||||
key={activityItem.id}
|
<CommentCard
|
||||||
comment={activityItem as any}
|
comment={activityItem as any}
|
||||||
onSubmit={handleCommentUpdate}
|
onSubmit={handleCommentUpdate}
|
||||||
handleCommentDeletion={handleCommentDelete}
|
handleCommentDeletion={handleCommentDelete}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ export const SidebarAssigneeSelect: React.FC<Props> = ({ value, onChange, userAu
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<UserGroupIcon className="h-4 w-4 flex-shrink-0" />
|
<UserGroupIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
<p>Assignees</p>
|
<p>Assignees</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -66,9 +66,9 @@ export const SidebarAssigneeSelect: React.FC<Props> = ({ value, onChange, userAu
|
||||||
label={
|
label={
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-brand-secondary">
|
||||||
{value && value.length > 0 && Array.isArray(value) ? (
|
{value && value.length > 0 && Array.isArray(value) ? (
|
||||||
<div className="flex items-center justify-center gap-2 -my-0.5">
|
<div className="-my-0.5 flex items-center justify-center gap-2">
|
||||||
<AssigneesList userIds={value} length={3} showLength={false} />
|
<AssigneesList userIds={value} length={3} showLength={false} />
|
||||||
<span className="text-brand-secondary">{value.length} Assignees</span>
|
<span className="text-brand-base">{value.length} Assignees</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
"No assignees"
|
"No assignees"
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-start py-2">
|
<div className="flex flex-wrap items-start py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<BlockedIcon height={16} width={16} />
|
<BlockedIcon height={16} width={16} />
|
||||||
<p>Blocked by</p>
|
<p>Blocked by</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -115,7 +115,7 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
|
||||||
? watch("blocked_list").map((issue) => (
|
? watch("blocked_list").map((issue) => (
|
||||||
<div
|
<div
|
||||||
key={issue}
|
key={issue}
|
||||||
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-brand-base px-1.5 py-0.5 text-xs text-red-500 duration-300 hover:border-red-500 hover:bg-red-500/30"
|
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-brand-base px-1.5 py-0.5 text-xs text-red-500 duration-300 hover:border-red-500/20 hover:bg-red-500/20"
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspaceSlug}/projects/${projectId}/issues/${
|
href={`/${workspaceSlug}/projects/${projectId}/issues/${
|
||||||
|
|
@ -287,9 +287,9 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex w-full ${
|
className={`flex w-full text-brand-secondary ${
|
||||||
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
||||||
} items-center justify-between gap-1 rounded-md border border-brand-base px-2 py-1 text-xs shadow-sm duration-300 focus:border-brand-accent focus:outline-none focus:ring-1 focus:ring-brand-accent`}
|
} items-center justify-between gap-1 rounded-md border border-brand-base px-2 py-1 text-xs shadow-sm duration-300 focus:outline-none`}
|
||||||
onClick={() => setIsBlockedModalOpen(true)}
|
onClick={() => setIsBlockedModalOpen(true)}
|
||||||
disabled={isNotAllowed}
|
disabled={isNotAllowed}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-start py-2">
|
<div className="flex flex-wrap items-start py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<BlockerIcon height={16} width={16} />
|
<BlockerIcon height={16} width={16} />
|
||||||
<p>Blocking</p>
|
<p>Blocking</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -115,7 +115,7 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
|
||||||
? watch("blockers_list").map((issue) => (
|
? watch("blockers_list").map((issue) => (
|
||||||
<div
|
<div
|
||||||
key={issue}
|
key={issue}
|
||||||
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-white px-1.5 py-0.5 text-xs text-yellow-500 duration-300 hover:border-yellow-500 hover:bg-yellow-50"
|
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-brand-base px-1.5 py-0.5 text-xs text-yellow-500 duration-300 hover:border-yellow-500/20 hover:bg-yellow-500/20"
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspaceSlug}/projects/${projectId}/issues/${
|
href={`/${workspaceSlug}/projects/${projectId}/issues/${
|
||||||
|
|
@ -284,9 +284,9 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex w-full ${
|
className={`flex w-full text-brand-secondary ${
|
||||||
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
||||||
} items-center justify-between gap-1 rounded-md border border-brand-base px-2 py-1 text-xs shadow-sm duration-300 focus:border-brand-accent focus:outline-none focus:ring-1 focus:ring-brand-accent`}
|
} items-center justify-between gap-1 rounded-md border border-brand-base px-2 py-1 text-xs shadow-sm duration-300 focus:outline-none`}
|
||||||
onClick={() => setIsBlockerModalOpen(true)}
|
onClick={() => setIsBlockerModalOpen(true)}
|
||||||
disabled={isNotAllowed}
|
disabled={isNotAllowed}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import { Spinner, CustomSelect, Tooltip } from "components/ui";
|
||||||
// helper
|
// helper
|
||||||
import { truncateText } from "helpers/string.helper";
|
import { truncateText } from "helpers/string.helper";
|
||||||
// icons
|
// icons
|
||||||
import { CyclesIcon } from "components/icons";
|
import { ContrastIcon } from "components/icons";
|
||||||
// types
|
// types
|
||||||
import { ICycle, IIssue, UserAuth } from "types";
|
import { ICycle, IIssue, UserAuth } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
|
|
@ -60,20 +60,21 @@ export const SidebarCycleSelect: React.FC<Props> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<CyclesIcon className="h-4 w-4 flex-shrink-0" />
|
<ContrastIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
<p>Cycle</p>
|
<p>Cycle</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 sm:basis-1/2">
|
<div className="space-y-1 sm:basis-1/2">
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
label={
|
label={
|
||||||
<Tooltip position="left" tooltipContent={`${issueCycle ? issueCycle.cycle_detail.name : ""}`}>
|
<Tooltip
|
||||||
<span
|
position="left"
|
||||||
className={`w-full max-w-[125px] truncate text-left sm:block ${
|
tooltipContent={`${issueCycle ? issueCycle.cycle_detail.name : "No cycle"}`}
|
||||||
issueCycle ? "" : "text-brand-base"
|
>
|
||||||
}`}
|
<span className="w-full max-w-[125px] truncate text-left sm:block">
|
||||||
>
|
<span className={`${issueCycle ? "text-brand-base" : "text-brand-secondary"}`}>
|
||||||
{issueCycle ? truncateText(issueCycle.cycle_detail.name, 15) : "None"}
|
{issueCycle ? truncateText(issueCycle.cycle_detail.name, 15) : "No cycle"}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ export const SidebarEstimateSelect: React.FC<Props> = ({ value, onChange, userAu
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<PlayIcon className="h-4 w-4 -rotate-90 flex-shrink-0" />
|
<PlayIcon className="h-4 w-4 flex-shrink-0 -rotate-90" />
|
||||||
<p>Estimate</p>
|
<p>Estimate</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:basis-1/2">
|
<div className="sm:basis-1/2">
|
||||||
|
|
@ -33,10 +33,14 @@ export const SidebarEstimateSelect: React.FC<Props> = ({ value, onChange, userAu
|
||||||
value={value}
|
value={value}
|
||||||
label={
|
label={
|
||||||
<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
|
||||||
<span className={`${value ? "text-gray-600" : "text-gray-500"}`}>
|
className={`h-4 w-4 -rotate-90 ${
|
||||||
{estimatePoints?.find((e) => e.key === value)?.value ?? "Estimate"}
|
value !== null ? "text-brand-base" : "text-brand-secondary"
|
||||||
</span>
|
}`}
|
||||||
|
/>
|
||||||
|
{estimatePoints?.find((e) => e.key === value)?.value ?? (
|
||||||
|
<span className="text-brand-secondary">No estimates</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|
|
||||||
|
|
@ -59,21 +59,27 @@ export const SidebarModuleSelect: React.FC<Props> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<RectangleGroupIcon className="h-4 w-4 flex-shrink-0" />
|
<RectangleGroupIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
<p>Module</p>
|
<p>Module</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 sm:basis-1/2">
|
<div className="space-y-1 sm:basis-1/2">
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
label={
|
label={
|
||||||
<Tooltip position="left" tooltipContent={`${modules?.find((m) => m.id === issueModule?.module)?.name ?? "None"}`}>
|
<Tooltip
|
||||||
<span
|
position="left"
|
||||||
className={`w-full max-w-[125px] truncate text-left sm:block ${
|
tooltipContent={`${
|
||||||
issueModule ? "" : "text-brand-base"
|
modules?.find((m) => m.id === issueModule?.module)?.name ?? "No module"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{truncateText(`${modules?.find((m) => m.id === issueModule?.module)?.name ?? "None"}`, 15)}
|
<span className="w-full max-w-[125px] truncate text-left sm:block">
|
||||||
</span>
|
<span className={`${issueModule ? "text-brand-base" : "text-brand-secondary"}`}>
|
||||||
|
{truncateText(
|
||||||
|
`${modules?.find((m) => m.id === issueModule?.module)?.name ?? "No module"}`,
|
||||||
|
15
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
value={issueModule?.module_detail?.id}
|
value={issueModule?.module_detail?.id}
|
||||||
|
|
@ -93,7 +99,9 @@ export const SidebarModuleSelect: React.FC<Props> = ({
|
||||||
{modules.map((option) => (
|
{modules.map((option) => (
|
||||||
<CustomSelect.Option key={option.id} value={option.id}>
|
<CustomSelect.Option key={option.id} value={option.id}>
|
||||||
<Tooltip position="left-bottom" tooltipContent={option.name}>
|
<Tooltip position="left-bottom" tooltipContent={option.name}>
|
||||||
<span className="w-full max-w-[125px] truncate">{truncateText(option.name, 15)}</span>
|
<span className="w-full max-w-[125px] truncate">
|
||||||
|
{truncateText(option.name, 15)}
|
||||||
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</CustomSelect.Option>
|
</CustomSelect.Option>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ export const SidebarParentSelect: React.FC<Props> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<UserIcon className="h-4 w-4 flex-shrink-0" />
|
<UserIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
<p>Parent</p>
|
<p>Parent</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -79,7 +79,7 @@ export const SidebarParentSelect: React.FC<Props> = ({
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex w-full ${
|
className={`flex w-full ${
|
||||||
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
||||||
} items-center justify-between gap-1 rounded-md border border-brand-base px-2 py-1 text-xs shadow-sm duration-300 focus:border-brand-accent focus:outline-none focus:ring-1 focus:ring-brand-accent`}
|
} items-center justify-between gap-1 rounded-md border border-brand-base px-2 py-1 text-xs shadow-sm duration-300 focus:outline-none`}
|
||||||
onClick={() => setIsParentModalOpen(true)}
|
onClick={() => setIsParentModalOpen(true)}
|
||||||
disabled={isNotAllowed}
|
disabled={isNotAllowed}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -21,21 +21,21 @@ export const SidebarPrioritySelect: React.FC<Props> = ({ value, onChange, userAu
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<ChartBarIcon className="h-4 w-4 flex-shrink-0" />
|
<ChartBarIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
<p>Priority</p>
|
<p>Priority</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:basis-1/2">
|
<div className="sm:basis-1/2">
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
label={
|
label={
|
||||||
<span
|
<div className="flex items-center gap-2 text-left capitalize">
|
||||||
className={`flex items-center gap-2 text-left capitalize ${
|
<span className={`${value ? "text-brand-base" : "text-brand-secondary"}`}>
|
||||||
value ? "" : "text-brand-base"
|
{getPriorityIcon(value ?? "None", "text-sm")}
|
||||||
}`}
|
</span>
|
||||||
>
|
<span className={`${value ? "text-brand-base" : "text-brand-secondary"}`}>
|
||||||
{getPriorityIcon(value && value !== "" ? value ?? "" : "None", "text-sm")}
|
{value ?? "None"}
|
||||||
{value && value !== "" ? value : "None"}
|
</span>
|
||||||
</span>
|
</div>
|
||||||
}
|
}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,14 @@ export const SidebarStateSelect: React.FC<Props> = ({ value, onChange, userAuth
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<Squares2X2Icon className="h-4 w-4 flex-shrink-0" />
|
<Squares2X2Icon className="h-4 w-4 flex-shrink-0" />
|
||||||
<p>State</p>
|
<p>State</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:basis-1/2">
|
<div className="sm:basis-1/2">
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
label={
|
label={
|
||||||
<div className={`flex items-center gap-2 text-left ${value ? "" : "text-brand-base"}`}>
|
<div className="flex items-center gap-2 text-left text-brand-base">
|
||||||
{getStateGroupIcon(
|
{getStateGroupIcon(
|
||||||
selectedState?.group ?? "backlog",
|
selectedState?.group ?? "backlog",
|
||||||
"16",
|
"16",
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||||
{!isNotAllowed && (
|
{!isNotAllowed && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="rounded-md border border-red-500 p-2 text-red-500 shadow-sm duration-300 hover:bg-red-500/30 focus:border-brand-accent focus:outline-none focus:ring-1 focus:ring-brand-accent"
|
className="rounded-md border border-red-500 p-2 text-red-500 shadow-sm duration-300 hover:bg-red-500/20 focus:outline-none"
|
||||||
onClick={() => setDeleteIssueModal(true)}
|
onClick={() => setDeleteIssueModal(true)}
|
||||||
>
|
>
|
||||||
<TrashIcon className="h-3.5 w-3.5" />
|
<TrashIcon className="h-3.5 w-3.5" />
|
||||||
|
|
@ -344,7 +344,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-wrap items-center py-2">
|
<div className="flex flex-wrap items-center py-2">
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
<div className="flex items-center gap-x-2 text-sm text-brand-secondary sm:basis-1/2">
|
||||||
<CalendarDaysIcon className="h-4 w-4 flex-shrink-0" />
|
<CalendarDaysIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
<p>Due date</p>
|
<p>Due date</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -382,7 +382,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-3 py-3">
|
<div className="space-y-3 py-3">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div className="flex basis-1/2 items-center gap-x-2 text-sm">
|
<div className="flex basis-1/2 items-center gap-x-2 text-sm text-brand-secondary">
|
||||||
<TagIcon className="h-4 w-4" />
|
<TagIcon className="h-4 w-4" />
|
||||||
<p>Label</p>
|
<p>Label</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -395,7 +395,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
key={label.id}
|
key={label.id}
|
||||||
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-brand-base px-1 py-0.5 text-xs hover:border-red-500 hover:bg-red-500/30"
|
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-brand-base px-1 py-0.5 text-xs hover:border-red-500/20 hover:bg-red-500/20"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const updatedLabels = watchIssue("labels_list")?.filter(
|
const updatedLabels = watchIssue("labels_list")?.filter(
|
||||||
(l) => l !== labelId
|
(l) => l !== labelId
|
||||||
|
|
@ -436,7 +436,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||||
isNotAllowed
|
isNotAllowed
|
||||||
? "cursor-not-allowed"
|
? "cursor-not-allowed"
|
||||||
: "cursor-pointer hover:bg-brand-surface-1"
|
: "cursor-pointer hover:bg-brand-surface-1"
|
||||||
} items-center gap-2 rounded-2xl border border-brand-base px-2 py-0.5 text-xs`}
|
} items-center gap-2 rounded-2xl border border-brand-base px-2 py-0.5 text-xs text-brand-secondary`}
|
||||||
>
|
>
|
||||||
Select Label
|
Select Label
|
||||||
</Listbox.Button>
|
</Listbox.Button>
|
||||||
|
|
@ -463,7 +463,9 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||||
<Listbox.Option
|
<Listbox.Option
|
||||||
key={label.id}
|
key={label.id}
|
||||||
className={({ active, selected }) =>
|
className={({ active, selected }) =>
|
||||||
`${active || selected ? "bg-brand-surface-1" : ""} ${
|
`${
|
||||||
|
active || selected ? "bg-brand-surface-1" : ""
|
||||||
|
} ${
|
||||||
selected ? "font-medium" : ""
|
selected ? "font-medium" : ""
|
||||||
} flex cursor-pointer select-none items-center gap-2 truncate p-2 text-brand-base`
|
} flex cursor-pointer select-none items-center gap-2 truncate p-2 text-brand-base`
|
||||||
}
|
}
|
||||||
|
|
@ -530,8 +532,10 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex ${
|
className={`flex ${
|
||||||
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
isNotAllowed
|
||||||
} items-center gap-1 rounded-2xl border border-brand-base px-2 py-0.5 text-xs`}
|
? "cursor-not-allowed"
|
||||||
|
: "cursor-pointer hover:bg-brand-surface-1"
|
||||||
|
} items-center gap-1 rounded-2xl border border-brand-base px-2 py-0.5 text-xs text-brand-secondary`}
|
||||||
onClick={() => setCreateLabelForm((prevData) => !prevData)}
|
onClick={() => setCreateLabelForm((prevData) => !prevData)}
|
||||||
>
|
>
|
||||||
{createLabelForm ? (
|
{createLabelForm ? (
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import {
|
||||||
import {
|
import {
|
||||||
ContrastIcon,
|
ContrastIcon,
|
||||||
LayerDiagonalIcon,
|
LayerDiagonalIcon,
|
||||||
PencilScribbleIcon,
|
|
||||||
PeopleGroupIcon,
|
PeopleGroupIcon,
|
||||||
SettingIcon,
|
SettingIcon,
|
||||||
ViewListIcon,
|
ViewListIcon,
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ const CustomSelect = ({
|
||||||
) : (
|
) : (
|
||||||
<Listbox.Button
|
<Listbox.Button
|
||||||
className={`flex w-full ${
|
className={`flex w-full ${
|
||||||
disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-base"
|
disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-brand-surface-1"
|
||||||
} items-center justify-between gap-1 rounded-md border border-brand-base shadow-sm duration-300 focus:outline-none focus:ring-1 focus:ring-brand-base ${
|
} items-center justify-between gap-1 rounded-md border border-brand-base shadow-sm duration-300 focus:outline-none ${
|
||||||
input ? "border-brand-base px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
|
input ? "border-brand-base px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
|
||||||
} ${
|
} ${
|
||||||
textAlignment === "right"
|
textAlignment === "right"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Header: React.FC<Props> = ({ breadcrumbs, left, right, setToggleSidebar }) => (
|
const Header: React.FC<Props> = ({ breadcrumbs, left, right, setToggleSidebar }) => (
|
||||||
<div className="flex w-full flex-row items-center justify-between gap-y-4 border-b border-brand-base bg-brand-sidebar px-5 py-4 ">
|
<div className="flex w-full flex-row items-center justify-between gap-y-4 border-b border-brand-base bg-brand-sidebar px-5 py-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="block md:hidden">
|
<div className="block md:hidden">
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ const ProjectAuthorizationWrapped: React.FC<Props> = ({
|
||||||
noPadding || issueView === "list" ? "" : settingsLayout ? "p-8 lg:px-28" : "p-8"
|
noPadding || issueView === "list" ? "" : settingsLayout ? "p-8 lg:px-28" : "p-8"
|
||||||
} ${
|
} ${
|
||||||
bg === "primary"
|
bg === "primary"
|
||||||
? "bg-brand-base"
|
? "bg-brand-sidebar"
|
||||||
: bg === "secondary"
|
: bg === "secondary"
|
||||||
? "bg-brand-surface-1"
|
? "bg-brand-surface-1"
|
||||||
: "bg-brand-base"
|
: "bg-brand-base"
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,6 @@ const IssueDetailsPage: NextPage = () => {
|
||||||
return (
|
return (
|
||||||
<ProjectAuthorizationWrapper
|
<ProjectAuthorizationWrapper
|
||||||
noPadding
|
noPadding
|
||||||
bg="secondary"
|
|
||||||
breadcrumbs={
|
breadcrumbs={
|
||||||
<Breadcrumbs>
|
<Breadcrumbs>
|
||||||
<Breadcrumbs.BreadcrumbItem
|
<Breadcrumbs.BreadcrumbItem
|
||||||
|
|
@ -149,18 +148,18 @@ const IssueDetailsPage: NextPage = () => {
|
||||||
issueDetails.parent
|
issueDetails.parent
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<a className="flex items-center gap-2">
|
<a className="flex items-center gap-2 text-brand-secondary">
|
||||||
<span
|
<span
|
||||||
className="block h-1.5 w-1.5 rounded-full"
|
className="block h-1.5 w-1.5 rounded-full"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: issueDetails?.state_detail?.color,
|
backgroundColor: issueDetails?.state_detail?.color,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="flex-shrink-0 text-gray-600">
|
<span className="flex-shrink-0">
|
||||||
{issueDetails.project_detail.identifier}-
|
{issueDetails.project_detail.identifier}-
|
||||||
{issueDetails.parent_detail?.sequence_id}
|
{issueDetails.parent_detail?.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
<span className="truncate font-medium">
|
<span className="truncate">
|
||||||
{issueDetails.parent_detail?.name.substring(0, 50)}
|
{issueDetails.parent_detail?.name.substring(0, 50)}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -182,7 +181,7 @@ const IssueDetailsPage: NextPage = () => {
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<CustomMenu.MenuItem className="flex items-center gap-2 whitespace-nowrap p-2 text-left text-xs text-brand-base">
|
<CustomMenu.MenuItem className="flex items-center gap-2 whitespace-nowrap p-2 text-left text-xs text-brand-secondary">
|
||||||
No other sibling issues
|
No other sibling issues
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
)}
|
)}
|
||||||
|
|
@ -196,12 +195,12 @@ const IssueDetailsPage: NextPage = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-3 py-3">
|
<div className="flex flex-col gap-3 py-3">
|
||||||
<h3 className="text-lg">Attachments</h3>
|
<h3 className="text-lg">Attachments</h3>
|
||||||
<div className="grid gap-3 grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
|
||||||
<IssueAttachmentUpload />
|
<IssueAttachmentUpload />
|
||||||
<IssueAttachments />
|
<IssueAttachments />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-5 bg-brand-base pt-3">
|
<div className="space-y-5 pt-3">
|
||||||
<h3 className="text-lg text-brand-base">Comments/Activity</h3>
|
<h3 className="text-lg text-brand-base">Comments/Activity</h3>
|
||||||
<IssueActivitySection />
|
<IssueActivitySection />
|
||||||
<AddComment />
|
<AddComment />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue