[WEB-2273] Chore: page alignments (#5505)

* chore: headers + common containers

* fix: filters code splitting

* fix: home header

* fix: header changes

* chore: page alignments fixed

* fix: uncommented filters

* fix: used enums

* fix: cards + filters

* fix: enum changes

* fix: reverted package changes

* fix: reverted package changes

* fix: Card + tags seperated + naming fixed

* fix: card + tags seperated + naming fixed

* fix: mobile headers fixed partially

* fix: build errors + minor css

* fix: checkbox spacing

* fix: review changes

* fix: lint errors

* fix: minor review changes
This commit is contained in:
Akshita Goyal 2024-09-05 12:16:24 +05:30 committed by GitHub
parent c78b2344b8
commit 87dbb9b888
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
181 changed files with 1323 additions and 1122 deletions

View file

@ -8,6 +8,7 @@ import {
IIssueFilterOptions,
TIssueKanbanFilters,
} from "@plane/types";
import { Row } from "@plane/ui";
import { CalendarMonthsDropdown, CalendarOptionsDropdown } from "@/components/issues";
// icons
import { EIssueFilterType } from "@/constants/issue";
@ -96,7 +97,7 @@ export const CalendarHeader: React.FC<ICalendarHeader> = observer((props) => {
};
return (
<div className="mb-4 flex items-center justify-between gap-2 px-3">
<Row className="mb-4 flex items-center justify-between gap-2">
<div className="flex items-center gap-1.5">
<button type="button" className="grid place-items-center" onClick={handlePrevious}>
<ChevronLeft size={16} strokeWidth={2} />
@ -116,6 +117,6 @@ export const CalendarHeader: React.FC<ICalendarHeader> = observer((props) => {
</button>
<CalendarOptionsDropdown issuesFilterStore={issuesFilterStore} updateFilters={updateFilters} />
</div>
</div>
</Row>
);
});

View file

@ -3,6 +3,7 @@ import { X } from "lucide-react";
// types
import { IIssueFilterOptions, IIssueLabel, IState } from "@plane/types";
// components
import { Tag } from "@plane/ui";
import {
AppliedCycleFilters,
AppliedDateFilters,
@ -67,100 +68,90 @@ export const AppliedFiltersList: React.FC<Props> = observer((props) => {
if (Array.isArray(value) && value.length === 0) return;
return (
<div
key={filterKey}
className="flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1 capitalize truncate"
>
<div className="flex flex-wrap items-center gap-1.5 truncate">
<span className="text-xs text-custom-text-300">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{membersFilters.includes(filterKey) && (
<AppliedMembersFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter(filterKey, val)}
values={value}
/>
)}
{dateFilters.includes(filterKey) && (
<AppliedDateFilters handleRemove={(val) => handleRemoveFilter(filterKey, val)} values={value} />
)}
{filterKey === "labels" && (
<AppliedLabelsFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("labels", val)}
labels={labels}
values={value}
/>
)}
{filterKey === "priority" && (
<AppliedPriorityFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("priority", val)}
values={value}
/>
)}
{filterKey === "state" && states && (
<AppliedStateFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("state", val)}
states={states}
values={value}
/>
)}
{filterKey === "state_group" && (
<AppliedStateGroupFilters
handleRemove={(val) => handleRemoveFilter("state_group", val)}
values={value}
/>
)}
{filterKey === "project" && (
<AppliedProjectFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("project", val)}
values={value}
/>
)}
{filterKey === "cycle" && (
<AppliedCycleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("cycle", val)}
values={value}
/>
)}
{filterKey === "module" && (
<AppliedModuleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("module", val)}
values={value}
/>
)}
{filterKey === "issue_type" && (
<AppliedIssueTypeFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("issue_type", val)}
values={value}
/>
)}
{isEditingAllowed && (
<button
type="button"
className="grid place-items-center text-custom-text-300 hover:text-custom-text-200"
onClick={() => handleRemoveFilter(filterKey, null)}
>
<X size={12} strokeWidth={2} />
</button>
)}
</div>
</div>
<Tag key={filterKey}>
<span className="text-xs text-custom-text-300">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{membersFilters.includes(filterKey) && (
<AppliedMembersFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter(filterKey, val)}
values={value}
/>
)}
{dateFilters.includes(filterKey) && (
<AppliedDateFilters handleRemove={(val) => handleRemoveFilter(filterKey, val)} values={value} />
)}
{filterKey === "labels" && (
<AppliedLabelsFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("labels", val)}
labels={labels}
values={value}
/>
)}
{filterKey === "priority" && (
<AppliedPriorityFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("priority", val)}
values={value}
/>
)}
{filterKey === "state" && states && (
<AppliedStateFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("state", val)}
states={states}
values={value}
/>
)}
{filterKey === "state_group" && (
<AppliedStateGroupFilters handleRemove={(val) => handleRemoveFilter("state_group", val)} values={value} />
)}
{filterKey === "project" && (
<AppliedProjectFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("project", val)}
values={value}
/>
)}
{filterKey === "cycle" && (
<AppliedCycleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("cycle", val)}
values={value}
/>
)}
{filterKey === "module" && (
<AppliedModuleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("module", val)}
values={value}
/>
)}
{filterKey === "issue_type" && (
<AppliedIssueTypeFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("issue_type", val)}
values={value}
/>
)}
{isEditingAllowed && (
<button
type="button"
className="grid place-items-center text-custom-text-300 hover:text-custom-text-200"
onClick={() => handleRemoveFilter(filterKey, null)}
>
<X size={12} strokeWidth={2} />
</button>
)}
</Tag>
);
})}
{isEditingAllowed && (
<button
type="button"
onClick={handleClearAllFilters}
className="flex items-center gap-2 flex-shrink-0 rounded-md border border-custom-border-200 px-2 py-1 text-xs text-custom-text-300 hover:text-custom-text-200"
>
Clear all
<X size={12} strokeWidth={2} />
<button type="button" onClick={handleClearAllFilters}>
<Tag>
Clear all
<X size={12} strokeWidth={2} />
</Tag>
</button>
)}
</div>

View file

@ -29,7 +29,7 @@ export const AppliedMembersFilters: React.FC<Props> = observer((props) => {
return (
<div key={memberId} className="flex items-center gap-1 rounded bg-custom-background-80 p-1 text-xs">
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} />
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} size={"sm"} />
<span className="normal-case">{memberDetails.display_name}</span>
{editable && (
<button

View file

@ -2,7 +2,7 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { IIssueFilterOptions } from "@plane/types";
// hooks
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
@ -77,8 +77,8 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
if (Object.keys(appliedFilters).length === 0 || !workspaceSlug || !projectId || !cycleId) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<CustomHeader.LeftItem>
<Header variant={EHeaderVariant.TERNARY}>
<Header.LeftItem>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
@ -86,7 +86,7 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
labels={projectLabels ?? []}
states={projectStates}
/>
</CustomHeader.LeftItem>
</Header.LeftItem>
<SaveFilterView
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
@ -96,6 +96,6 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
display_properties: issueFilters?.displayProperties,
}}
/>
</CustomHeader>
</Header>
);
});

View file

@ -9,7 +9,7 @@ import { useParams } from "next/navigation";
import { IIssueFilterOptions, TStaticViewTypes } from "@plane/types";
//ui
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList } from "@/components/issues";
import { UpdateViewComponent } from "@/components/views/update-view-component";
import { CreateUpdateWorkspaceViewModal } from "@/components/workspace";
@ -133,7 +133,7 @@ export const GlobalViewsAppliedFiltersRoot = observer((props: Props) => {
if (areAppliedFiltersEmpty && areFiltersEqual) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<Header variant={EHeaderVariant.TERNARY}>
<CreateUpdateWorkspaceViewModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
@ -166,6 +166,6 @@ export const GlobalViewsAppliedFiltersRoot = observer((props: Props) => {
) : (
<></>
)}
</CustomHeader>
</Header>
);
});

View file

@ -2,7 +2,7 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { IIssueFilterOptions } from "@plane/types";
// hooks
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
@ -76,8 +76,8 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
if (!workspaceSlug || !projectId || !moduleId || Object.keys(appliedFilters).length === 0) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<CustomHeader.LeftItem>
<Header variant={EHeaderVariant.TERNARY}>
<Header.LeftItem>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
@ -85,7 +85,7 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
labels={projectLabels ?? []}
states={projectStates}
/>
</CustomHeader.LeftItem>
</Header.LeftItem>
<SaveFilterView
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
@ -95,6 +95,6 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
display_properties: issueFilters?.displayProperties,
}}
/>
</CustomHeader>
</Header>
);
});

View file

@ -3,7 +3,7 @@ import { useParams } from "next/navigation";
import { IIssueFilterOptions } from "@plane/types";
// hooks
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
// constants
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
@ -68,25 +68,29 @@ export const ProjectAppliedFiltersRoot: React.FC = observer(() => {
if (Object.keys(appliedFilters).length === 0) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
labels={projectLabels ?? []}
states={projectStates}
/>
{isEditingAllowed && (
<SaveFilterView
workspaceSlug={workspaceSlug}
projectId={projectId}
filterParams={{
filters: appliedFilters,
display_filters: issueFilters?.displayFilters,
display_properties: issueFilters?.displayProperties,
}}
<Header variant={EHeaderVariant.TERNARY}>
<Header.LeftItem>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
labels={projectLabels ?? []}
states={projectStates}
/>
)}
</CustomHeader>
</Header.LeftItem>
<Header.RightItem>
{isEditingAllowed && (
<SaveFilterView
workspaceSlug={workspaceSlug}
projectId={projectId}
filterParams={{
filters: appliedFilters,
display_filters: issueFilters?.displayFilters,
display_properties: issueFilters?.displayProperties,
}}
/>
)}
</Header.RightItem>
</Header>
);
});

View file

@ -8,7 +8,7 @@ import { useParams } from "next/navigation";
// types
import { IIssueFilterOptions } from "@plane/types";
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList } from "@/components/issues";
import { CreateUpdateProjectViewModal } from "@/components/views";
import { UpdateViewComponent } from "@/components/views/update-view-component";
@ -114,7 +114,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
const isOwner = viewDetails?.owned_by === data?.id;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<Header variant={EHeaderVariant.TERNARY}>
<CreateUpdateProjectViewModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
@ -128,7 +128,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
...viewFilters,
}}
/>
<CustomHeader.LeftItem>
<Header.LeftItem className="w-[70%]">
<AppliedFiltersList
appliedFilters={appliedFilters ?? {}}
handleClearAllFilters={handleClearAllFilters}
@ -137,15 +137,17 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
states={projectStates}
disableEditing={isLocked}
/>
</CustomHeader.LeftItem>
<UpdateViewComponent
isLocked={isLocked}
areFiltersEqual={!!areFiltersEqual}
isOwner={isOwner}
isAuthorizedUser={isAuthorizedUser}
setIsModalOpen={setIsModalOpen}
handleUpdateView={handleUpdateView}
/>
</CustomHeader>
</Header.LeftItem>
<Header.RightItem>
<UpdateViewComponent
isLocked={isLocked}
areFiltersEqual={!!areFiltersEqual}
isOwner={isOwner}
isAuthorizedUser={isAuthorizedUser}
setIsModalOpen={setIsModalOpen}
handleUpdateView={handleUpdateView}
/>
</Header.RightItem>
</Header>
);
});

View file

@ -192,7 +192,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
<DropIndicator isVisible={!isCurrentBlockDragging && isDraggingOverBlock} />
<div
// make Z-index higher at the beginning of drag, to have a issue drag image of issue block without any overlaps
className={cn("group/kanban-block relative p-1.5", { "z-[1]": isCurrentBlockDragging })}
className={cn("group/kanban-block relative mb-2", { "z-[1]": isCurrentBlockDragging })}
onDragStart={() => {
if (isDragAllowed) setIsCurrentBlockDragging(true);
else

View file

@ -14,6 +14,7 @@ import {
} from "@plane/types";
// constants
// hooks
import { ContentWrapper } from "@plane/ui";
import { useCycle, useKanbanView, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store";
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
// types
@ -134,7 +135,7 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
const isGroupByCreatedBy = group_by === "created_by";
return (
<div className={`relative w-full flex gap-2 px-2 ${sub_group_by ? "h-full" : "h-full"}`}>
<ContentWrapper className={`flex-row relative gap-4`}>
{list &&
list.length > 0 &&
list.map((subList: IGroupByColumn) => {
@ -149,7 +150,7 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
} `}
>
{sub_group_by === null && (
<div className="sticky top-0 z-[2] w-full flex-shrink-0 bg-custom-background-90 py-1">
<div className="sticky top-0 z-[2] w-full flex-shrink-0 bg-custom-background-90 py-1 mb-1">
<HeaderGroupByCard
sub_group_by={sub_group_by}
group_by={group_by}
@ -193,6 +194,6 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
</div>
);
})}
</div>
</ContentWrapper>
);
});

View file

@ -103,11 +103,11 @@ export const HeaderGroupByCard: FC<IHeaderGroupByCard> = observer((props) => {
/>
)}
<div
className={`relative flex flex-shrink-0 gap-2 p-1.5 ${
className={`relative flex flex-shrink-0 gap-2 py-1.5 ${
verticalAlignPosition ? `w-[44px] flex-col items-center` : `w-full flex-row items-center`
}`}
>
<div className="flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center overflow-hidden rounded-sm">
<div className="flex h-[20px] flex-shrink-0 items-center justify-center overflow-hidden rounded-sm">
{icon ? icon : <Circle width={14} strokeWidth={2} />}
</div>

View file

@ -217,8 +217,8 @@ export const KanbanGroup = observer((props: IKanbanGroup) => {
const isSubGroup = !!sub_group_id && sub_group_id !== "null";
const issueIds = isSubGroup
? (groupedIssueIds as TSubGroupedIssues)?.[groupId]?.[sub_group_id] ?? []
: (groupedIssueIds as TGroupedIssues)?.[groupId] ?? [];
? ((groupedIssueIds as TSubGroupedIssues)?.[groupId]?.[sub_group_id] ?? [])
: ((groupedIssueIds as TGroupedIssues)?.[groupId] ?? []);
const groupIssueCount = getGroupIssueCount(groupId, sub_group_id, false) ?? 0;

View file

@ -9,7 +9,7 @@ import { ChevronRight } from "lucide-react";
// types
import { TIssue, IIssueDisplayProperties, TIssueMap } from "@plane/types";
// ui
import { Spinner, Tooltip, ControlLink, setToast, TOAST_TYPE } from "@plane/ui";
import { Spinner, Tooltip, ControlLink, setToast, TOAST_TYPE, Row } from "@plane/ui";
// components
import { MultipleSelectEntityAction } from "@/components/core";
import { IssueProperties } from "@/components/issues/issue-layouts/properties";
@ -130,13 +130,13 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
};
//TODO: add better logic. This is to have a min width for ID/Key based on the length of project identifier
const keyMinWidth = ((projectIdentifier?.length ?? 0) + 5) * 7;
const keyMinWidth = (projectIdentifier?.length ?? 0) * 7;
return (
<div
<Row
ref={issueRef}
className={cn(
"group/list-block min-h-11 relative flex flex-col gap-3 bg-custom-background-100 hover:bg-custom-background-90 p-3 pl-1.5 text-sm transition-colors border border-transparent",
"group/list-block min-h-11 relative flex flex-col gap-3 bg-custom-background-100 hover:bg-custom-background-90 py-3 text-sm transition-colors border border-transparent",
{
"border-custom-primary-70": getIsIssuePeeked(issue.id) && peekIssue?.nestingLevel === nestingLevel,
"border-custom-border-400": isIssueActive,
@ -173,7 +173,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
disabled={issue.project_id === projectId}
renderByDefault={false}
>
<div className="flex-shrink-0 grid place-items-center w-3.5">
<div className="flex-shrink-0 grid place-items-center w-3.5 absolute left-1">
<MultipleSelectEntityAction
className={cn(
"opacity-0 pointer-events-none group-hover/list-block:opacity-100 group-hover/list-block:pointer-events-auto transition-opacity",
@ -190,7 +190,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
</Tooltip>
)}
{displayProperties && displayProperties?.key && (
<div className="flex-shrink-0 pl-2" style={{ minWidth: `${keyMinWidth}px` }}>
<div className="flex-shrink-0" style={{ minWidth: `${keyMinWidth}px` }}>
{issue.project_id && (
<IssueIdentifier
issueId={issueId}
@ -293,6 +293,6 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
</div>
)}
</div>
</div>
</Row>
);
});

View file

@ -86,12 +86,12 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => {
return (
<>
<div className="group/list-header relative w-full flex-shrink-0 flex items-center gap-2 py-1.5">
<div className="group/list-header w-full flex-shrink-0 flex items-center gap-2 py-1.5">
{canSelectIssues && (
<div className="flex-shrink-0 flex items-center w-3.5">
<div className="flex-shrink-0 flex items-center w-3.5 absolute left-1">
<MultipleSelectGroupAction
className={cn(
"size-3.5 opacity-0 pointer-events-none group-hover/list-header:opacity-100 group-hover/list-header:pointer-events-auto !outline-none",
"size-3.5 opacity-0 pointer-events-none group-hover/list-header:opacity-100 group-hover/list-header:pointer-events-auto !outline-none ",
{
"opacity-100 pointer-events-auto": !isGroupSelectionEmpty,
}
@ -106,8 +106,10 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => {
{icon ?? <CircleDashed className="size-3.5" strokeWidth={2} />}
</div>
<div className="relative flex w-full flex-row items-center gap-1 overflow-hidden cursor-pointer"
onClick={toggleListGroup}>
<div
className="relative flex w-full flex-row items-center gap-1 overflow-hidden cursor-pointer"
onClick={toggleListGroup}
>
<div className="inline-block line-clamp-1 truncate font-medium text-custom-text-100">{title}</div>
<div className="pl-2 text-sm font-medium text-custom-text-300">{count || 0}</div>
</div>

View file

@ -14,7 +14,7 @@ import {
TIssue,
IIssueDisplayProperties,
} from "@plane/types";
import { setToast, TOAST_TYPE } from "@plane/ui";
import { Row, setToast, TOAST_TYPE } from "@plane/ui";
// components
import { ListLoaderItemRow } from "@/components/ui";
// constants
@ -230,7 +230,7 @@ export const ListGroup = observer((props: Props) => {
"border-custom-error-200": isDraggingOverColumn && !!group.isDropDisabled,
})}
>
<div className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 pl-2 pr-3 py-1">
<Row className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 pr-3 py-1">
<HeaderGroupByCard
groupID={group.id}
icon={group.icon}
@ -243,7 +243,7 @@ export const ListGroup = observer((props: Props) => {
selectionHelpers={selectionHelpers}
toggleListGroup={toggleListGroup}
/>
</div>
</Row>
{shouldExpand && (
<div className="relative">
<GroupDragOverlay

View file

@ -33,6 +33,7 @@ export interface IIssuePropertyLabels {
placeholderText?: string;
onClose?: () => void;
renderByDefault?: boolean;
fullWidth?: boolean;
}
export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((props) => {
@ -52,6 +53,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
noLabelBorder = false,
placeholderText,
renderByDefault = true,
fullWidth = false,
} = props;
// router
const { workspaceSlug: routerWorkspaceSlug } = useParams();
@ -149,7 +151,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase()));
const label = (
<div className="flex h-5 w-full flex-wrap items-center gap-2 overflow-hidden">
<div className="flex h-full w-full flex-wrap items-center gap-2 overflow-hidden">
{value.length > 0 ? (
value.length <= maxRender ? (
<>
@ -168,7 +170,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
key={label?.id}
className={`flex overflow-hidden hover:bg-custom-background-80 ${
!disabled && "cursor-pointer"
} h-full max-w-full flex-shrink-0 items-center rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 text-xs`}
} h-full ${fullWidth && "w-full"} max-w-full flex-shrink-0 items-center rounded px-2.5 text-xs ${noLabelBorder ? "rounded-none" : "border-[0.5px] border-custom-border-300"}`}
>
<div className="flex max-w-full items-center gap-1.5 overflow-hidden text-custom-text-200">
<span
@ -185,9 +187,9 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
</>
) : (
<div
className={`flex h-full flex-shrink-0 items-center rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 text-xs ${
className={`flex h-full ${fullWidth && "w-full"} flex-shrink-0 items-center rounded px-2.5 text-xs ${
disabled ? "cursor-not-allowed" : "cursor-pointer"
}`}
} ${noLabelBorder ? "rounded-none" : "border-[0.5px] border-custom-border-300"}`}
>
<Tooltip
isMobile={isMobile}
@ -215,8 +217,8 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
renderByDefault={false}
>
<div
className={`flex h-full items-center justify-center gap-2 rounded px-2.5 py-1 text-xs hover:bg-custom-background-80 ${
noLabelBorder ? "" : "border-[0.5px] border-custom-border-300"
className={`flex h-full ${fullWidth && "w-full"} items-center justify-center gap-2 rounded px-2.5 py-1 text-xs hover:bg-custom-background-80 ${
noLabelBorder ? "rounded-none" : "border-[0.5px] border-custom-border-300"
}`}
>
<Tags className="h-3.5 w-3.5" strokeWidth={2} />
@ -231,7 +233,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
<button
ref={setReferenceElement}
type="button"
className={`clickable flex w-full items-center justify-between gap-1 text-xs ${
className={`clickable flex w-full h-full items-center justify-between gap-1 text-xs ${fullWidth && "hover:bg-custom-background-80"} ${
disabled
? "cursor-not-allowed text-custom-text-200"
: value.length <= maxRender
@ -249,7 +251,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
<ComboDropDown
as="div"
ref={dropdownRef}
className={`w-auto max-w-full flex-shrink-0 text-left ${className}`}
className={`w-auto max-w-full h-full flex-shrink-0 text-left ${className}`}
value={value}
onChange={onChange}
disabled={disabled}
@ -261,7 +263,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
{isOpen && (
<Combobox.Options className="fixed z-10" static>
<div
className={`z-10 my-1 w-48 whitespace-nowrap rounded border border-custom-border-300 bg-custom-background-100 px-2 py-2.5 text-xs shadow-custom-shadow-rg focus:outline-none ${optionsClassName}`}
className={`z-10 my-1 w-48 h-auto whitespace-nowrap rounded border border-custom-border-300 bg-custom-background-100 px-2 py-2.5 text-xs shadow-custom-shadow-rg focus:outline-none ${optionsClassName}`}
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}

View file

@ -1,6 +1,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { PlusIcon } from "lucide-react";
import { Row } from "@plane/ui";
import { TQuickAddIssueButton } from "../root";
export const GanttQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
@ -9,11 +10,13 @@ export const GanttQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((prop
return (
<button
type="button"
className="sticky bottom-0 z-[1] flex w-full cursor-pointer items-center gap-2 border-t-[1px] border-custom-border-200 bg-custom-background-100 px-3 pt-2 text-custom-text-350 hover:text-custom-text-300"
className="sticky bottom-0 z-[1] flex w-full cursor-pointer items-center border-t-[1px] border-custom-border-200 bg-custom-background-100 text-custom-text-350 hover:text-custom-text-300"
onClick={onClick}
>
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
<span className="text-sm font-medium">New Issue</span>
<Row className="flex py-2 gap-2">
<PlusIcon className="h-3.5 w-3.5 stroke-2 my-auto" />
<span className="text-sm font-medium">New Issue</span>
</Row>
</button>
);
});

View file

@ -1,18 +1,19 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { PlusIcon } from "lucide-react";
import { Row } from "@plane/ui";
import { TQuickAddIssueButton } from "../root";
export const ListQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
const { onClick } = props;
return (
<div
className="flex w-full cursor-pointer items-center gap-2 px-2 py-3 text-custom-text-350 hover:text-custom-text-300"
<Row
className="flex w-full cursor-pointer items-center gap-2 py-3 text-custom-text-350 hover:text-custom-text-300"
onClick={onClick}
>
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
<span className="text-sm font-medium">New Issue</span>
</div>
</Row>
);
});

View file

@ -1,9 +1,10 @@
import React from "react"
import React from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import useSWR from "swr";
// mobx store
// components
import { Row, ERowVariant } from "@plane/ui";
import {
IssuePeekOverview,
ModuleAppliedFiltersRoot,
@ -62,9 +63,9 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
<IssuesStoreContext.Provider value={EIssuesStoreType.MODULE}>
<div className="relative flex h-full w-full flex-col overflow-hidden">
<ModuleAppliedFiltersRoot />
<div className="h-full w-full overflow-auto">
<Row variant={ERowVariant.HUGGING} className="h-full w-full overflow-auto">
<ModuleIssueLayout activeLayout={activeLayout} moduleId={moduleId?.toString()} />
</div>
</Row>
{/* peek overview */}
<IssuePeekOverview />
</div>

View file

@ -36,7 +36,7 @@ export const SpreadsheetAssigneeColumn: React.FC<Props> = observer((props: Props
buttonVariant={
issue?.assignee_ids && issue.assignee_ids.length > 1 ? "transparent-without-text" : "transparent-with-text"
}
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -2,6 +2,7 @@ import React from "react";
import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
import { Row } from "@plane/ui";
type Props = {
issue: TIssue;
@ -11,8 +12,8 @@ export const SpreadsheetAttachmentColumn: React.FC<Props> = observer((props) =>
const { issue } = props;
return (
<div className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
{issue?.attachment_count} {issue?.attachment_count === 1 ? "attachment" : "attachments"}
</div>
</Row>
);
});

View file

@ -3,6 +3,7 @@ import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
// helpers
import { Row } from "@plane/ui";
import { renderFormattedDate } from "@/helpers/date-time.helper";
type Props = {
@ -13,8 +14,8 @@ export const SpreadsheetCreatedOnColumn: React.FC<Props> = observer((props: Prop
const { issue } = props;
return (
<div className="flex h-11 w-full items-center justify-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
{renderFormattedDate(issue.created_at)}
</div>
</Row>
);
});

View file

@ -54,8 +54,8 @@ export const SpreadsheetCycleColumn: React.FC<Props> = observer((props) => {
disabled={disabled}
placeholder="Select cycle"
buttonVariant="transparent-with-text"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent px-0"
onClose={onClose}
/>
</div>

View file

@ -48,7 +48,7 @@ export const SpreadsheetDueDateColumn: React.FC<Props> = observer((props: Props)
buttonVariant="transparent-with-text"
buttonContainerClassName="w-full"
buttonClassName={cn(
"rounded-none text-left group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10",
"rounded-none text-left group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x",
{
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
}

View file

@ -25,7 +25,7 @@ export const SpreadsheetEstimateColumn: React.FC<Props> = observer((props: Props
projectId={issue.project_id ?? undefined}
disabled={disabled}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -11,7 +11,7 @@ import {
MoveRight,
} from "lucide-react";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, TIssueOrderByOptions } from "@plane/types";
import { CustomMenu } from "@plane/ui";
import { CustomMenu, Row } from "@plane/ui";
//hooks
import { SPREADSHEET_PROPERTY_DETAILS } from "@/constants/spreadsheet";
import useLocalStorage from "@/hooks/use-local-storage";
@ -51,7 +51,7 @@ export const HeaderColumn = (props: Props) => {
customButtonTabIndex={-1}
className="!w-full"
customButton={
<div className="flex w-full cursor-pointer items-center justify-between gap-1.5 py-2 text-sm text-custom-text-200 hover:text-custom-text-100">
<Row className="flex w-full cursor-pointer items-center justify-between gap-1.5 py-2 text-sm text-custom-text-200 hover:text-custom-text-100">
<div className="flex items-center gap-1.5">
{<propertyDetails.icon className="h-4 w-4 text-custom-text-400" />}
{propertyDetails.title}
@ -64,7 +64,7 @@ export const HeaderColumn = (props: Props) => {
)}
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</div>
</div>
</Row>
}
onMenuClose={onClose}
placement="bottom-start"

View file

@ -22,18 +22,22 @@ export const SpreadsheetLabelColumn: React.FC<Props> = observer((props: Props) =
const defaultLabelOptions = issue?.label_ids?.map((id) => labelMap[id]) || [];
return (
<IssuePropertyLabels
projectId={issue.project_id ?? null}
value={issue.label_ids}
defaultOptions={defaultLabelOptions}
onChange={(data) => onChange(issue, { label_ids: data }, { changed_property: "labels", change_details: data })}
className="h-11 w-full border-b-[0.5px] border-custom-border-200"
buttonClassName="px-2.5 h-full group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
hideDropdownArrow
maxRender={1}
disabled={disabled}
placeholderText="Select labels"
onClose={onClose}
/>
<div className="h-11 border-b-[0.5px] border-custom-border-200 w-full">
<IssuePropertyLabels
projectId={issue.project_id ?? null}
value={issue.label_ids}
defaultOptions={defaultLabelOptions}
onChange={(data) => onChange(issue, { label_ids: data }, { changed_property: "labels", change_details: data })}
className="h-full w-full "
buttonClassName="px-page-x w-full h-full group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 rounded-none"
hideDropdownArrow
maxRender={1}
disabled={disabled}
placeholderText="Select labels"
onClose={onClose}
noLabelBorder
fullWidth
/>
</div>
);
});

View file

@ -2,6 +2,7 @@ import React from "react";
import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
import { Row } from "@plane/ui";
type Props = {
issue: TIssue;
@ -11,8 +12,8 @@ export const SpreadsheetLinkColumn: React.FC<Props> = observer((props: Props) =>
const { issue } = props;
return (
<div className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x">
{issue?.link_count} {issue?.link_count === 1 ? "link" : "links"}
</div>
</Row>
);
});

View file

@ -64,8 +64,8 @@ export const SpreadsheetModuleColumn: React.FC<Props> = observer((props) => {
disabled={disabled}
placeholder="Select modules"
buttonVariant="transparent-with-text"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent !px-0"
onClose={onClose}
multiple
showCount

View file

@ -22,7 +22,7 @@ export const SpreadsheetPriorityColumn: React.FC<Props> = observer((props: Props
onChange={(data) => onChange(issue, { priority: data }, { changed_property: "priority", change_details: data })}
disabled={disabled}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -38,7 +38,7 @@ export const SpreadsheetStartDateColumn: React.FC<Props> = observer((props: Prop
placeholder="Start date"
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -23,7 +23,7 @@ export const SpreadsheetStateColumn: React.FC<Props> = observer((props) => {
onChange={(data) => onChange(issue, { state_id: data }, { changed_property: "state", change_details: data })}
disabled={disabled}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
showTooltip

View file

@ -4,6 +4,7 @@ import { useParams } from "next/navigation";
// types
import { TIssue } from "@plane/types";
// helpers
import { Row } from "@plane/ui";
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppRouter } from "@/hooks/use-app-router";
@ -22,20 +23,22 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
const subIssueCount = issue?.sub_issues_count ?? 0;
const redirectToIssueDetail = () => {
router.push(`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${issue.id}#sub-issues`);
router.push(
`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${issue.id}#sub-issues`
);
};
return (
<div
<Row
onClick={subIssueCount ? redirectToIssueDetail : () => {}}
className={cn(
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10",
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10",
{
"cursor-pointer": subIssueCount,
}
)}
>
{subIssueCount} {subIssueCount === 1 ? "sub-issue" : "sub-issues"}
</div>
</Row>
);
});

View file

@ -3,6 +3,7 @@ import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
// helpers
import { Row } from "@plane/ui";
import { renderFormattedDate } from "@/helpers/date-time.helper";
type Props = {
@ -13,8 +14,8 @@ export const SpreadsheetUpdatedOnColumn: React.FC<Props> = observer((props: Prop
const { issue } = props;
return (
<div className="flex h-11 w-full items-center justify-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
{renderFormattedDate(issue.updated_at)}
</div>
</Row>
);
});

View file

@ -7,7 +7,7 @@ import { ChevronRight, MoreHorizontal } from "lucide-react";
// types
import { IIssueDisplayProperties, TIssue } from "@plane/types";
// ui
import { ControlLink, Tooltip } from "@plane/ui";
import { ControlLink, Row, Tooltip } from "@plane/ui";
// components
import { MultipleSelectEntityAction } from "@/components/core";
import RenderIfVisible from "@/components/core/render-if-visible-HOC";
@ -237,7 +237,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
id={`issue-${issueId}`}
ref={cellRef}
tabIndex={0}
className="sticky left-0 z-10 group/list-block bg-custom-background-100"
className="relative md:sticky left-0 z-10 group/list-block bg-custom-background-100"
>
<ControlLink
href={`/${workspaceSlug}/projects/${issueDetail.project_id}/issues/${issueId}`}
@ -253,97 +253,99 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
)}
disabled={!!issueDetail?.tempId}
>
<div className="flex items-center gap-0.5 min-w-min py-2.5 pl-2">
{/* select checkbox */}
{projectId && canSelectIssues && (
<Tooltip
tooltipContent={
<>
Only issues within the current
<br />
project can be selected.
</>
}
disabled={issueDetail.project_id === projectId}
>
<div className="flex-shrink-0 grid place-items-center w-3.5 mr-1">
<MultipleSelectEntityAction
className={cn(
"opacity-0 pointer-events-none group-hover/list-block:opacity-100 group-hover/list-block:pointer-events-auto transition-opacity",
{
"opacity-100 pointer-events-auto": isIssueSelected,
}
)}
groupId={SPREADSHEET_SELECT_GROUP}
id={issueDetail.id}
selectionHelpers={selectionHelpers}
disabled={issueDetail.project_id !== projectId}
/>
</div>
</Tooltip>
)}
{/* sub issues indentation */}
<div style={nestingLevel !== 0 ? { width: subIssueIndentation } : {}} />
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="key">
<div className="relative flex cursor-pointer items-center text-center text-xs hover:text-custom-text-100">
<p className={`flex font-medium leading-7`} style={{ minWidth: `${keyMinWidth}px` }}>
{issueDetail.project_id && (
<IssueIdentifier
issueId={issueDetail.id}
projectId={issueDetail.project_id}
textContainerClassName="text-sm md:text-xs text-custom-text-300"
/>
)}
</p>
</div>
</WithDisplayPropertiesHOC>
{/* sub-issues chevron */}
<div className="grid place-items-center size-4">
{subIssuesCount > 0 && (
<button
type="button"
className="grid place-items-center size-4 rounded-sm text-custom-text-400 hover:text-custom-text-300"
onClick={handleToggleExpand}
<Row className="flex item-center flex-row w-full">
<div className="flex items-center gap-0.5 min-w-min py-2.5">
{/* select checkbox */}
{projectId && canSelectIssues && (
<Tooltip
tooltipContent={
<>
Only issues within the current
<br />
project can be selected.
</>
}
disabled={issueDetail.project_id === projectId}
>
<ChevronRight
className={cn("size-4", {
"rotate-90": isExpanded,
})}
strokeWidth={2.5}
/>
</button>
)}
</div>
</div>
<div className="flex items-center gap-2 justify-between h-full w-full pr-4 pl-1 truncate">
<div className="w-full line-clamp-1 text-sm text-custom-text-100">
<div className="w-full overflow-hidden">
<Tooltip tooltipContent={issueDetail.name} isMobile={isMobile}>
<div
className="h-full w-full cursor-pointer truncate pr-4 text-left text-[0.825rem] text-custom-text-100 focus:outline-none"
tabIndex={-1}
>
{issueDetail.name}
<div className="flex-shrink-0 grid place-items-center w-3.5 mr-1 absolute left-1">
<MultipleSelectEntityAction
className={cn(
"opacity-0 pointer-events-none group-hover/list-block:opacity-100 group-hover/list-block:pointer-events-auto transition-opacity",
{
"opacity-100 pointer-events-auto": isIssueSelected,
}
)}
groupId={SPREADSHEET_SELECT_GROUP}
id={issueDetail.id}
selectionHelpers={selectionHelpers}
disabled={issueDetail.project_id !== projectId}
/>
</div>
</Tooltip>
)}
{/* sub issues indentation */}
{nestingLevel !== 0 && <div style={{ width: subIssueIndentation }} />}
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="key">
<div className="relative flex cursor-pointer items-center text-center text-xs hover:text-custom-text-100">
<p className={`flex font-medium leading-7`} style={{ minWidth: `${keyMinWidth}px` }}>
{issueDetail.project_id && (
<IssueIdentifier
issueId={issueDetail.id}
projectId={issueDetail.project_id}
textContainerClassName="text-sm md:text-xs text-custom-text-300"
/>
)}
</p>
</div>
</WithDisplayPropertiesHOC>
{/* sub-issues chevron */}
<div className="grid place-items-center size-4">
{subIssuesCount > 0 && (
<button
type="button"
className="grid place-items-center size-4 rounded-sm text-custom-text-400 hover:text-custom-text-300"
onClick={handleToggleExpand}
>
<ChevronRight
className={cn("size-4", {
"rotate-90": isExpanded,
})}
strokeWidth={2.5}
/>
</button>
)}
</div>
</div>
<div
className={`hidden group-hover:block ${isMenuActive ? "!block" : ""}`}
onClick={(e) => e.stopPropagation()}
>
{quickActions({
issue: issueDetail,
parentRef: cellRef,
customActionButton,
portalElement: portalElement.current,
})}
<div className="flex items-center gap-2 justify-between h-full w-full truncate my-auto">
<div className="w-full line-clamp-1 text-sm text-custom-text-100">
<div className="w-full overflow-hidden">
<Tooltip tooltipContent={issueDetail.name} isMobile={isMobile}>
<div
className="h-full w-full cursor-pointer truncate pr-4 text-left text-[0.825rem] text-custom-text-100 focus:outline-none"
tabIndex={-1}
>
{issueDetail.name}
</div>
</Tooltip>
</div>
</div>
<div
className={`hidden group-hover:block ${isMenuActive ? "!block" : ""}`}
onClick={(e) => e.stopPropagation()}
>
{quickActions({
issue: issueDetail,
parentRef: cellRef,
customActionButton,
portalElement: portalElement.current,
})}
</div>
</div>
</div>
</Row>
</ControlLink>
</td>
{/* Rest of the columns */}

View file

@ -28,7 +28,7 @@ export const SpreadsheetHeaderColumn = observer((props: Props) => {
shouldRenderProperty={() => shouldRenderProperty}
>
<th
className="h-11 w-full min-w-36 max-w-48 items-center bg-custom-background-90 text-sm font-medium px-4 py-1 border border-b-0 border-t-0 border-custom-border-100"
className="h-11 w-full min-w-36 max-w-48 items-center bg-custom-background-90 text-sm font-medium py-1 border border-b-0 border-t-0 border-custom-border-100"
ref={tableHeaderCellRef}
tabIndex={0}
>

View file

@ -3,6 +3,7 @@ import { useParams } from "next/navigation";
// ui
import { IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@plane/types";
// components
import { Row } from "@plane/ui";
import { MultipleSelectGroupAction } from "@/components/core";
import { SpreadsheetHeaderColumn } from "@/components/issues/issue-layouts";
// constants
@ -43,24 +44,26 @@ export const SpreadsheetHeader = observer((props: Props) => {
<thead className="sticky top-0 left-0 z-[12] border-b-[0.5px] border-custom-border-100">
<tr>
<th
className="group/list-header sticky left-0 z-[15] h-11 w-[28rem] flex items-center gap-1 bg-custom-background-90 text-sm font-medium before:absolute before:h-full before:right-0 before:border-[0.5px] before:border-custom-border-100 pl-2"
className="group/list-header sticky left-0 z-[15] h-11 w-[28rem] flex items-center gap-1 bg-custom-background-90 text-sm font-medium before:absolute before:h-full before:right-0 before:border-custom-border-100"
tabIndex={-1}
>
{canSelectIssues && (
<div className="flex-shrink-0 flex items-center w-3.5 mr-1">
<MultipleSelectGroupAction
className={cn(
"size-3.5 opacity-0 pointer-events-none group-hover/list-header:opacity-100 group-hover/list-header:pointer-events-auto !outline-none",
{
"opacity-100 pointer-events-auto": !isGroupSelectionEmpty,
}
)}
groupID={SPREADSHEET_SELECT_GROUP}
selectionHelpers={selectionHelpers}
/>
</div>
)}
<span className="flex h-full w-full flex-grow items-center py-2.5">Issues</span>
<Row>
{canSelectIssues && (
<div className="flex-shrink-0 flex items-center w-3.5 mr-1 absolute left-1 py-[11px]">
<MultipleSelectGroupAction
className={cn(
"size-3.5 opacity-0 pointer-events-none group-hover/list-header:opacity-100 group-hover/list-header:pointer-events-auto !outline-none",
{
"opacity-100 pointer-events-auto": !isGroupSelectionEmpty,
}
)}
groupID={SPREADSHEET_SELECT_GROUP}
selectionHelpers={selectionHelpers}
/>
</div>
)}
<span className="flex h-full w-full flex-grow items-center py-2.5">Issues</span>
</Row>
</th>
{spreadsheetColumnsList.map((property) => (

View file

@ -275,14 +275,14 @@ export const CreateUpdateIssueModalBase: React.FC<IssuesModalProps> = observer((
let response: TIssue | undefined = undefined;
try{
try {
if (!data?.id) response = await handleCreateIssue(payload, is_draft_issue);
else response = await handleUpdateIssue(payload);
}catch(error){
} catch (error) {
throw error;
}finally{
if (response != undefined && onSubmit) await onSubmit(response)
}
} finally {
if (response != undefined && onSubmit) await onSubmit(response);
}
};
const handleFormChange = (formData: Partial<TIssue> | null) => setChangesMade(formData);

View file

@ -158,7 +158,6 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
}, [data, projectId]);
const handleFormSubmit = async (formData: Partial<TIssue>, is_draft_issue = false) => {
// Check if the editor is ready to discard
if (!editorRef.current?.isEditorReadyToDiscard()) {
setToast({
@ -190,9 +189,9 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
// this condition helps to move the issues from draft to project issues
if (formData.hasOwnProperty("is_draft")) submitData.is_draft = formData.is_draft;
await onSubmit(submitData, is_draft_issue)
.then(() =>{
.then(() => {
setGptAssistantModal(false);
reset({
...defaultValues,
@ -203,8 +202,9 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
});
editorRef?.current?.clearEditor();
})
.catch((error) => {})
.catch((error) => {
console.error(error);
});
};
const condition =