forked from github/plane
Merge pull request #2304 from makeplane/develop
promote: develop to stage release
This commit is contained in:
commit
26bb51e686
@ -83,88 +83,89 @@ export const IssueColumn: React.FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="group flex items-center w-[28rem] text-sm h-11 sticky top-0 bg-custom-background-100 truncate border-b border-r border-custom-border-100">
|
<div className="group flex items-center w-[28rem] text-sm h-11 sticky top-0 bg-custom-background-100 truncate border-b border-r border-custom-border-100">
|
||||||
<div
|
{properties.key && (
|
||||||
className="flex gap-1.5 px-4 pr-0 py-2.5 items-center w-24"
|
<div
|
||||||
style={issue.parent && nestingLevel !== 0 ? { paddingLeft } : {}}
|
className="flex gap-1.5 px-4 pr-0 py-2.5 items-center min-w-[96px]"
|
||||||
>
|
style={issue.parent && nestingLevel !== 0 ? { paddingLeft } : {}}
|
||||||
<div className="relative flex items-center cursor-pointer text-xs text-center hover:text-custom-text-100">
|
>
|
||||||
{properties.key && (
|
<div className="relative flex items-center cursor-pointer text-xs text-center hover:text-custom-text-100">
|
||||||
<span className="flex items-center justify-center font-medium opacity-100 group-hover:opacity-0">
|
<span className="flex items-center justify-center font-medium opacity-100 group-hover:opacity-0 ">
|
||||||
{issue.project_detail?.identifier}-{issue.sequence_id}
|
{issue.project_detail?.identifier}-{issue.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
)}
|
|
||||||
{!isNotAllowed && !disableUserActions && (
|
|
||||||
<div className="absolute top-0 left-2.5 opacity-0 group-hover:opacity-100">
|
|
||||||
<Popover2
|
|
||||||
isOpen={isOpen}
|
|
||||||
canEscapeKeyClose
|
|
||||||
onInteraction={(nextOpenState) => setIsOpen(nextOpenState)}
|
|
||||||
content={
|
|
||||||
<div
|
|
||||||
className={`flex flex-col gap-1.5 overflow-y-scroll whitespace-nowrap rounded-md border p-1 text-xs shadow-lg focus:outline-none max-h-44 min-w-full border-custom-border-100 bg-custom-background-90`}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
|
||||||
onClick={() => {
|
|
||||||
handleEditIssue(issue);
|
|
||||||
setIsOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-start gap-2">
|
|
||||||
<PencilIcon className="h-4 w-4" />
|
|
||||||
<span>Edit issue</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
{!isNotAllowed && !disableUserActions && (
|
||||||
type="button"
|
<div className="absolute top-0 left-2.5 opacity-0 group-hover:opacity-100">
|
||||||
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
<Popover2
|
||||||
onClick={() => {
|
isOpen={isOpen}
|
||||||
handleDeleteIssue(issue);
|
canEscapeKeyClose
|
||||||
setIsOpen(false);
|
onInteraction={(nextOpenState) => setIsOpen(nextOpenState)}
|
||||||
}}
|
content={
|
||||||
|
<div
|
||||||
|
className={`flex flex-col gap-1.5 overflow-y-scroll whitespace-nowrap rounded-md border p-1 text-xs shadow-lg focus:outline-none max-h-44 min-w-full border-custom-border-100 bg-custom-background-90`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-start gap-2">
|
<button
|
||||||
<TrashIcon className="h-4 w-4" />
|
type="button"
|
||||||
<span>Delete issue</span>
|
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
||||||
</div>
|
onClick={() => {
|
||||||
</button>
|
handleEditIssue(issue);
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-start gap-2">
|
||||||
|
<PencilIcon className="h-4 w-4" />
|
||||||
|
<span>Edit issue</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleCopyText();
|
handleDeleteIssue(issue);
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-start gap-2">
|
<div className="flex items-center justify-start gap-2">
|
||||||
<LinkIcon className="h-4 w-4" />
|
<TrashIcon className="h-4 w-4" />
|
||||||
<span>Copy issue link</span>
|
<span>Delete issue</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
}
|
<button
|
||||||
placement="bottom-start"
|
type="button"
|
||||||
|
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
||||||
|
onClick={() => {
|
||||||
|
handleCopyText();
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-start gap-2">
|
||||||
|
<LinkIcon className="h-4 w-4" />
|
||||||
|
<span>Copy issue link</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<EllipsisHorizontalIcon className="h-5 w-5 text-custom-text-200" />
|
||||||
|
</Popover2>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{issue.sub_issues_count > 0 && (
|
||||||
|
<div className="h-6 w-6 flex justify-center items-center">
|
||||||
|
<button
|
||||||
|
className="h-5 w-5 hover:bg-custom-background-90 hover:text-custom-text-100 rounded-sm cursor-pointer"
|
||||||
|
onClick={() => handleToggleExpand(issue.id)}
|
||||||
>
|
>
|
||||||
<EllipsisHorizontalIcon className="h-5 w-5 text-custom-text-200" />
|
<Icon iconName="chevron_right" className={`${expanded ? "rotate-90" : ""}`} />
|
||||||
</Popover2>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
{issue.sub_issues_count > 0 && (
|
|
||||||
<div className="h-6 w-6 flex justify-center items-center">
|
|
||||||
<button
|
|
||||||
className="h-5 w-5 hover:bg-custom-background-90 hover:text-custom-text-100 rounded-sm cursor-pointer"
|
|
||||||
onClick={() => handleToggleExpand(issue.id)}
|
|
||||||
>
|
|
||||||
<Icon iconName="chevron_right" className={`${expanded ? "rotate-90" : ""}`} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<span className="flex items-center px-4 py-2.5 h-full truncate flex-grow">
|
<span className="flex items-center px-4 py-2.5 h-full truncate flex-grow">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -82,7 +82,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId, workspaceViewId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, viewId, globalViewId } = router.query;
|
||||||
|
|
||||||
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
||||||
|
|
||||||
@ -129,7 +129,17 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
router.pathname.includes(path.path)
|
router.pathname.includes(path.path)
|
||||||
);
|
);
|
||||||
|
|
||||||
const { params: workspaceViewParams, handleFilters } = useWorkspaceView();
|
const {
|
||||||
|
params: workspaceViewParams,
|
||||||
|
filters: workspaceViewFilters,
|
||||||
|
handleFilters,
|
||||||
|
} = useWorkspaceView();
|
||||||
|
|
||||||
|
const workspaceViewProperties = workspaceViewFilters.display_properties;
|
||||||
|
|
||||||
|
const isWorkspaceView = globalViewId || currentWorkspaceIssuePath;
|
||||||
|
|
||||||
|
const currentViewProperties = isWorkspaceView ? workspaceViewProperties : properties;
|
||||||
|
|
||||||
const { params, displayFilters, setDisplayFilters } = useSpreadsheetIssuesView();
|
const { params, displayFilters, setDisplayFilters } = useSpreadsheetIssuesView();
|
||||||
|
|
||||||
@ -143,8 +153,8 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
|
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
|
||||||
: viewId
|
: viewId
|
||||||
? VIEW_ISSUES(viewId.toString(), params)
|
? VIEW_ISSUES(viewId.toString(), params)
|
||||||
: workspaceViewId
|
: globalViewId
|
||||||
? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), workspaceViewParams)
|
? WORKSPACE_VIEW_ISSUES(globalViewId.toString(), workspaceViewParams)
|
||||||
: currentWorkspaceIssuePath
|
: currentWorkspaceIssuePath
|
||||||
? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), currentWorkspaceIssuePath?.params)
|
? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), currentWorkspaceIssuePath?.params)
|
||||||
: PROJECT_ISSUES_LIST_WITH_PARAMS(issue.project_detail.id, params);
|
: PROJECT_ISSUES_LIST_WITH_PARAMS(issue.project_detail.id, params);
|
||||||
@ -213,7 +223,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
cycleId,
|
cycleId,
|
||||||
moduleId,
|
moduleId,
|
||||||
viewId,
|
viewId,
|
||||||
workspaceViewId,
|
globalViewId,
|
||||||
workspaceViewParams,
|
workspaceViewParams,
|
||||||
currentWorkspaceIssuePath,
|
currentWorkspaceIssuePath,
|
||||||
params,
|
params,
|
||||||
@ -224,8 +234,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
||||||
|
|
||||||
const handleOrderBy = (order: TIssueOrderByOptions, itemKey: string) => {
|
const handleOrderBy = (order: TIssueOrderByOptions, itemKey: string) => {
|
||||||
if (!workspaceViewId || !currentWorkspaceIssuePath)
|
if (globalViewId) handleFilters("display_filters", { order_by: order });
|
||||||
handleFilters("display_filters", { order_by: order });
|
|
||||||
else setDisplayFilters({ order_by: order });
|
else setDisplayFilters({ order_by: order });
|
||||||
setSelectedMenuItem(`${order}_${itemKey}`);
|
setSelectedMenuItem(`${order}_${itemKey}`);
|
||||||
setActiveSortingProperty(order === "-created_at" ? "" : itemKey);
|
setActiveSortingProperty(order === "-created_at" ? "" : itemKey);
|
||||||
@ -240,199 +249,203 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
) => (
|
) => (
|
||||||
<div className="relative flex flex-col h-max w-full bg-custom-background-100">
|
<div className="relative flex flex-col h-max w-full bg-custom-background-100">
|
||||||
<div className="flex items-center min-w-[9rem] px-4 py-2.5 text-sm font-medium z-[1] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-100">
|
<div className="flex items-center min-w-[9rem] px-4 py-2.5 text-sm font-medium z-[1] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-100">
|
||||||
<CustomMenu
|
{currentWorkspaceIssuePath ? (
|
||||||
customButtonClassName="!w-full"
|
<span>{header}</span>
|
||||||
className="!w-full"
|
) : (
|
||||||
position="left"
|
<CustomMenu
|
||||||
customButton={
|
customButtonClassName="!w-full"
|
||||||
<div
|
className="!w-full"
|
||||||
className={`relative group flex items-center justify-between gap-1.5 cursor-pointer text-sm text-custom-text-200 hover:text-custom-text-100 w-full py-3 px-2 ${
|
position="left"
|
||||||
activeSortingProperty === propertyName ? "bg-custom-background-80" : ""
|
customButton={
|
||||||
}`}
|
<div
|
||||||
>
|
className={`relative group flex items-center justify-between gap-1.5 cursor-pointer text-sm text-custom-text-200 hover:text-custom-text-100 w-full py-3 px-2 ${
|
||||||
{activeSortingProperty === propertyName && (
|
activeSortingProperty === propertyName ? "bg-custom-background-80" : ""
|
||||||
<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-custom-primary text-xs text-white"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{header}
|
|
||||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
width="xl"
|
|
||||||
>
|
|
||||||
<CustomMenu.MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
handleOrderBy(ascendingOrder, propertyName);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
|
||||||
selectedMenuItem === `${ascendingOrder}_${propertyName}`
|
|
||||||
? "text-custom-text-100"
|
|
||||||
: "text-custom-text-200 hover:text-custom-text-100"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
{propertyName === "assignee" || propertyName === "labels" ? (
|
|
||||||
<>
|
|
||||||
<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>A</span>
|
|
||||||
<Icon iconName="east" className="text-sm" />
|
|
||||||
<span>Z</span>
|
|
||||||
</>
|
|
||||||
) : propertyName === "due_date" ||
|
|
||||||
propertyName === "created_on" ||
|
|
||||||
propertyName === "updated_on" ? (
|
|
||||||
<>
|
|
||||||
<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>New</span>
|
|
||||||
<Icon iconName="east" className="text-sm" />
|
|
||||||
<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>
|
|
||||||
<Icon iconName="east" className="text-sm" />
|
|
||||||
<span>Last</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CheckIcon
|
|
||||||
className={`h-3.5 w-3.5 opacity-0 group-hover:opacity-100 ${
|
|
||||||
selectedMenuItem === `${ascendingOrder}_${propertyName}` ? "opacity-100" : ""
|
|
||||||
}`}
|
}`}
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
<CustomMenu.MenuItem
|
|
||||||
className={`mt-0.5 ${
|
|
||||||
selectedMenuItem === `${descendingOrder}_${propertyName}`
|
|
||||||
? "bg-custom-background-80"
|
|
||||||
: ""
|
|
||||||
}`}
|
|
||||||
key={propertyName}
|
|
||||||
onClick={() => {
|
|
||||||
handleOrderBy(descendingOrder, propertyName);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
|
||||||
selectedMenuItem === `${descendingOrder}_${propertyName}`
|
|
||||||
? "text-custom-text-100"
|
|
||||||
: "text-custom-text-200 hover:text-custom-text-100"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
{propertyName === "assignee" || propertyName === "labels" ? (
|
|
||||||
<>
|
|
||||||
<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>Z</span>
|
|
||||||
<Icon iconName="east" className="text-sm" />
|
|
||||||
<span>A</span>
|
|
||||||
</>
|
|
||||||
) : propertyName === "due_date" ? (
|
|
||||||
<>
|
|
||||||
<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>Old</span>
|
|
||||||
<Icon iconName="east" className="text-sm" />
|
|
||||||
<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>
|
|
||||||
<Icon iconName="east" className="text-sm" />
|
|
||||||
<span>First</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CheckIcon
|
|
||||||
className={`h-3.5 w-3.5 opacity-0 group-hover:opacity-100 ${
|
|
||||||
selectedMenuItem === `${descendingOrder}_${propertyName}` ? "opacity-100" : ""
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
{selectedMenuItem &&
|
|
||||||
selectedMenuItem !== "" &&
|
|
||||||
displayFilters?.order_by !== "-created_at" &&
|
|
||||||
selectedMenuItem.includes(propertyName) && (
|
|
||||||
<CustomMenu.MenuItem
|
|
||||||
className={`mt-0.5${
|
|
||||||
selectedMenuItem === `-created_at_${propertyName}`
|
|
||||||
? "bg-custom-background-80"
|
|
||||||
: ""
|
|
||||||
}`}
|
|
||||||
key={propertyName}
|
|
||||||
onClick={() => {
|
|
||||||
handleOrderBy("-created_at", propertyName);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className={`group flex gap-1.5 px-1 items-center justify-between `}>
|
{activeSortingProperty === propertyName && (
|
||||||
<div className="flex gap-1.5 items-center">
|
<div className="absolute top-1 right-1.5">
|
||||||
<span className="relative flex items-center justify-center h-6 w-6">
|
<Icon
|
||||||
<Icon iconName="ink_eraser" className="text-sm" />
|
iconName="filter_list"
|
||||||
</span>
|
className="flex items-center justify-center h-3.5 w-3.5 rounded-full bg-custom-primary text-xs text-white"
|
||||||
|
/>
|
||||||
<span>Clear sorting</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{header}
|
||||||
|
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
width="xl"
|
||||||
|
>
|
||||||
|
<CustomMenu.MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
handleOrderBy(ascendingOrder, propertyName);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
||||||
|
selectedMenuItem === `${ascendingOrder}_${propertyName}`
|
||||||
|
? "text-custom-text-100"
|
||||||
|
: "text-custom-text-200 hover:text-custom-text-100"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex gap-2 items-center">
|
||||||
|
{propertyName === "assignee" || propertyName === "labels" ? (
|
||||||
|
<>
|
||||||
|
<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>A</span>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<span>Z</span>
|
||||||
|
</>
|
||||||
|
) : propertyName === "due_date" ||
|
||||||
|
propertyName === "created_on" ||
|
||||||
|
propertyName === "updated_on" ? (
|
||||||
|
<>
|
||||||
|
<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>New</span>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<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>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<span>Last</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
)}
|
<CheckIcon
|
||||||
</CustomMenu>
|
className={`h-3.5 w-3.5 opacity-0 group-hover:opacity-100 ${
|
||||||
|
selectedMenuItem === `${ascendingOrder}_${propertyName}` ? "opacity-100" : ""
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</CustomMenu.MenuItem>
|
||||||
|
<CustomMenu.MenuItem
|
||||||
|
className={`mt-0.5 ${
|
||||||
|
selectedMenuItem === `${descendingOrder}_${propertyName}`
|
||||||
|
? "bg-custom-background-80"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
key={propertyName}
|
||||||
|
onClick={() => {
|
||||||
|
handleOrderBy(descendingOrder, propertyName);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
||||||
|
selectedMenuItem === `${descendingOrder}_${propertyName}`
|
||||||
|
? "text-custom-text-100"
|
||||||
|
: "text-custom-text-200 hover:text-custom-text-100"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex gap-2 items-center">
|
||||||
|
{propertyName === "assignee" || propertyName === "labels" ? (
|
||||||
|
<>
|
||||||
|
<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>Z</span>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<span>A</span>
|
||||||
|
</>
|
||||||
|
) : propertyName === "due_date" ? (
|
||||||
|
<>
|
||||||
|
<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>Old</span>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<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>
|
||||||
|
<Icon iconName="east" className="text-sm" />
|
||||||
|
<span>First</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CheckIcon
|
||||||
|
className={`h-3.5 w-3.5 opacity-0 group-hover:opacity-100 ${
|
||||||
|
selectedMenuItem === `${descendingOrder}_${propertyName}` ? "opacity-100" : ""
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</CustomMenu.MenuItem>
|
||||||
|
{selectedMenuItem &&
|
||||||
|
selectedMenuItem !== "" &&
|
||||||
|
displayFilters?.order_by !== "-created_at" &&
|
||||||
|
selectedMenuItem.includes(propertyName) && (
|
||||||
|
<CustomMenu.MenuItem
|
||||||
|
className={`mt-0.5${
|
||||||
|
selectedMenuItem === `-created_at_${propertyName}`
|
||||||
|
? "bg-custom-background-80"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
key={propertyName}
|
||||||
|
onClick={() => {
|
||||||
|
handleOrderBy("-created_at", 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>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full min-w-[9rem] w-full">
|
<div className="h-full min-w-[9rem] w-full">
|
||||||
{spreadsheetIssues.map((issue: IIssue, index) => (
|
{spreadsheetIssues.map((issue: IIssue, index) => (
|
||||||
@ -442,7 +455,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
projectId={issue.project_detail.id}
|
projectId={issue.project_detail.id}
|
||||||
partialUpdateIssue={partialUpdateIssue}
|
partialUpdateIssue={partialUpdateIssue}
|
||||||
expandedIssues={expandedIssues}
|
expandedIssues={expandedIssues}
|
||||||
properties={properties}
|
properties={currentViewProperties}
|
||||||
user={user}
|
user={user}
|
||||||
isNotAllowed={isNotAllowed}
|
isNotAllowed={isNotAllowed}
|
||||||
/>
|
/>
|
||||||
@ -492,9 +505,11 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center text-sm font-medium z-[2] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-100">
|
<div className="flex items-center text-sm font-medium z-[2] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-100">
|
||||||
<span className="flex items-center px-4 py-2.5 h-full w-24 flex-shrink-0">
|
{currentViewProperties.key && (
|
||||||
ID
|
<span className="flex items-center px-4 py-2.5 h-full w-24 flex-shrink-0">
|
||||||
</span>
|
ID
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
<span className="flex items-center px-4 py-2.5 h-full w-full flex-grow">
|
<span className="flex items-center px-4 py-2.5 h-full w-full flex-grow">
|
||||||
Issue
|
Issue
|
||||||
</span>
|
</span>
|
||||||
@ -508,7 +523,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
expandedIssues={expandedIssues}
|
expandedIssues={expandedIssues}
|
||||||
setExpandedIssues={setExpandedIssues}
|
setExpandedIssues={setExpandedIssues}
|
||||||
setCurrentProjectId={setCurrentProjectId}
|
setCurrentProjectId={setCurrentProjectId}
|
||||||
properties={properties}
|
properties={currentViewProperties}
|
||||||
handleIssueAction={handleIssueAction}
|
handleIssueAction={handleIssueAction}
|
||||||
disableUserActions={disableUserActions}
|
disableUserActions={disableUserActions}
|
||||||
userAuth={userAuth}
|
userAuth={userAuth}
|
||||||
@ -516,69 +531,79 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{renderColumn(
|
{currentViewProperties.state &&
|
||||||
"State",
|
renderColumn(
|
||||||
"state",
|
"State",
|
||||||
SpreadsheetStateColumn,
|
"state",
|
||||||
"state__name",
|
SpreadsheetStateColumn,
|
||||||
"-state__name"
|
"state__name",
|
||||||
)}
|
"-state__name"
|
||||||
{renderColumn(
|
)}
|
||||||
"Priority",
|
|
||||||
"priority",
|
{currentViewProperties.priority &&
|
||||||
SpreadsheetPriorityColumn,
|
renderColumn(
|
||||||
"priority",
|
"Priority",
|
||||||
"-priority"
|
"priority",
|
||||||
)}
|
SpreadsheetPriorityColumn,
|
||||||
{renderColumn(
|
"priority",
|
||||||
"Assignees",
|
"-priority"
|
||||||
"assignee",
|
)}
|
||||||
SpreadsheetAssigneeColumn,
|
{currentViewProperties.assignee &&
|
||||||
"assignees__first_name",
|
renderColumn(
|
||||||
"-assignees__first_name"
|
"Assignees",
|
||||||
)}
|
"assignee",
|
||||||
{renderColumn(
|
SpreadsheetAssigneeColumn,
|
||||||
"Label",
|
"assignees__first_name",
|
||||||
"labels",
|
"-assignees__first_name"
|
||||||
SpreadsheetLabelColumn,
|
)}
|
||||||
"labels__name",
|
{currentViewProperties.labels &&
|
||||||
"-labels__name"
|
renderColumn(
|
||||||
)}
|
"Label",
|
||||||
{renderColumn(
|
"labels",
|
||||||
"Start Date",
|
SpreadsheetLabelColumn,
|
||||||
"start_date",
|
"labels__name",
|
||||||
SpreadsheetStartDateColumn,
|
"-labels__name"
|
||||||
"-start_date",
|
)}
|
||||||
"start_date"
|
{currentViewProperties.start_date &&
|
||||||
)}
|
renderColumn(
|
||||||
{renderColumn(
|
"Start Date",
|
||||||
"Due Date",
|
"start_date",
|
||||||
"due_date",
|
SpreadsheetStartDateColumn,
|
||||||
SpreadsheetDueDateColumn,
|
"-start_date",
|
||||||
"-target_date",
|
"start_date"
|
||||||
"target_date"
|
)}
|
||||||
)}
|
{currentViewProperties.due_date &&
|
||||||
{renderColumn(
|
renderColumn(
|
||||||
"Estimate",
|
"Due Date",
|
||||||
"estimate",
|
"due_date",
|
||||||
SpreadsheetEstimateColumn,
|
SpreadsheetDueDateColumn,
|
||||||
"estimate_point",
|
"-target_date",
|
||||||
"-estimate_point"
|
"target_date"
|
||||||
)}
|
)}
|
||||||
{renderColumn(
|
{currentViewProperties.estimate &&
|
||||||
"Created On",
|
renderColumn(
|
||||||
"created_on",
|
"Estimate",
|
||||||
SpreadsheetCreatedOnColumn,
|
"estimate",
|
||||||
"-created_at",
|
SpreadsheetEstimateColumn,
|
||||||
"created_at"
|
"estimate_point",
|
||||||
)}
|
"-estimate_point"
|
||||||
{renderColumn(
|
)}
|
||||||
"Updated On",
|
{currentViewProperties.created_on &&
|
||||||
"updated_on",
|
renderColumn(
|
||||||
SpreadsheetUpdatedOnColumn,
|
"Created On",
|
||||||
"-updated_at",
|
"created_on",
|
||||||
"updated_at"
|
SpreadsheetCreatedOnColumn,
|
||||||
)}
|
"-created_at",
|
||||||
|
"created_at"
|
||||||
|
)}
|
||||||
|
{currentViewProperties.updated_on &&
|
||||||
|
renderColumn(
|
||||||
|
"Updated On",
|
||||||
|
"updated_on",
|
||||||
|
SpreadsheetUpdatedOnColumn,
|
||||||
|
"-updated_at",
|
||||||
|
"updated_at"
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col justify-center items-center h-full w-full">
|
<div className="flex flex-col justify-center items-center h-full w-full">
|
||||||
|
@ -30,7 +30,7 @@ const issueViewOptions: { type: TIssueViewOptions; Icon: any }[] = [
|
|||||||
|
|
||||||
export const MyIssuesViewOptions: React.FC = () => {
|
export const MyIssuesViewOptions: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, workspaceViewId } = router.query;
|
const { workspaceSlug, globalViewId } = router.query;
|
||||||
|
|
||||||
const { displayFilters, setDisplayFilters, filters, setFilters } = useMyIssuesFilters(
|
const { displayFilters, setDisplayFilters, filters, setFilters } = useMyIssuesFilters(
|
||||||
workspaceSlug?.toString()
|
workspaceSlug?.toString()
|
||||||
@ -42,7 +42,7 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
router.pathname.includes(pathname)
|
router.pathname.includes(pathname)
|
||||||
);
|
);
|
||||||
|
|
||||||
const showFilters = isWorkspaceViewPath || workspaceViewId;
|
const showFilters = isWorkspaceViewPath || globalViewId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
@ -13,6 +13,7 @@ import useProjects from "hooks/use-projects";
|
|||||||
import useUser from "hooks/use-user";
|
import useUser from "hooks/use-user";
|
||||||
import { useWorkspaceView } from "hooks/use-workspace-view";
|
import { useWorkspaceView } from "hooks/use-workspace-view";
|
||||||
import useWorkspaceMembers from "hooks/use-workspace-members";
|
import useWorkspaceMembers from "hooks/use-workspace-members";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { WorkspaceViewsNavigation } from "components/workspace/views/workpace-view-navigation";
|
import { WorkspaceViewsNavigation } from "components/workspace/views/workpace-view-navigation";
|
||||||
import { EmptyState, PrimaryButton } from "components/ui";
|
import { EmptyState, PrimaryButton } from "components/ui";
|
||||||
@ -31,7 +32,9 @@ import { IIssue, IWorkspaceIssueFilterOptions } from "types";
|
|||||||
|
|
||||||
export const WorkspaceViewIssues = () => {
|
export const WorkspaceViewIssues = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, viewId } = router.query;
|
const { workspaceSlug, globalViewId } = router.query;
|
||||||
|
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { memberRole } = useProjectMyMembership();
|
const { memberRole } = useProjectMyMembership();
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
@ -111,7 +114,9 @@ export const WorkspaceViewIssues = () => {
|
|||||||
const nullFilters =
|
const nullFilters =
|
||||||
filters.filters &&
|
filters.filters &&
|
||||||
Object.keys(filters.filters).filter(
|
Object.keys(filters.filters).filter(
|
||||||
(key) => filters.filters[key as keyof IWorkspaceIssueFilterOptions] === null
|
(key) =>
|
||||||
|
filters.filters[key as keyof IWorkspaceIssueFilterOptions] === null ||
|
||||||
|
(filters.filters[key as keyof IWorkspaceIssueFilterOptions]?.length ?? 0) <= 0
|
||||||
);
|
);
|
||||||
|
|
||||||
const areFiltersApplied =
|
const areFiltersApplied =
|
||||||
@ -189,16 +194,22 @@ export const WorkspaceViewIssues = () => {
|
|||||||
/>
|
/>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (viewId) handleFilters("filters", filters.filters, true);
|
if (globalViewId) {
|
||||||
else
|
handleFilters("filters", filters.filters, true);
|
||||||
|
setToastAlert({
|
||||||
|
title: "View updated",
|
||||||
|
message: "Your view has been updated",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
} else
|
||||||
setCreateViewModal({
|
setCreateViewModal({
|
||||||
query: filters.filters,
|
query: filters.filters,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
className="flex items-center gap-2 text-sm"
|
className="flex items-center gap-2 text-sm"
|
||||||
>
|
>
|
||||||
{!viewId && <PlusIcon className="h-4 w-4" />}
|
{!globalViewId && <PlusIcon className="h-4 w-4" />}
|
||||||
{viewId ? "Update" : "Save"} view
|
{globalViewId ? "Update" : "Save"} view
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
{<div className="mt-3 border-t border-custom-border-200" />}
|
{<div className="mt-3 border-t border-custom-border-200" />}
|
||||||
|
@ -31,7 +31,7 @@ import { IIssue, IWorkspaceIssueFilterOptions } from "types";
|
|||||||
|
|
||||||
export const WorkspaceAllIssue = () => {
|
export const WorkspaceAllIssue = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, viewId } = router.query;
|
const { workspaceSlug, globalViewId } = router.query;
|
||||||
|
|
||||||
const [createViewModal, setCreateViewModal] = useState<any>(null);
|
const [createViewModal, setCreateViewModal] = useState<any>(null);
|
||||||
|
|
||||||
@ -128,7 +128,9 @@ export const WorkspaceAllIssue = () => {
|
|||||||
const nullFilters =
|
const nullFilters =
|
||||||
filters.filters &&
|
filters.filters &&
|
||||||
Object.keys(filters.filters).filter(
|
Object.keys(filters.filters).filter(
|
||||||
(key) => filters.filters[key as keyof IWorkspaceIssueFilterOptions] === null
|
(key) =>
|
||||||
|
filters.filters[key as keyof IWorkspaceIssueFilterOptions] === null ||
|
||||||
|
(filters.filters[key as keyof IWorkspaceIssueFilterOptions]?.length ?? 0) <= 0
|
||||||
);
|
);
|
||||||
|
|
||||||
const areFiltersApplied =
|
const areFiltersApplied =
|
||||||
@ -203,7 +205,7 @@ export const WorkspaceAllIssue = () => {
|
|||||||
/>
|
/>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (viewId) handleFilters("filters", filters.filters, true);
|
if (globalViewId) handleFilters("filters", filters.filters, true);
|
||||||
else
|
else
|
||||||
setCreateViewModal({
|
setCreateViewModal({
|
||||||
query: filters.filters,
|
query: filters.filters,
|
||||||
@ -211,8 +213,8 @@ export const WorkspaceAllIssue = () => {
|
|||||||
}}
|
}}
|
||||||
className="flex items-center gap-2 text-sm"
|
className="flex items-center gap-2 text-sm"
|
||||||
>
|
>
|
||||||
{!viewId && <PlusIcon className="h-4 w-4" />}
|
{!globalViewId && <PlusIcon className="h-4 w-4" />}
|
||||||
{viewId ? "Update" : "Save"} view
|
{globalViewId ? "Update" : "Save"} view
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
{<div className="mt-3 border-t border-custom-border-200" />}
|
{<div className="mt-3 border-t border-custom-border-200" />}
|
||||||
|
@ -50,13 +50,6 @@ export const WorkspaceAssignedIssue = () => {
|
|||||||
sub_issue: false,
|
sub_issue: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// const { data: viewDetails, error } = useSWR(
|
|
||||||
// workspaceSlug && workspaceViewId ? WORKSPACE_VIEW_DETAILS(workspaceViewId.toString()) : null,
|
|
||||||
// workspaceSlug && workspaceViewId
|
|
||||||
// ? () => workspaceService.getViewDetails(workspaceSlug.toString(), workspaceViewId.toString())
|
|
||||||
// : null
|
|
||||||
// );
|
|
||||||
|
|
||||||
const { data: viewIssues, mutate: mutateIssues } = useSWR(
|
const { data: viewIssues, mutate: mutateIssues } = useSWR(
|
||||||
workspaceSlug ? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), params) : null,
|
workspaceSlug ? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), params) : null,
|
||||||
workspaceSlug ? () => workspaceService.getViewIssues(workspaceSlug.toString(), params) : null
|
workspaceSlug ? () => workspaceService.getViewIssues(workspaceSlug.toString(), params) : null
|
||||||
|
@ -30,13 +30,13 @@ const issueViewOptions: { type: TIssueViewOptions; Icon: any }[] = [
|
|||||||
|
|
||||||
export const WorkspaceIssuesViewOptions: React.FC = () => {
|
export const WorkspaceIssuesViewOptions: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, workspaceViewId } = router.query;
|
const { workspaceSlug, globalViewId } = router.query;
|
||||||
|
|
||||||
const { filters, handleFilters } = useWorkspaceView();
|
const { filters, handleFilters } = useWorkspaceView();
|
||||||
|
|
||||||
const isWorkspaceViewPath = router.pathname.includes("workspace-views/all-issues");
|
const isWorkspaceViewPath = router.pathname.includes("workspace-views/all-issues");
|
||||||
|
|
||||||
const showFilters = isWorkspaceViewPath || workspaceViewId;
|
const showFilters = isWorkspaceViewPath || globalViewId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
@ -91,7 +91,7 @@ export const SingleViewItem: React.FC<Props> = ({
|
|||||||
const viewRedirectionUrl =
|
const viewRedirectionUrl =
|
||||||
viewType === "project"
|
viewType === "project"
|
||||||
? `/${workspaceSlug}/projects/${projectId}/views/${view.id}`
|
? `/${workspaceSlug}/projects/${projectId}/views/${view.id}`
|
||||||
: `/${workspaceSlug}/workspace-views/issues?viewId=${view.id}`;
|
: `/${workspaceSlug}/workspace-views/issues?globalViewId=${view.id}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="group hover:bg-custom-background-90 border-b border-custom-border-200">
|
<div className="group hover:bg-custom-background-90 border-b border-custom-border-200">
|
||||||
|
@ -17,7 +17,7 @@ type Props = {
|
|||||||
|
|
||||||
export const WorkspaceViewsNavigation: React.FC<Props> = ({ handleAddView }) => {
|
export const WorkspaceViewsNavigation: React.FC<Props> = ({ handleAddView }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, viewId } = router.query;
|
const { workspaceSlug, globalViewId } = router.query;
|
||||||
|
|
||||||
const { data: workspaceViews } = useSWR(
|
const { data: workspaceViews } = useSWR(
|
||||||
workspaceSlug ? WORKSPACE_VIEWS_LIST(workspaceSlug.toString()) : null,
|
workspaceSlug ? WORKSPACE_VIEWS_LIST(workspaceSlug.toString()) : null,
|
||||||
@ -28,7 +28,7 @@ export const WorkspaceViewsNavigation: React.FC<Props> = ({ handleAddView }) =>
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const activeTabElement = document.getElementById("active-tab-global-view");
|
const activeTabElement = document.getElementById("active-tab-global-view");
|
||||||
if (activeTabElement) activeTabElement.scrollIntoView({ behavior: "smooth", inline: "center" });
|
if (activeTabElement) activeTabElement.scrollIntoView({ behavior: "smooth", inline: "center" });
|
||||||
}, [viewId, workspaceViews]);
|
}, [globalViewId, workspaceViews]);
|
||||||
|
|
||||||
const tabsList = [
|
const tabsList = [
|
||||||
{
|
{
|
||||||
@ -80,13 +80,13 @@ export const WorkspaceViewsNavigation: React.FC<Props> = ({ handleAddView }) =>
|
|||||||
workspaceViews?.map((view) => (
|
workspaceViews?.map((view) => (
|
||||||
<button
|
<button
|
||||||
className={`border-b-2 min-w-min p-3 text-sm font-medium outline-none whitespace-nowrap flex-shrink-0 ${
|
className={`border-b-2 min-w-min p-3 text-sm font-medium outline-none whitespace-nowrap flex-shrink-0 ${
|
||||||
view.id === viewId
|
view.id === globalViewId
|
||||||
? "border-custom-primary-100 text-custom-primary-100"
|
? "border-custom-primary-100 text-custom-primary-100"
|
||||||
: "border-transparent hover:border-custom-border-200 hover:text-custom-text-400"
|
: "border-transparent hover:border-custom-border-200 hover:text-custom-text-400"
|
||||||
}`}
|
}`}
|
||||||
id={view.id === viewId ? `active-tab-global-view` : ``}
|
id={view.id === globalViewId ? `active-tab-global-view` : ``}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
router.replace(`/${workspaceSlug}/workspace-views/issues?viewId=${view.id}`)
|
router.replace(`/${workspaceSlug}/workspace-views/issues?globalViewId=${view.id}`)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{view.name}
|
{view.name}
|
||||||
|
@ -162,13 +162,11 @@ export const PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS = (projectId: string, params?
|
|||||||
|
|
||||||
export const WORKSPACE_VIEWS_LIST = (workspaceSlug: string) =>
|
export const WORKSPACE_VIEWS_LIST = (workspaceSlug: string) =>
|
||||||
`WORKSPACE_VIEWS_LIST_${workspaceSlug.toUpperCase()}`;
|
`WORKSPACE_VIEWS_LIST_${workspaceSlug.toUpperCase()}`;
|
||||||
export const WORKSPACE_VIEW_DETAILS = (workspaceViewId: string) =>
|
export const WORKSPACE_VIEW_DETAILS = (globalViewId: string) =>
|
||||||
`WORKSPACE_VIEW_DETAILS_${workspaceViewId.toUpperCase()}`;
|
`WORKSPACE_VIEW_DETAILS_${globalViewId.toUpperCase()}`;
|
||||||
export const WORKSPACE_VIEW_ISSUES = (workspaceViewId: string, params: any) => {
|
export const WORKSPACE_VIEW_ISSUES = (globalViewId: string, params: any) => {
|
||||||
if (!params) return `WORKSPACE_VIEW_ISSUES_${workspaceViewId.toUpperCase()}`;
|
if (!params) return `WORKSPACE_VIEW_ISSUES_${globalViewId.toUpperCase()}`;
|
||||||
return `WORKSPACE_VIEW_ISSUES_${workspaceViewId.toUpperCase()}_${paramsToKey(
|
return `WORKSPACE_VIEW_ISSUES_${globalViewId.toUpperCase()}_${paramsToKey(params).toUpperCase()}`;
|
||||||
params
|
|
||||||
).toUpperCase()}`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PROJECT_ISSUES_DETAILS = (issueId: string) =>
|
export const PROJECT_ISSUES_DETAILS = (issueId: string) =>
|
||||||
|
@ -67,19 +67,19 @@ export const initialState: IWorkspaceGlobalViewProps = {
|
|||||||
|
|
||||||
const saveViewFilters = async (
|
const saveViewFilters = async (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
viewId: string,
|
globalViewId: string,
|
||||||
state: IWorkspaceGlobalViewProps
|
state: IWorkspaceGlobalViewProps
|
||||||
) => {
|
) => {
|
||||||
await workspaceService.updateView(workspaceSlug, viewId, {
|
await workspaceService.updateView(workspaceSlug, globalViewId, {
|
||||||
query_data: state,
|
query_data: state,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, viewId } = router.query as {
|
const { workspaceSlug, globalViewId } = router.query as {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
viewId: string;
|
globalViewId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const [filters, setFilters] = useState<IWorkspaceGlobalViewProps>(initialState);
|
const [filters, setFilters] = useState<IWorkspaceGlobalViewProps>(initialState);
|
||||||
@ -98,7 +98,7 @@ export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||||||
};
|
};
|
||||||
setFilters(() => updatedFilterPayload);
|
setFilters(() => updatedFilterPayload);
|
||||||
|
|
||||||
if (saveFiltersToServer) saveViewFilters(workspaceSlug, viewId, updatedFilterPayload);
|
if (saveFiltersToServer) saveViewFilters(workspaceSlug, globalViewId, updatedFilterPayload);
|
||||||
};
|
};
|
||||||
|
|
||||||
const computedFilter = (filters: any) => {
|
const computedFilter = (filters: any) => {
|
||||||
@ -151,9 +151,9 @@ export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { data: view, isLoading: viewLoading } = useSWR(
|
const { data: view, isLoading: viewLoading } = useSWR(
|
||||||
workspaceSlug && viewId ? WORKSPACE_VIEW_DETAILS(viewId.toString()) : null,
|
workspaceSlug && globalViewId ? WORKSPACE_VIEW_DETAILS(globalViewId.toString()) : null,
|
||||||
workspaceSlug && viewId
|
workspaceSlug && globalViewId
|
||||||
? () => workspaceService.getViewDetails(workspaceSlug.toString(), viewId.toString())
|
? () => workspaceService.getViewDetails(workspaceSlug.toString(), globalViewId.toString())
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -162,10 +162,10 @@ export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||||||
mutate: mutateViewIssues,
|
mutate: mutateViewIssues,
|
||||||
isLoading: viewIssueLoading,
|
isLoading: viewIssueLoading,
|
||||||
} = useSWR(
|
} = useSWR(
|
||||||
workspaceSlug && view && viewId && filters
|
workspaceSlug && view && globalViewId && filters
|
||||||
? WORKSPACE_VIEW_ISSUES(viewId.toString(), params)
|
? WORKSPACE_VIEW_ISSUES(globalViewId.toString(), params)
|
||||||
: null,
|
: null,
|
||||||
workspaceSlug && view && viewId
|
workspaceSlug && view && globalViewId
|
||||||
? () =>
|
? () =>
|
||||||
workspaceService.getViewIssues(
|
workspaceService.getViewIssues(
|
||||||
workspaceSlug.toString(),
|
workspaceSlug.toString(),
|
||||||
|
@ -18,7 +18,6 @@ const WorkspaceViewAllIssue = () => (
|
|||||||
}
|
}
|
||||||
right={
|
right={
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{/* <MyIssuesViewOptions /> */}
|
|
||||||
<WorkspaceIssuesViewOptions />
|
<WorkspaceIssuesViewOptions />
|
||||||
|
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
|
2
web/types/view-props.d.ts
vendored
2
web/types/view-props.d.ts
vendored
@ -103,5 +103,5 @@ export interface IWorkspaceViewProps {
|
|||||||
export interface IWorkspaceGlobalViewProps {
|
export interface IWorkspaceGlobalViewProps {
|
||||||
filters: IWorkspaceIssueFilterOptions;
|
filters: IWorkspaceIssueFilterOptions;
|
||||||
display_filters: IWorkspaceIssueDisplayFilterOptions | undefined;
|
display_filters: IWorkspaceIssueDisplayFilterOptions | undefined;
|
||||||
display_properties: Properties | undefined;
|
display_properties: Properties;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user