mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: workspace active cycles upgrade page implementation (#3454)
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
parent
a2f34e9573
commit
9d9d703c62
@ -20,3 +20,4 @@ export * from "./project-archived-issue-details";
|
|||||||
export * from "./project-archived-issues";
|
export * from "./project-archived-issues";
|
||||||
export * from "./project-issue-details";
|
export * from "./project-issue-details";
|
||||||
export * from "./user-profile";
|
export * from "./user-profile";
|
||||||
|
export * from "./workspace-active-cycles";
|
||||||
|
22
web/components/headers/workspace-active-cycles.tsx
Normal file
22
web/components/headers/workspace-active-cycles.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// ui
|
||||||
|
import { Breadcrumbs, ContrastIcon } from "@plane/ui";
|
||||||
|
// icons
|
||||||
|
import { Crown } from "lucide-react";
|
||||||
|
|
||||||
|
export const WorkspaceActiveCycleHeader = observer(() => (
|
||||||
|
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||||
|
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Breadcrumbs>
|
||||||
|
<Breadcrumbs.BreadcrumbItem
|
||||||
|
type="text"
|
||||||
|
icon={<ContrastIcon className="h-4 w-4 text-custom-text-300 rotate-180" />}
|
||||||
|
label="Active Cycles"
|
||||||
|
/>
|
||||||
|
</Breadcrumbs>
|
||||||
|
<Crown className="h-3.5 w-3.5 text-amber-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
));
|
@ -8,3 +8,4 @@ export * from "./send-workspace-invitation-modal";
|
|||||||
export * from "./sidebar-dropdown";
|
export * from "./sidebar-dropdown";
|
||||||
export * from "./sidebar-menu";
|
export * from "./sidebar-menu";
|
||||||
export * from "./sidebar-quick-action";
|
export * from "./sidebar-quick-action";
|
||||||
|
export * from "./workspace-active-cycles-upgrade";
|
||||||
|
@ -8,9 +8,12 @@ import { useApplication, useUser } from "hooks/store";
|
|||||||
import { NotificationPopover } from "components/notifications";
|
import { NotificationPopover } from "components/notifications";
|
||||||
// ui
|
// ui
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
|
import { Crown } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
import { SIDEBAR_MENU_ITEMS } from "constants/dashboard";
|
import { SIDEBAR_MENU_ITEMS } from "constants/dashboard";
|
||||||
|
// helper
|
||||||
|
import { cn } from "helpers/common.helper";
|
||||||
|
|
||||||
export const WorkspaceSidebarMenu = observer(() => {
|
export const WorkspaceSidebarMenu = observer(() => {
|
||||||
// store hooks
|
// store hooks
|
||||||
@ -44,8 +47,17 @@ export const WorkspaceSidebarMenu = observer(() => {
|
|||||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||||
} ${themeStore?.sidebarCollapsed ? "justify-center" : ""}`}
|
} ${themeStore?.sidebarCollapsed ? "justify-center" : ""}`}
|
||||||
>
|
>
|
||||||
{<link.Icon className="h-4 w-4" />}
|
{
|
||||||
|
<link.Icon
|
||||||
|
className={cn("h-4 w-4", {
|
||||||
|
"rotate-180": link.key === "active-cycles",
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
}
|
||||||
{!themeStore?.sidebarCollapsed && link.label}
|
{!themeStore?.sidebarCollapsed && link.label}
|
||||||
|
{!themeStore?.sidebarCollapsed && link.key === "active-cycles" && (
|
||||||
|
<Crown className="h-3.5 w-3.5 text-amber-400" />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</span>
|
</span>
|
||||||
|
100
web/components/workspace/workspace-active-cycles-upgrade.tsx
Normal file
100
web/components/workspace/workspace-active-cycles-upgrade.tsx
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
// hooks
|
||||||
|
import { useUser } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { getButtonStyling } from "@plane/ui";
|
||||||
|
// icons
|
||||||
|
import { Crown } from "lucide-react";
|
||||||
|
// helper
|
||||||
|
import { cn } from "helpers/common.helper";
|
||||||
|
// constants
|
||||||
|
import { WORKSPACE_ACTIVE_CYCLES_DETAILS } from "constants/cycle";
|
||||||
|
|
||||||
|
export const WorkspaceActiveCyclesUpgrade = observer(() => {
|
||||||
|
// store hooks
|
||||||
|
const { currentUser } = useUser();
|
||||||
|
|
||||||
|
const isDarkMode = currentUser?.theme.theme === "dark";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-10 p-8 rounded-xl">
|
||||||
|
<div
|
||||||
|
className={cn("flex item-center justify-between rounded-xl min-h-[25rem]", {
|
||||||
|
"bg-gradient-to-l from-[#CFCFCF] to-[#212121]": currentUser?.theme.theme === "dark",
|
||||||
|
"bg-gradient-to-l from-[#3b5ec6] to-[#f5f7fe]": currentUser?.theme.theme === "light",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div className="relative px-14 flex flex-col gap-7 justify-center lg:w-1/2">
|
||||||
|
<div className="flex flex-col gap-2 max-w-64">
|
||||||
|
<h2 className="text-2xl font-semibold">On-demand snapshots of all your cycles</h2>
|
||||||
|
<p className="text-base font-medium text-custom-text-300">
|
||||||
|
Monitor cycles across projects, track high-priority issues, and zoom in cycles that need attention.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<a
|
||||||
|
className={`${getButtonStyling("primary", "md")} cursor-pointer`}
|
||||||
|
href="https://plane.so/pricing"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<Crown className="h-3.5 w-3.5" />
|
||||||
|
Upgrade
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className={cn("text-sm underline", {
|
||||||
|
"text-white": currentUser?.theme.theme === "dark",
|
||||||
|
"text-blue-600": currentUser?.theme.theme === "light",
|
||||||
|
})}
|
||||||
|
href="https://plane.so/pricing"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
Talk custom pricing
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<span className="absolute left-0 top-0">
|
||||||
|
<Image
|
||||||
|
src={`/workspace-active-cycles/cta-l-1-${isDarkMode ? "dark" : "light"}.webp`}
|
||||||
|
height={125}
|
||||||
|
width={125}
|
||||||
|
className="rounded-xl"
|
||||||
|
alt="l-1"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="relative w-1/2 hidden lg:block">
|
||||||
|
<span className="absolute right-0 bottom-0">
|
||||||
|
<Image
|
||||||
|
src={`/workspace-active-cycles/cta-r-1-${isDarkMode ? "dark" : "light"}.webp`}
|
||||||
|
height={420}
|
||||||
|
width={500}
|
||||||
|
alt="r-1"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span className="absolute right-1/2 -bottom-16 rounded-xl">
|
||||||
|
<Image
|
||||||
|
src={`/workspace-active-cycles/cta-r-2-${isDarkMode ? "dark" : "light"}.webp`}
|
||||||
|
height={210}
|
||||||
|
width={280}
|
||||||
|
alt="r-2"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-5">
|
||||||
|
{WORKSPACE_ACTIVE_CYCLES_DETAILS.map((item) => (
|
||||||
|
<div className="flex flex-col gap-2 p-4 min-h-32 w-full bg-custom-background-80 rounded-md">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<h3 className="font-medium">{item.title}</h3>
|
||||||
|
<item.icon className="text-blue-500 h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-custom-text-300">{item.description}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -1,4 +1,15 @@
|
|||||||
import { GanttChartSquare, LayoutGrid, List } from "lucide-react";
|
import {
|
||||||
|
GanttChartSquare,
|
||||||
|
LayoutGrid,
|
||||||
|
List,
|
||||||
|
AlertOctagon,
|
||||||
|
BarChart4,
|
||||||
|
CircleDashed,
|
||||||
|
Folder,
|
||||||
|
Microscope,
|
||||||
|
Search,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import { TCycleLayout, TCycleView } from "@plane/types";
|
import { TCycleLayout, TCycleView } from "@plane/types";
|
||||||
|
|
||||||
@ -115,6 +126,43 @@ export const CYCLE_STATE_GROUPS_DETAILS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const WORKSPACE_ACTIVE_CYCLES_DETAILS = [
|
||||||
|
{
|
||||||
|
title: "10,000-feet view of all active cycles.",
|
||||||
|
description:
|
||||||
|
"Zoom out to see running cycles across all your projects at once instead of going from Cycle to Cycle in each project.",
|
||||||
|
icon: Folder,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Get a snapshot of each active cycle.",
|
||||||
|
description:
|
||||||
|
"Track high-level metrics for all active cycles, see their state of progress, and get a sense of scope against deadlines.",
|
||||||
|
icon: CircleDashed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Compare burndowns.",
|
||||||
|
description: "Monitor how each of your teams are performing with a peek into each cycle’s burndown report.",
|
||||||
|
icon: BarChart4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Quickly see make-or-break issues. ",
|
||||||
|
description:
|
||||||
|
"Preview high-priority issues for each cycle against due dates. See all of them per cycle in one click.",
|
||||||
|
icon: AlertOctagon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Zoom into cycles that need attention. ",
|
||||||
|
description: "Investigate the state of any cycle that doesn’t conform to expectations in one click.",
|
||||||
|
icon: Search,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Stay ahead of blockers.",
|
||||||
|
description:
|
||||||
|
"Spot challenges from one project to another and see inter-cycle dependencies that aren’t obvious from any other view.",
|
||||||
|
icon: Microscope,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const CYCLE_EMPTY_STATE_DETAILS = {
|
export const CYCLE_EMPTY_STATE_DETAILS = {
|
||||||
active: {
|
active: {
|
||||||
key: "active",
|
key: "active",
|
||||||
|
@ -19,6 +19,7 @@ import { Props } from "components/icons/types";
|
|||||||
import { EUserWorkspaceRoles } from "./workspace";
|
import { EUserWorkspaceRoles } from "./workspace";
|
||||||
// icons
|
// icons
|
||||||
import { BarChart2, Briefcase, CheckCircle, LayoutGrid } from "lucide-react";
|
import { BarChart2, Briefcase, CheckCircle, LayoutGrid } from "lucide-react";
|
||||||
|
import { ContrastIcon } from "@plane/ui";
|
||||||
|
|
||||||
// gradients for issues by priority widget graph bars
|
// gradients for issues by priority widget graph bars
|
||||||
export const PRIORITY_GRAPH_GRADIENTS = [
|
export const PRIORITY_GRAPH_GRADIENTS = [
|
||||||
@ -292,4 +293,12 @@ export const SIDEBAR_MENU_ITEMS: {
|
|||||||
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/workspace-views/all-issues`,
|
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/workspace-views/all-issues`,
|
||||||
Icon: CheckCircle,
|
Icon: CheckCircle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "active-cycles",
|
||||||
|
label: "Active Cycles",
|
||||||
|
href: `/active-cycles`,
|
||||||
|
access: EUserWorkspaceRoles.GUEST,
|
||||||
|
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/active-cycles`,
|
||||||
|
Icon: ContrastIcon,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
16
web/pages/[workspaceSlug]/active-cycles.tsx
Normal file
16
web/pages/[workspaceSlug]/active-cycles.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { ReactElement } from "react";
|
||||||
|
// components
|
||||||
|
import { WorkspaceActiveCycleHeader } from "components/headers";
|
||||||
|
import { WorkspaceActiveCyclesUpgrade } from "components/workspace";
|
||||||
|
// layouts
|
||||||
|
import { AppLayout } from "layouts/app-layout";
|
||||||
|
// types
|
||||||
|
import { NextPageWithLayout } from "lib/types";
|
||||||
|
|
||||||
|
const WorkspaceActiveCyclesPage: NextPageWithLayout = () => <WorkspaceActiveCyclesUpgrade />;
|
||||||
|
|
||||||
|
WorkspaceActiveCyclesPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <AppLayout header={<WorkspaceActiveCycleHeader />}>{page}</AppLayout>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkspaceActiveCyclesPage;
|
BIN
web/public/workspace-active-cycles/cta-l-1-dark.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-l-1-dark.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
web/public/workspace-active-cycles/cta-l-1-light.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-l-1-light.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
web/public/workspace-active-cycles/cta-r-1-dark.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-1-dark.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
web/public/workspace-active-cycles/cta-r-1-light.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-1-light.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
BIN
web/public/workspace-active-cycles/cta-r-2-dark.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-2-dark.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 377 KiB |
BIN
web/public/workspace-active-cycles/cta-r-2-light.webp
Normal file
BIN
web/public/workspace-active-cycles/cta-r-2-light.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 383 KiB |
Loading…
Reference in New Issue
Block a user