[WEB-3092] fix: fixed recents + removed home route (#6365)

* fix: fixed recents + removed home route

* Return current users recents

---------

Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
This commit is contained in:
Akshita Goyal 2025-01-09 17:25:49 +05:30 committed by GitHub
parent 448a34aa5f
commit add35b5ea6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 81 additions and 119 deletions

View file

@ -9,6 +9,7 @@ from plane.app.serializers import WorkspaceRecentVisitSerializer
from ..base import BaseViewSet
from plane.app.permissions import allow_permission, ROLE
class UserRecentVisitViewSet(BaseViewSet):
model = UserRecentVisit
@ -17,15 +18,18 @@ class UserRecentVisitViewSet(BaseViewSet):
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST], level="WORKSPACE")
def list(self, request, slug):
user_recent_visits = UserRecentVisit.objects.filter(workspace__slug=slug)
user_recent_visits = UserRecentVisit.objects.filter(
workspace__slug=slug, user=request.user
)
entity_name = request.query_params.get("entity_name")
entity_name = request.query_params.get("entity_name")
if entity_name:
user_recent_visits = user_recent_visits.filter(entity_name=entity_name)
user_recent_visits = user_recent_visits.filter(entity_name__in=["issue","page","project"])
serializer = WorkspaceRecentVisitSerializer(user_recent_visits[:20], many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
if entity_name:
user_recent_visits = user_recent_visits.filter(entity_name=entity_name)
user_recent_visits = user_recent_visits.filter(
entity_name__in=["issue", "page", "project"]
)
serializer = WorkspaceRecentVisitSerializer(user_recent_visits[:20], many=True)
return Response(serializer.data, status=status.HTTP_200_OK)

View file

@ -1,60 +0,0 @@
"use client";
import Image from "next/image";
import { useTheme } from "next-themes";
import { Home } from "lucide-react";
// images
import githubBlackImage from "/public/logos/github-black.png";
import githubWhiteImage from "/public/logos/github-white.png";
// ui
import { Breadcrumbs, Header } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common";
// constants
import { GITHUB_REDIRECTED } from "@/constants/event-tracker";
// hooks
import { useEventTracker } from "@/hooks/store";
export const WorkspaceDashboardHeader = () => {
// hooks
const { captureEvent } = useEventTracker();
const { resolvedTheme } = useTheme();
return (
<>
<Header>
<Header.LeftItem>
<div>
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
link={<BreadcrumbLink label="Home" icon={<Home className="h-4 w-4 text-custom-text-300" />} />}
/>
</Breadcrumbs>
</div>
</Header.LeftItem>
<Header.RightItem>
<a
onClick={() =>
captureEvent(GITHUB_REDIRECTED, {
element: "navbar",
})
}
className="flex flex-shrink-0 items-center gap-1.5 rounded bg-custom-background-80 px-3 py-1.5"
href="https://github.com/makeplane/plane"
target="_blank"
rel="noopener noreferrer"
>
<Image
src={resolvedTheme === "dark" ? githubWhiteImage : githubBlackImage}
height={16}
width={16}
alt="GitHub Logo"
/>
<span className="hidden text-xs font-medium sm:hidden md:block">Star us on GitHub</span>
</a>
</Header.RightItem>
</Header>
</>
);
};

View file

@ -1,28 +0,0 @@
"use client";
import { observer } from "mobx-react";
// components
import { PageHead, AppHeader, ContentWrapper } from "@/components/core";
// hooks
import { WorkspaceHomeView } from "@/components/home";
import { useWorkspace } from "@/hooks/store";
// local components
import { WorkspaceDashboardHeader } from "../header";
const WorkspaceDashboardPage = observer(() => {
const { currentWorkspace } = useWorkspace();
// derived values
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Home` : undefined;
return (
<>
<AppHeader header={<WorkspaceDashboardHeader />} />
<ContentWrapper>
<PageHead title={pageTitle} />
<WorkspaceHomeView />
</ContentWrapper>
</>
);
});
export default WorkspaceDashboardPage;

View file

@ -23,9 +23,11 @@ export const ContentOverflowWrapper = observer((props: IContentOverflowWrapper)
// states
const [containerHeight, setContainerHeight] = useState(0);
const [showAll, setShowAll] = useState(false);
const [isTransitioning, setIsTransitioning] = useState(false);
// refs
const contentRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!contentRef?.current) return;
@ -70,37 +72,72 @@ export const ContentOverflowWrapper = observer((props: IContentOverflowWrapper)
};
}, [contentRef?.current]);
useEffect(() => {
if (!containerRef.current) return;
const handleTransitionEnd = () => {
setIsTransitioning(false);
};
containerRef.current.addEventListener("transitionend", handleTransitionEnd);
return () => {
containerRef.current?.removeEventListener("transitionend", handleTransitionEnd);
};
}, []);
const handleToggle = () => {
setIsTransitioning(true);
setShowAll((prev) => !prev);
};
if (!children) return fallback;
return (
<div
ref={containerRef}
className={cn(
"relative",
{
[`overflow-hidden`]: !showAll,
"overflow-visible": showAll,
[`overflow-hidden transition-[height] duration-300 ease-in-out`]: containerHeight > maxHeight,
},
containerClassName
)}
style={{ maxHeight: showAll ? "100%" : `${maxHeight}px` }}
style={{
height: showAll ? `${containerHeight}px` : `${Math.min(maxHeight, containerHeight)}px`,
}}
>
<div ref={contentRef}>{children}</div>
<div
ref={contentRef}
className={cn("h-auto", {
"pb-6": showAll,
})}
>
{children}
</div>
{containerHeight > maxHeight && (
<div
className={cn(
"bottom-0 left-0 w-full",
"bottom-0 left-0 w-full transition-all duration-300 ease-in-out",
`bg-gradient-to-t from-custom-background-100 to-transparent flex flex-col items-center justify-end`,
"text-center",
{
"absolute h-[100px]": !showAll,
"h-[30px]": showAll,
"absolute h-[100px] opacity-100": !showAll,
"absolute h-[30px] opacity-70": showAll,
}
)}
style={{
pointerEvents: isTransitioning ? "none" : "auto",
}}
>
<button
className={cn("gap-1 w-full text-custom-primary-100 text-sm font-medium", buttonClassName)}
onClick={() => setShowAll((prev) => !prev)}
className={cn(
"gap-1 w-full text-custom-primary-100 text-sm font-medium transition-opacity duration-300",
buttonClassName
)}
onClick={handleToggle}
disabled={isTransitioning}
>
{showAll ? "Show less" : "Show all"}
</button>

View file

@ -28,20 +28,21 @@ export const ProjectLinkList: FC<TProjectLinkList> = observer((props) => {
if (links === undefined) return <WidgetLoader widgetKey={EWidgetKeys.QUICK_LINKS} />;
if (links.length === 0) return <LinksEmptyState handleCreate={() => toggleLinkModal(true)} />;
return (
<ContentOverflowWrapper
maxHeight={150}
containerClassName="pb-2 box-border"
fallback={<></>}
buttonClassName="bg-custom-background-90/20"
>
<div>
<div className="flex gap-2 mb-2 flex-wrap">
<div className="relative">
<ContentOverflowWrapper
maxHeight={150}
containerClassName="box-border min-h-[30px] flex flex-col"
fallback={<></>}
buttonClassName="bg-custom-background-90/20"
>
<div className="flex gap-2 mb-2 flex-wrap flex-1">
{links &&
links.length > 0 &&
links.map((linkId) => <ProjectLinkDetail key={linkId} linkId={linkId} linkOperations={linkOperations} />)}
</div>
</div>
</ContentOverflowWrapper>
</ContentOverflowWrapper>
</div>
);
});

View file

@ -17,6 +17,7 @@ import { FiltersDropdown } from "./filters";
import { RecentIssue } from "./issue";
import { RecentPage } from "./page";
import { RecentProject } from "./project";
import { ContentOverflowWrapper } from "@/components/core/content-overflow-HOC";
const WIDGET_KEY = EWidgetKeys.RECENT_ACTIVITY;
const workspaceService = new WorkspaceService();
@ -79,7 +80,12 @@ export const RecentActivityWidget: React.FC<THomeWidgetProps> = observer((props)
);
return (
<div ref={ref} className=" max-h-[500px] min-h-[250px] overflow-y-scroll">
<ContentOverflowWrapper
maxHeight={415}
containerClassName="box-border min-h-[250px]"
fallback={<></>}
buttonClassName="bg-custom-background-90/20"
>
<div className="flex items-center justify-between mb-2">
<div className="text-base font-semibold text-custom-text-350">Recents</div>
@ -89,8 +95,10 @@ export const RecentActivityWidget: React.FC<THomeWidgetProps> = observer((props)
{isLoading && <WidgetLoader widgetKey={WIDGET_KEY} />}
{!isLoading &&
recents?.length > 0 &&
recents.map((activity: TActivityEntityData) => <div key={activity.id}>{resolveRecent(activity)}</div>)}
recents
.filter((recent: TActivityEntityData) => recent.entity_data)
.map((activity: TActivityEntityData) => <div key={activity.id}>{resolveRecent(activity)}</div>)}
</div>
</div>
</ContentOverflowWrapper>
);
});