forked from github/plane
feat: spreadsheet view improvements (#1379)
* feat: quick menu for spreadsheet view added ,style: spreadsheet view column updated ,fix: z-index issue * feat: sorting indicator, style: spreadsheet column
This commit is contained in:
parent
ca7d3309d3
commit
160cc014a7
@ -128,15 +128,15 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-brand-surface-2 border-b border-brand-base w-full min-w-max"
|
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-brand-surface-2 border-b border-brand-base w-full min-w-max"
|
||||||
style={{ gridTemplateColumns }}
|
style={{ gridTemplateColumns }}
|
||||||
>
|
>
|
||||||
<div className="flex gap-1.5 items-center px-4 sticky left-0 z-10 text-brand-secondary bg-brand-base group-hover:text-brand-base group-hover:bg-brand-surface-2 border-brand-base w-full">
|
<div className="flex gap-1.5 items-center px-4 sticky left-0 z-[1] text-brand-secondary bg-brand-base group-hover:text-brand-base group-hover:bg-brand-surface-2 border-brand-base w-full">
|
||||||
<span className="flex gap-1 items-center" style={issue.parent ? { paddingLeft } : {}}>
|
<span className="flex gap-1 items-center" style={issue.parent ? { paddingLeft } : {}}>
|
||||||
{properties.key && (
|
<div className="flex items-center cursor-pointer text-xs text-center hover:text-brand-base w-14 opacity-100 group-hover:opacity-0">
|
||||||
<>
|
{properties.key && (
|
||||||
<div className="flex items-center cursor-pointer text-xs text-center hover:text-brand-base w-14 ">
|
<span>
|
||||||
{issue.project_detail?.identifier}-{issue.sequence_id}
|
{issue.project_detail?.identifier}-{issue.sequence_id}
|
||||||
</div>
|
</span>
|
||||||
</>
|
)}
|
||||||
)}
|
</div>
|
||||||
|
|
||||||
<div className="h-5 w-5">
|
<div className="h-5 w-5">
|
||||||
{issue.sub_issues_count > 0 && (
|
{issue.sub_issues_count > 0 && (
|
||||||
@ -237,9 +237,14 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="absolute top-2.5 right-2.5 z-30 cursor-pointer opacity-0 group-hover:opacity-100">
|
<div
|
||||||
|
className="absolute top-2.5 z-10 cursor-pointer opacity-0 group-hover:opacity-100"
|
||||||
|
style={{
|
||||||
|
left: `${nestingLevel * 68 + 24}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{!isNotAllowed && (
|
{!isNotAllowed && (
|
||||||
<CustomMenu width="auto" ellipsis>
|
<CustomMenu width="auto" position="left" ellipsis>
|
||||||
<CustomMenu.MenuItem onClick={handleEditIssue}>
|
<CustomMenu.MenuItem onClick={handleEditIssue}>
|
||||||
<div className="flex items-center justify-start gap-2">
|
<div className="flex items-center justify-start gap-2">
|
||||||
<PencilIcon className="h-4 w-4" />
|
<PencilIcon className="h-4 w-4" />
|
||||||
|
@ -19,13 +19,17 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
"spreadsheetViewSorting",
|
"spreadsheetViewSorting",
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
const { storedValue: activeSortingProperty, setValue: setActiveSortingProperty } =
|
||||||
|
useLocalStorage("spreadsheetViewActiveSortingProperty", "");
|
||||||
|
|
||||||
const { orderBy, setOrderBy } = useSpreadsheetIssuesView();
|
const { orderBy, setOrderBy } = useSpreadsheetIssuesView();
|
||||||
|
|
||||||
const handleOrderBy = (order: TIssueOrderByOptions, itemKey: string) => {
|
const handleOrderBy = (order: TIssueOrderByOptions, itemKey: string) => {
|
||||||
setOrderBy(order);
|
setOrderBy(order);
|
||||||
setSelectedMenuItem(`${order}_${itemKey}`);
|
setSelectedMenuItem(`${order}_${itemKey}`);
|
||||||
|
setActiveSortingProperty(order === "-created_at" ? "" : itemKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`grid auto-rows-[minmax(36px,1fr)] w-full min-w-max`}
|
className={`grid auto-rows-[minmax(36px,1fr)] w-full min-w-max`}
|
||||||
@ -35,39 +39,34 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
if (col.isActive) {
|
if (col.isActive) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`bg-brand-surface-2 ${
|
className={`bg-brand-surface-1 w-full ${
|
||||||
col.propertyName === "title" ? "sticky left-0 z-20 bg-brand-surface-2 pl-24" : ""
|
col.propertyName === "title" ? "sticky left-0 z-[2] bg-brand-surface-1 pl-24" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{col.propertyName === "title" || col.propertyName === "priority" ? (
|
{col.propertyName === "title" ? (
|
||||||
<div
|
<div
|
||||||
className={`flex items-center justify-start gap-1.5 cursor-default text-sm text-brand-secondary text-current py-2.5 px-2`}
|
className={`flex items-center justify-start gap-1.5 cursor-default text-sm text-brand-secondary text-current w-full py-2.5 px-2`}
|
||||||
>
|
>
|
||||||
{col.icon ? (
|
|
||||||
<col.icon
|
|
||||||
className={`text-brand-secondary ${
|
|
||||||
col.propertyName === "estimate" ? "-rotate-90" : ""
|
|
||||||
}`}
|
|
||||||
aria-hidden="true"
|
|
||||||
height="14"
|
|
||||||
width="14"
|
|
||||||
/>
|
|
||||||
) : col.propertyName === "priority" ? (
|
|
||||||
<span className="text-sm material-symbols-rounded text-brand-secondary">
|
|
||||||
signal_cellular_alt
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)}
|
|
||||||
|
|
||||||
{col.colName}
|
{col.colName}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
|
className="!w-full"
|
||||||
customButton={
|
customButton={
|
||||||
<div
|
<div
|
||||||
className={`group flex items-center justify-start gap-1.5 cursor-pointer text-sm text-brand-secondary text-current hover:text-brand-base py-2.5 px-2`}
|
className={`relative group flex items-center justify-start gap-1.5 cursor-pointer text-sm text-brand-secondary text-current hover:text-brand-base w-full py-3 px-2 ${
|
||||||
|
activeSortingProperty === col.propertyName ? "bg-brand-surface-2" : ""
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
|
{activeSortingProperty === col.propertyName && (
|
||||||
|
<div className="absolute top-1 right-1.5">
|
||||||
|
<Icon
|
||||||
|
iconName="filter_list"
|
||||||
|
className="flex items-center justify-center h-3.5 w-3.5 rounded-full bg-brand-accent text-xs text-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{col.icon ? (
|
{col.icon ? (
|
||||||
<col.icon
|
<col.icon
|
||||||
className={`text-brand-secondary group-hover:text-brand-base ${
|
className={`text-brand-secondary group-hover:text-brand-base ${
|
||||||
@ -110,25 +109,42 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
: "text-brand-secondary hover:text-brand-base"
|
: "text-brand-secondary hover:text-brand-base"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-1.5 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
{col.propertyName === "assignee" || col.propertyName === "labels" ? (
|
{col.propertyName === "assignee" || col.propertyName === "labels" ? (
|
||||||
<>
|
<>
|
||||||
<span>A-Z</span>
|
<span className="relative flex items-center h-6 w-6">
|
||||||
<span>Ascending</span>
|
<Icon
|
||||||
|
iconName="east"
|
||||||
|
className="absolute left-0 rotate-90 text-xs leading-3"
|
||||||
|
/>
|
||||||
|
<Icon iconName="sort" className="absolute right-0 text-sm" />
|
||||||
|
</span>
|
||||||
|
<span>A</span>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<span>Z</span>
|
||||||
</>
|
</>
|
||||||
) : col.propertyName === "due_date" ? (
|
) : col.propertyName === "due_date" ? (
|
||||||
<>
|
<>
|
||||||
<span>1-9</span>
|
<span className="relative flex items-center h-6 w-6">
|
||||||
<span>Ascending</span>
|
<Icon
|
||||||
</>
|
iconName="east"
|
||||||
) : col.propertyName === "estimate" ? (
|
className="absolute left-0 rotate-90 text-xs leading-3"
|
||||||
<>
|
/>
|
||||||
<span>0</span>
|
<Icon iconName="sort" className="absolute right-0 text-sm" />
|
||||||
|
</span>
|
||||||
|
<span>New</span>
|
||||||
<Icon iconName="east" className="text-sm" />
|
<Icon iconName="east" className="text-sm" />
|
||||||
<span>10</span>
|
<span>Old</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
<span className="relative flex items-center h-6 w-6">
|
||||||
|
<Icon
|
||||||
|
iconName="east"
|
||||||
|
className="absolute left-0 rotate-90 text-xs leading-3"
|
||||||
|
/>
|
||||||
|
<Icon iconName="sort" className="absolute right-0 text-sm" />
|
||||||
|
</span>
|
||||||
<span>First</span>
|
<span>First</span>
|
||||||
<Icon iconName="east" className="text-sm" />
|
<Icon iconName="east" className="text-sm" />
|
||||||
<span>Last</span>
|
<span>Last</span>
|
||||||
@ -146,7 +162,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
className={`${
|
className={`mt-0.5 ${
|
||||||
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
||||||
? "bg-brand-surface-2"
|
? "bg-brand-surface-2"
|
||||||
: ""
|
: ""
|
||||||
@ -163,25 +179,51 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
: "text-brand-secondary hover:text-brand-base"
|
: "text-brand-secondary hover:text-brand-base"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-1.5 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
{col.propertyName === "assignee" || col.propertyName === "labels" ? (
|
{col.propertyName === "assignee" || col.propertyName === "labels" ? (
|
||||||
<>
|
<>
|
||||||
<span>Z-A</span>
|
<span className="relative flex items-center h-6 w-6">
|
||||||
<span>Descending</span>
|
<Icon
|
||||||
|
iconName="east"
|
||||||
|
className="absolute left-0 -rotate-90 text-xs leading-3"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
iconName="sort"
|
||||||
|
className="absolute rotate-180 transform scale-x-[-1] right-0 text-sm"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>Z</span>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<span>A</span>
|
||||||
</>
|
</>
|
||||||
) : col.propertyName === "due_date" ? (
|
) : col.propertyName === "due_date" ? (
|
||||||
<>
|
<>
|
||||||
<span>9-1</span>
|
<span className="relative flex items-center h-6 w-6">
|
||||||
<span>Descending</span>
|
<Icon
|
||||||
</>
|
iconName="east"
|
||||||
) : col.propertyName === "estimate" ? (
|
className="absolute left-0 -rotate-90 text-xs leading-3"
|
||||||
<>
|
/>
|
||||||
<span>10</span>
|
<Icon
|
||||||
|
iconName="sort"
|
||||||
|
className="absolute rotate-180 transform scale-x-[-1] right-0 text-sm"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>Old</span>
|
||||||
<Icon iconName="east" className="text-sm" />
|
<Icon iconName="east" className="text-sm" />
|
||||||
<span>0</span>
|
<span>New</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
<span className="relative flex items-center h-6 w-6">
|
||||||
|
<Icon
|
||||||
|
iconName="east"
|
||||||
|
className="absolute left-0 -rotate-90 text-xs leading-3"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
iconName="sort"
|
||||||
|
className="absolute rotate-180 transform scale-x-[-1] right-0 text-sm"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
<span>Last</span>
|
<span>Last</span>
|
||||||
<Icon iconName="east" className="text-sm" />
|
<Icon iconName="east" className="text-sm" />
|
||||||
<span>First</span>
|
<span>First</span>
|
||||||
@ -198,38 +240,32 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
<CustomMenu.MenuItem
|
{selectedMenuItem &&
|
||||||
className={`${
|
selectedMenuItem !== "" &&
|
||||||
selectedMenuItem === `-created_at_${col.propertyName}`
|
orderBy !== "-created_at" &&
|
||||||
? "bg-brand-surface-2"
|
selectedMenuItem.includes(col.propertyName) && (
|
||||||
: ""
|
<CustomMenu.MenuItem
|
||||||
}`}
|
className={`mt-0.5${
|
||||||
key={col.property}
|
|
||||||
onClick={() => {
|
|
||||||
handleOrderBy("-created_at", col.propertyName);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
|
||||||
selectedMenuItem === `-created_at_${col.propertyName}`
|
|
||||||
? "text-brand-base"
|
|
||||||
: "text-brand-secondary hover:text-brand-base"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="flex gap-1.5 items-center">
|
|
||||||
<Icon iconName="block" className="text-sm" />
|
|
||||||
<span>None</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CheckIcon
|
|
||||||
className={`h-3.5 w-3.5 opacity-0 group-hover:opacity-100 ${
|
|
||||||
selectedMenuItem === `-created_at_${col.propertyName}`
|
selectedMenuItem === `-created_at_${col.propertyName}`
|
||||||
? "opacity-100"
|
? "bg-brand-surface-2"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
/>
|
key={col.property}
|
||||||
</div>
|
onClick={() => {
|
||||||
</CustomMenu.MenuItem>
|
handleOrderBy("-created_at", col.propertyName);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={`group flex gap-1.5 px-1 items-center justify-between `}>
|
||||||
|
<div className="flex gap-1.5 items-center">
|
||||||
|
<span className="relative flex items-center justify-center h-6 w-6">
|
||||||
|
<Icon iconName="ink_eraser" className="text-sm" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>Clear sorting</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CustomMenu.MenuItem>
|
||||||
|
)}
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,7 +56,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full rounded-lg text-brand-secondary overflow-x-auto whitespace-nowrap bg-brand-base">
|
<div className="h-full rounded-lg text-brand-secondary overflow-x-auto whitespace-nowrap bg-brand-base">
|
||||||
<div className="sticky z-20 top-0 border-b border-brand-base bg-brand-surface-2 w-full min-w-max">
|
<div className="sticky z-[2] top-0 border-b border-brand-base bg-brand-surface-1 w-full min-w-max">
|
||||||
<SpreadsheetColumns columnData={columnData} gridTemplateColumns={gridTemplateColumns} />
|
<SpreadsheetColumns columnData={columnData} gridTemplateColumns={gridTemplateColumns} />
|
||||||
</div>
|
</div>
|
||||||
{spreadsheetIssues ? (
|
{spreadsheetIssues ? (
|
||||||
|
@ -24,6 +24,8 @@ export const SPREADSHEET_COLUMN = [
|
|||||||
propertyName: "priority",
|
propertyName: "priority",
|
||||||
colName: "Priority",
|
colName: "Priority",
|
||||||
colSize: "128px",
|
colSize: "128px",
|
||||||
|
ascendingOrder: "priority",
|
||||||
|
descendingOrder: "-priority",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
propertyName: "assignee",
|
propertyName: "assignee",
|
||||||
|
Loading…
Reference in New Issue
Block a user