[WEB-5600] chore: project identifier char limit updated and table layout enhancements (#8263)
This commit is contained in:
parent
7659997b53
commit
f0bc2bd3bd
23 changed files with 116 additions and 109 deletions
|
|
@ -239,11 +239,6 @@ const IssueRowDetails = observer(function IssueRowDetails(props: IssueRowDetails
|
|||
|
||||
const canSelectIssues = !disableUserActions && !selectionHelpers.isSelectionDisabled;
|
||||
|
||||
//TODO: add better logic. This is to have a min width for ID/Key based on the length of project identifier
|
||||
const keyMinWidth = displayProperties?.key
|
||||
? (getProjectIdentifierById(issueDetail.project_id)?.length ?? 0 + 5) * 7
|
||||
: 0;
|
||||
|
||||
const workItemLink = generateWorkItemLink({
|
||||
workspaceSlug: workspaceSlug?.toString(),
|
||||
projectId: issueDetail?.project_id,
|
||||
|
|
@ -255,11 +250,12 @@ const IssueRowDetails = observer(function IssueRowDetails(props: IssueRowDetails
|
|||
|
||||
return (
|
||||
<>
|
||||
{/* Single sticky column containing both identifier and workitem */}
|
||||
<td
|
||||
id={`issue-${issueId}`}
|
||||
ref={cellRef}
|
||||
tabIndex={0}
|
||||
className="relative md:sticky left-0 z-10 group/list-block bg-custom-background-100 min-w-60 max-w-[30vw]"
|
||||
className="relative md:sticky left-0 z-10 group/list-block bg-custom-background-100"
|
||||
>
|
||||
<ControlLink
|
||||
href={workItemLink}
|
||||
|
|
@ -278,7 +274,29 @@ const IssueRowDetails = observer(function IssueRowDetails(props: IssueRowDetails
|
|||
}
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-0.5 min-w-min py-2">
|
||||
{/* Identifier section - conditionally rendered */}
|
||||
{displayProperties?.key && (
|
||||
<div className="flex-shrink-0 flex items-center h-full min-w-24">
|
||||
<div className="relative flex cursor-pointer items-center text-xs hover:text-custom-text-100">
|
||||
{issueDetail.project_id && (
|
||||
<IssueIdentifier
|
||||
issueId={issueDetail.id}
|
||||
projectId={issueDetail.project_id}
|
||||
textContainerClassName="text-sm md:text-xs text-custom-text-300"
|
||||
displayProperties={displayProperties}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Workitem section */}
|
||||
<div
|
||||
className={cn("flex items-center gap-0.5 py-2 flex-grow", {
|
||||
"min-w-[360px]": !displayProperties?.key,
|
||||
"min-w-60": displayProperties?.key,
|
||||
})}
|
||||
>
|
||||
{/* select checkbox */}
|
||||
{projectId && canSelectIssues && (
|
||||
<Tooltip
|
||||
|
|
@ -311,21 +329,6 @@ const IssueRowDetails = observer(function IssueRowDetails(props: IssueRowDetails
|
|||
{/* sub issues indentation */}
|
||||
{nestingLevel !== 0 && <div style={{ width: subIssueIndentation }} />}
|
||||
|
||||
{(displayProperties?.key || displayProperties?.issue_type) && (
|
||||
<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"
|
||||
displayProperties={displayProperties}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* sub-issues chevron */}
|
||||
<div className="grid place-items-center size-4">
|
||||
{subIssuesCount > 0 && !isEpic && (
|
||||
|
|
@ -343,31 +346,31 @@ const IssueRowDetails = observer(function IssueRowDetails(props: IssueRowDetails
|
|||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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 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={`opacity-0 group-hover:opacity-100 transition-opacity ${isMenuActive ? "!opacity-100" : ""}`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{quickActions({
|
||||
issue: issueDetail,
|
||||
parentRef: cellRef,
|
||||
customActionButton,
|
||||
portalElement: portalElement.current,
|
||||
})}
|
||||
</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>
|
||||
</Row>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { SPREADSHEET_SELECT_GROUP } from "@plane/constants";
|
|||
// ui
|
||||
import type { IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@plane/types";
|
||||
// components
|
||||
import { Row } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
import { MultipleSelectGroupAction } from "@/components/core/multiple-select";
|
||||
// hooks
|
||||
|
|
@ -44,27 +43,31 @@ export const SpreadsheetHeader = observer(function SpreadsheetHeader(props: Prop
|
|||
return (
|
||||
<thead className="sticky top-0 left-0 z-[12] border-b-[0.5px] border-custom-border-100">
|
||||
<tr>
|
||||
{/* Single header column containing both identifier and workitem */}
|
||||
<th
|
||||
className="group/list-header sticky min-w-60 left-0 z-[15] h-11 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"
|
||||
className="group/list-header md:sticky min-w-60 left-0 z-[15] h-11 bg-custom-background-90 text-sm font-medium border-r-[0.5px] border-custom-border-100"
|
||||
tabIndex={-1}
|
||||
>
|
||||
<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">{`${isEpic ? "Epics" : "Work items"}`}</span>
|
||||
</Row>
|
||||
<div className="flex items-center gap-2 h-full w-full px-page-x">
|
||||
{/* Workitem header section */}
|
||||
<div className="flex items-center gap-1 flex-grow h-full py-2.5 min-w-80">
|
||||
{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="text-sm font-medium">{`${isEpic ? "Epics" : "Work items"}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
{spreadsheetColumnsList.map((property) => (
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ function ProjectCommonAttributes(props: Props) {
|
|||
return;
|
||||
}
|
||||
if (e.target.value === "") setValue("identifier", "");
|
||||
else setValue("identifier", projectIdentifierSanitizer(e.target.value).substring(0, 5));
|
||||
else setValue("identifier", projectIdentifierSanitizer(e.target.value).substring(0, 10));
|
||||
onChange(e);
|
||||
handleFormOnChange?.();
|
||||
};
|
||||
|
|
@ -91,11 +91,11 @@ function ProjectCommonAttributes(props: Props) {
|
|||
/^[ÇŞĞIİÖÜA-Z0-9]+$/.test(value.toUpperCase()) || t("only_alphanumeric_non_latin_characters_allowed"),
|
||||
minLength: {
|
||||
value: 1,
|
||||
message: t("project_id_must_be_at_least_1_character"),
|
||||
message: t("project_id_min_char"),
|
||||
},
|
||||
maxLength: {
|
||||
value: 5,
|
||||
message: t("project_id_must_be_at_most_5_characters"),
|
||||
value: 10,
|
||||
message: t("project_id_max_char"),
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
|
|||
|
||||
if (project.identifier !== formData.identifier)
|
||||
await projectService
|
||||
.checkProjectIdentifierAvailability(workspaceSlug as string, payload.identifier ?? "")
|
||||
.checkProjectIdentifierAvailability(workspaceSlug, payload.identifier ?? "")
|
||||
.then(async (res) => {
|
||||
if (res.exists) setError("identifier", { message: t("common.identifier_already_exists") });
|
||||
else await handleUpdateChange(payload);
|
||||
|
|
@ -338,7 +338,7 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
|
|||
message: t("project_id_min_char"),
|
||||
},
|
||||
maxLength: {
|
||||
value: 5,
|
||||
value: 10,
|
||||
message: t("project_id_max_char"),
|
||||
},
|
||||
}}
|
||||
|
|
@ -359,7 +359,7 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
|
|||
/>
|
||||
<Tooltip
|
||||
isMobile={isMobile}
|
||||
tooltipContent="Helps you identify work items in the project uniquely. Max 5 characters."
|
||||
tooltipContent={t("project_id_tooltip_content")}
|
||||
className="text-sm"
|
||||
position="right-start"
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue