[WEB-2273] Chore: page alignments (#5505)

* chore: headers + common containers

* fix: filters code splitting

* fix: home header

* fix: header changes

* chore: page alignments fixed

* fix: uncommented filters

* fix: used enums

* fix: cards + filters

* fix: enum changes

* fix: reverted package changes

* fix: reverted package changes

* fix: Card + tags seperated + naming fixed

* fix: card + tags seperated + naming fixed

* fix: mobile headers fixed partially

* fix: build errors + minor css

* fix: checkbox spacing

* fix: review changes

* fix: lint errors

* fix: minor review changes
This commit is contained in:
Akshita Goyal 2024-09-05 12:16:24 +05:30 committed by GitHub
parent c78b2344b8
commit 87dbb9b888
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
181 changed files with 1323 additions and 1122 deletions

View file

@ -5,6 +5,7 @@ import useSWR from "swr";
import { IAnalyticsParams } from "@plane/types";
// services
// components
import { ContentWrapper } from "@plane/ui";
import { CustomAnalyticsSelectBar, CustomAnalyticsMainContent, CustomAnalyticsSidebar } from "@/components/analytics";
// types
// fetch-keys
@ -53,7 +54,7 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
return (
<div className={cn("relative flex h-full w-full overflow-hidden", isProjectLevel ? "flex-col-reverse" : "")}>
<div className="flex h-full w-full flex-col overflow-hidden">
<ContentWrapper>
<CustomAnalyticsSelectBar
control={control}
setValue={setValue}
@ -67,7 +68,7 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
params={params}
fullScreen={fullScreen}
/>
</div>
</ContentWrapper>
<div
className={cn(

View file

@ -51,7 +51,7 @@ export const CustomAnalyticsMainContent: React.FC<Props> = (props) => {
</div>
)
) : (
<Loader className="space-y-6 p-5">
<Loader className="space-y-6">
<Loader.Item height="300px" />
<Loader className="space-y-4">
<Loader.Item height="30px" />

View file

@ -31,13 +31,13 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
return (
<div
className={`grid items-center gap-4 px-5 py-2.5 ${
className={`grid items-center gap-4 pb-2.5 ${
isProjectLevel ? "grid-cols-1 sm:grid-cols-3" : "grid-cols-2"
} ${fullScreen ? "md:py-5 lg:grid-cols-4" : ""}`}
} ${fullScreen ? "md:pb-5 lg:grid-cols-4" : ""}`}
>
{!isProjectLevel && (
<div>
<h6 className="text-xs text-custom-text-200">Project</h6>
<h6 className="text-xs text-custom-text-200 mb-2">Project</h6>
<Controller
name="project"
control={control}
@ -52,7 +52,7 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
</div>
)}
<div>
<h6 className="text-xs text-custom-text-200">Measure (y-axis)</h6>
<h6 className="text-xs text-custom-text-200 mb-2">Measure (y-axis)</h6>
<Controller
name="y_axis"
control={control}
@ -60,7 +60,7 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
/>
</div>
<div>
<h6 className="text-xs text-custom-text-200">Dimension (x-axis)</h6>
<h6 className="text-xs text-custom-text-200 mb-2">Dimension (x-axis)</h6>
<Controller
name="x_axis"
control={control}
@ -79,7 +79,7 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
/>
</div>
<div>
<h6 className="text-xs text-custom-text-200">Group</h6>
<h6 className="text-xs text-custom-text-200 mb-2">Group</h6>
<Controller
name="segment"
control={control}

View file

@ -19,11 +19,11 @@ type Props = {
};
export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, params, yAxisKey }) => (
<div className="w-full overflow-hidden overflow-x-auto">
<div className="w-full overflow-hidden overflow-x-auto absolute left-0">
<table className="w-full overflow-hidden divide-y divide-custom-border-200 whitespace-nowrap border-y border-custom-border-200">
<thead className="bg-custom-background-80">
<tr className="divide-x divide-custom-border-200 text-sm text-custom-text-100">
<th scope="col" className="px-2.5 py-3 text-left font-medium">
<th scope="col" className="px-page-x py-3 text-left font-medium">
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label}
</th>
{params.segment ? (
@ -31,7 +31,7 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
<th
key={`segment-${key}`}
scope="col"
className={`px-2.5 py-3 text-left font-medium ${
className={`px-page-x py-3 text-left font-medium ${
params.segment === "priority" || params.segment === "state__group" ? "capitalize" : ""
}`}
>
@ -51,7 +51,7 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
</th>
))
) : (
<th scope="col" className="px-2.5 py-3 text-left font-medium sm:pr-0">
<th scope="col" className="px-page-x py-3 text-left font-medium sm:pr-0">
{ANALYTICS_Y_AXIS_VALUES.find((v) => v.value === params.y_axis)?.label}
</th>
)}
@ -60,7 +60,7 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
<tbody className="divide-y divide-custom-border-200">
{barGraphData.data.map((item, index) => (
<tr key={`table-row-${index}`} className="divide-x divide-custom-border-200 text-xs text-custom-text-200">
<td className="px-2.5 py-2">
<td className="px-page-x py-2">
<div className="relative flex items-center gap-2 w-full overflow-hidden">
<div className="flex-shrink-0 h-3 w-3 rounded overflow-hidden">
{params.x_axis === "priority" ? (
@ -90,12 +90,12 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
</td>
{params.segment ? (
barGraphData.xAxisKeys.map((key, index) => (
<td key={`segment-value-${index}`} className="whitespace-nowrap px-2.5 py-2 sm:pr-0">
<td key={`segment-value-${index}`} className="whitespace-nowrap px-page-x py-2 sm:pr-0">
{item[key] ?? 0}
</td>
))
) : (
<td className="whitespace-nowrap px-2.5 py-2 sm:pr-0">{item[yAxisKey]}</td>
<td className="whitespace-nowrap px-page-x py-2 sm:pr-0">{item[yAxisKey]}</td>
)}
</tr>
))}

View file

@ -1,6 +1,7 @@
// types
import { IDefaultAnalyticsResponse, TStateGroups } from "@plane/types";
// constants
import { Card } from "@plane/ui";
import { STATE_GROUPS } from "@/constants/state";
type Props = {
@ -8,7 +9,7 @@ type Props = {
};
export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
<div className="space-y-3 rounded-[10px] border border-custom-border-200 p-3">
<Card>
<div>
<h4 className="text-base font-medium text-custom-text-100">Total open tasks</h4>
<h3 className="mt-1 text-xl font-semibold">{defaultAnalytics.open_issues}</h3>
@ -47,5 +48,5 @@ export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
);
})}
</div>
</div>
</Card>
);

View file

@ -1,4 +1,5 @@
// ui
import { Card } from "@plane/ui";
import { ProfileEmptyState } from "@/components/ui";
// image
import emptyUsers from "@/public/empty-state/empty_users.svg";
@ -18,7 +19,7 @@ type Props = {
};
export const AnalyticsLeaderBoard: React.FC<Props> = ({ users, title, emptyStateMessage, workspaceSlug }) => (
<div className="rounded-[10px] border border-custom-border-200 p-3">
<Card>
<h6 className="text-base font-medium">{title}</h6>
{users.length > 0 ? (
<div className="mt-3 space-y-3">
@ -57,5 +58,5 @@ export const AnalyticsLeaderBoard: React.FC<Props> = ({ users, title, emptyState
<ProfileEmptyState title="No Data yet" description={emptyStateMessage} image={emptyUsers} />
</div>
)}
</div>
</Card>
);

View file

@ -2,7 +2,7 @@
import { useParams } from "next/navigation";
import useSWR from "swr";
// ui
import { Button, Loader } from "@plane/ui";
import { Button, ContentWrapper, Loader } from "@plane/ui";
// components
import { AnalyticsDemand, AnalyticsLeaderBoard, AnalyticsScope, AnalyticsYearWiseIssues } from "@/components/analytics";
// fetch-keys
@ -50,7 +50,7 @@ export const ScopeAndDemand: React.FC<Props> = (props) => {
<>
{!defaultAnalyticsError ? (
defaultAnalytics ? (
<div className="h-full overflow-y-auto p-5 text-sm vertical-scrollbar scrollbar-lg">
<ContentWrapper>
<div className={`grid grid-cols-1 gap-5 ${fullScreen ? "md:grid-cols-2" : ""}`}>
<AnalyticsDemand defaultAnalytics={defaultAnalytics} />
<AnalyticsScope
@ -87,7 +87,7 @@ export const ScopeAndDemand: React.FC<Props> = (props) => {
<AnalyticsYearWiseIssues defaultAnalytics={defaultAnalytics} />
</div>
</div>
</div>
</ContentWrapper>
) : (
<Loader className="grid grid-cols-1 gap-5 p-5 lg:grid-cols-2">
<Loader.Item height="250px" />

View file

@ -1,5 +1,6 @@
// ui
import { IDefaultAnalyticsUser } from "@plane/types";
import { Card } from "@plane/ui";
import { BarGraph, ProfileEmptyState } from "@/components/ui";
// image
import emptyBarGraph from "@/public/empty-state/empty_bar_graph.svg";
@ -11,7 +12,7 @@ type Props = {
};
export const AnalyticsScope: React.FC<Props> = ({ pendingUnAssignedIssuesUser, pendingAssignedIssues }) => (
<div className="rounded-[10px] border border-custom-border-200 p-3">
<Card>
<div className="divide-y divide-custom-border-200">
<div>
<div className="flex items-center justify-between">
@ -87,5 +88,5 @@ export const AnalyticsScope: React.FC<Props> = ({ pendingUnAssignedIssuesUser, p
)}
</div>
</div>
</div>
</Card>
);

View file

@ -1,5 +1,6 @@
// ui
import { IDefaultAnalyticsResponse } from "@plane/types";
import { Card } from "@plane/ui";
import { LineGraph, ProfileEmptyState } from "@/components/ui";
// image
import { MONTHS_LIST } from "@/constants/calendar";
@ -12,8 +13,8 @@ type Props = {
};
export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) => (
<div className="rounded-[10px] border border-custom-border-200 py-3">
<h1 className="px-3 text-base font-medium">Issues closed in a year</h1>
<Card>
<h1 className="py-3 text-base font-medium">Issues closed in a year</h1>
{defaultAnalytics.issue_completed_month_wise.length > 0 ? (
<LineGraph
data={[
@ -55,5 +56,5 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
/>
</div>
)}
</div>
</Card>
);

View file

@ -38,7 +38,7 @@ export const AppliedDateFilters: React.FC<Props> = observer((props) => {
return (
<>
{values.map((date) => (
<div key={date} className="flex items-center gap-1 rounded bg-custom-background-80 p-1 text-xs">
<div key={date} className="flex items-center gap-1 rounded bg-custom-background-80 py-1 px-1.5 text-xs">
<span className="normal-case">{getDateLabel(date)}</span>
{editable && (
<button

View file

@ -28,8 +28,8 @@ export const AppliedMembersFilters: React.FC<Props> = observer((props) => {
if (!memberDetails) return null;
return (
<div key={memberId} className="flex items-center gap-1 rounded bg-custom-background-80 p-1 text-xs">
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} />
<div key={memberId} className="flex items-center gap-1 rounded bg-custom-background-80 py-1 px-1.5 text-xs">
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} size={"sm"} />
<span className="normal-case">{memberDetails.display_name}</span>
{editable && (
<button

View file

@ -33,7 +33,7 @@ export const BreadcrumbLink: React.FC<Props> = (props) => {
</Link>
) : (
<div className="flex cursor-default items-center gap-1 text-sm font-medium text-custom-text-100">
{icon && <div className="flex h-5 w-5 items-center justify-center overflow-hidden">{icon}</div>}
{icon && <div className="flex h-5 w-5 items-center justify-start overflow-hidden">{icon}</div>}
<div className="relative line-clamp-1 block max-w-[150px] overflow-hidden truncate">{label}</div>
</div>
)}

View file

@ -2,7 +2,7 @@
import { ReactNode } from "react";
// components
import { CustomRow } from "@plane/ui";
import { Row } from "@plane/ui";
import { SidebarHamburgerToggle } from "@/components/core";
export interface AppHeaderProps {
@ -15,12 +15,12 @@ export const AppHeader = (props: AppHeaderProps) => {
return (
<div className="z-[15]">
<CustomRow className="h-[3.75rem] z-10 flex gap-2 w-full items-center border-b border-custom-border-200">
<Row className="h-[3.75rem] z-10 flex gap-2 w-full items-center border-b border-custom-border-200">
<div className="block bg-custom-sidebar-background-100 md:hidden">
<SidebarHamburgerToggle />
</div>
<div className="w-full">{header}</div>
</CustomRow>
</Row>
{mobileHeader && mobileHeader}
</div>
);

View file

@ -1,7 +1,7 @@
"use client";
import React, { FC } from "react";
// ui
import { ControlLink, Tooltip } from "@plane/ui";
import { ControlLink, Row, Tooltip } from "@plane/ui";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
@ -51,9 +51,9 @@ export const ListItem: FC<IListItemProps> = (props) => {
return (
<div ref={parentRef} className="relative">
<div
<Row
className={cn(
"group min-h-[52px] flex w-full flex-col items-center justify-between gap-3 px-6 py-4 text-sm border-b border-custom-border-200 bg-custom-background-100 hover:bg-custom-background-90 ",
"group min-h-[52px] flex w-full flex-col items-center justify-between gap-3 py-4 text-sm border-b border-custom-border-200 bg-custom-background-100 hover:bg-custom-background-90 ",
{
"xl:gap-5 xl:py-0 xl:flex-row": isSidebarOpen,
"lg:gap-5 lg:py-0 lg:flex-row": !isSidebarOpen,
@ -93,7 +93,7 @@ export const ListItem: FC<IListItemProps> = (props) => {
{actionableItems}
</div>
)}
</div>
</Row>
</div>
);
};

View file

@ -1,4 +1,5 @@
import React, { FC } from "react";
import { Row, ERowVariant } from "@plane/ui";
interface IListContainer {
children: React.ReactNode;
@ -6,5 +7,12 @@ interface IListContainer {
export const ListLayout: FC<IListContainer> = (props) => {
const { children } = props;
return <div className="flex h-full w-full flex-col overflow-y-auto vertical-scrollbar scrollbar-lg">{children}</div>;
return (
<Row
variant={ERowVariant.HUGGING}
className="flex h-full w-full flex-col overflow-y-auto vertical-scrollbar scrollbar-lg"
>
{children}
</Row>
);
};

View file

@ -2,6 +2,8 @@
import { observer } from "mobx-react";
import { Disclosure } from "@headlessui/react";
// ui
import { Row } from "@plane/ui";
// components
import {
ActiveCycleProductivity,
@ -36,14 +38,14 @@ export const ActiveCycleRoot: React.FC<IActiveCycleDetails> = observer((props) =
<Disclosure as="div" className="flex flex-shrink-0 flex-col" defaultOpen>
{({ open }) => (
<>
<Disclosure.Button className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 px-7 py-1 cursor-pointer">
<Disclosure.Button className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 cursor-pointer">
<CycleListGroupHeader title="Active cycle" type="current" isExpanded={open} />
</Disclosure.Button>
<Disclosure.Panel>
{!currentProjectActiveCycle ? (
<EmptyState type={EmptyStateType.PROJECT_CYCLE_ACTIVE} size="sm" />
) : (
<div className="flex flex-col bg-custom-background-90 border-b border-custom-border-200">
<div className="flex flex-col border-b border-custom-border-200">
{currentProjectActiveCycleId && (
<CyclesListItem
key={currentProjectActiveCycleId}
@ -53,7 +55,7 @@ export const ActiveCycleRoot: React.FC<IActiveCycleDetails> = observer((props) =
className="!border-b-transparent"
/>
)}
<div className="bg-custom-background-100 pt-3 pb-6 px-6">
<Row className="bg-custom-background-100 pt-3 pb-6">
<div className="grid grid-cols-1 bg-custom-background-100 gap-3 lg:grid-cols-2 xl:grid-cols-3">
<ActiveCycleProgress
handleFiltersUpdate={handleFiltersUpdate}
@ -75,7 +77,7 @@ export const ActiveCycleRoot: React.FC<IActiveCycleDetails> = observer((props) =
cycleIssueDetails={cycleIssueDetails as ActiveCycleIssueDetails}
/>
</div>
</div>
</Row>
</div>
)}
</Disclosure.Panel>

View file

@ -37,7 +37,7 @@ export const AppliedDateFilters: React.FC<Props> = observer((props) => {
return (
<>
{values.map((date) => (
<div key={date} className="flex items-center gap-1 rounded bg-custom-background-80 p-1 text-xs">
<div key={date} className="flex items-center gap-1 rounded bg-custom-background-80 py-1 px-1.5 text-xs">
<span className="normal-case">{getDateLabel(date)}</span>
{editable && (
<button

View file

@ -2,6 +2,7 @@ import { observer } from "mobx-react";
import { X } from "lucide-react";
import { TCycleFilters } from "@plane/types";
// hooks
import { Tag } from "@plane/ui";
import { AppliedDateFilters, AppliedStatusFilters } from "@/components/cycles";
import { EUserProjectRoles } from "@/constants/project";
import { replaceUnderscoreIfSnakeCase } from "@/helpers/string.helper";
@ -42,10 +43,7 @@ export const CycleAppliedFiltersList: React.FC<Props> = observer((props) => {
if (Array.isArray(value) && value.length === 0) return;
return (
<div
key={filterKey}
className="flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1 capitalize"
>
<Tag key={filterKey}>
<span className="text-xs text-custom-text-300">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
<div className="flex flex-wrap items-center gap-1">
{filterKey === "status" && (
@ -72,17 +70,15 @@ export const CycleAppliedFiltersList: React.FC<Props> = observer((props) => {
</button>
)}
</div>
</div>
</Tag>
);
})}
{isEditingAllowed && (
<button
type="button"
onClick={handleClearAllFilters}
className="flex items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1 text-xs text-custom-text-300 hover:text-custom-text-200"
>
Clear all
<X size={12} strokeWidth={2} />
<button type="button" onClick={handleClearAllFilters}>
<Tag>
Clear all
<X size={12} strokeWidth={2} />
</Tag>
</button>
)}
</div>

View file

@ -20,7 +20,7 @@ export const AppliedStatusFilters: React.FC<Props> = observer((props) => {
<div
key={status}
className={cn(
"flex items-center gap-1 rounded p-1 text-xs",
"flex items-center gap-1 rounded py-1 px-1.5 text-xs",
statusDetails?.bgColor,
statusDetails?.textColor
)}

View file

@ -50,14 +50,12 @@ export const CyclesView: FC<ICyclesView> = observer((props) => {
);
return (
<>
<CyclesList
completedCycleIds={filteredCompletedCycleIds ?? []}
upcomingCycleIds={filteredUpcomingCycleIds}
cycleIds={filteredCycleIds}
workspaceSlug={workspaceSlug}
projectId={projectId}
/>
</>
<CyclesList
completedCycleIds={filteredCompletedCycleIds ?? []}
upcomingCycleIds={filteredUpcomingCycleIds}
cycleIds={filteredCycleIds}
workspaceSlug={workspaceSlug}
projectId={projectId}
/>
);
});

View file

@ -5,7 +5,7 @@ import { ChevronDown } from "lucide-react";
// types
import { TCycleGroups } from "@plane/types";
// icons
import { CycleGroupIcon } from "@plane/ui";
import { Row, CycleGroupIcon } from "@plane/ui";
// helpers
import { cn } from "@/helpers/common.helper";
@ -20,7 +20,7 @@ type Props = {
export const CycleListGroupHeader: FC<Props> = (props) => {
const { type, title, count, showCount = false, isExpanded = false } = props;
return (
<div className="relative flex items-center justify-between w-full gap-5 py-1.5">
<Row className="flex items-center justify-between py-2.5">
<div className="flex items-center gap-5 flex-shrink-0">
<div className="flex h-5 w-5 flex-shrink-0 items-center justify-center overflow-hidden rounded-sm">
<CycleGroupIcon cycleGroup={type} className="h-5 w-5" />
@ -36,6 +36,6 @@ export const CycleListGroupHeader: FC<Props> = (props) => {
"rotate-180": isExpanded,
})}
/>
</div>
</Row>
);
};

View file

@ -2,6 +2,7 @@ import { FC } from "react";
import { observer } from "mobx-react";
import { Disclosure } from "@headlessui/react";
// components
import { ContentWrapper, ERowVariant } from "@plane/ui";
import { ListLayout } from "@/components/core/list";
import { ActiveCycleRoot, CycleListGroupHeader, CyclePeekOverview, CyclesListMap } from "@/components/cycles";
@ -18,7 +19,7 @@ export const CyclesList: FC<ICyclesList> = observer((props) => {
const { completedCycleIds, upcomingCycleIds, cycleIds, workspaceSlug, projectId, isArchived = false } = props;
return (
<div className="flex h-full w-full justify-between ">
<ContentWrapper variant={ERowVariant.HUGGING}>
<ListLayout>
{isArchived ? (
<>
@ -32,7 +33,7 @@ export const CyclesList: FC<ICyclesList> = observer((props) => {
<Disclosure as="div" className="flex flex-shrink-0 flex-col" defaultOpen>
{({ open }) => (
<>
<Disclosure.Button className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 px-7 py-1 cursor-pointer">
<Disclosure.Button className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 cursor-pointer">
<CycleListGroupHeader
title="Upcoming cycle"
type="upcoming"
@ -52,7 +53,7 @@ export const CyclesList: FC<ICyclesList> = observer((props) => {
<Disclosure as="div" className="flex flex-shrink-0 flex-col pb-7">
{({ open }) => (
<>
<Disclosure.Button className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 px-7 py-1 cursor-pointer">
<Disclosure.Button className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 cursor-pointer">
<CycleListGroupHeader
title="Completed cycle"
type="completed"
@ -71,6 +72,6 @@ export const CyclesList: FC<ICyclesList> = observer((props) => {
)}
</ListLayout>
<CyclePeekOverview projectId={projectId} workspaceSlug={workspaceSlug} isArchived={isArchived} />
</div>
</ContentWrapper>
);
});

View file

@ -4,6 +4,7 @@ import Link from "next/link";
import { Tab } from "@headlessui/react";
import { TAssignedIssuesWidgetFilters, TAssignedIssuesWidgetResponse } from "@plane/types";
// hooks
import { Card } from "@plane/ui";
import {
DurationFilterDropdown,
IssuesErrorState,
@ -79,7 +80,7 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
if ((!widgetDetails || !widgetStats) && !widgetStatsError) return <WidgetLoader widgetKey={WIDGET_KEY} />;
return (
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col min-h-96">
<Card>
{widgetStatsError ? (
<IssuesErrorState
isRefreshing={fetching}
@ -93,7 +94,7 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
) : (
widgetStats && (
<>
<div className="flex items-center justify-between gap-2 p-6 pl-7">
<div className="flex items-center justify-between gap-2 mb-4">
<Link
href={`/${workspaceSlug}/workspace-views/assigned/${filterParams}`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
@ -137,9 +138,7 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
}}
className="h-full flex flex-col"
>
<div className="px-6">
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
</div>
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
<Tab.Panels as="div" className="h-full">
{tabsList.map((tab) => {
if (tab.key !== selectedTab) return null;
@ -161,6 +160,6 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
</>
)
)}
</div>
</Card>
);
});

View file

@ -4,6 +4,7 @@ import Link from "next/link";
import { Tab } from "@headlessui/react";
import { TCreatedIssuesWidgetFilters, TCreatedIssuesWidgetResponse } from "@plane/types";
// hooks
import { Card } from "@plane/ui";
import {
DurationFilterDropdown,
IssuesErrorState,
@ -76,7 +77,7 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
if ((!widgetDetails || !widgetStats) && !widgetStatsError) return <WidgetLoader widgetKey={WIDGET_KEY} />;
return (
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col min-h-96">
<Card>
{widgetStatsError ? (
<IssuesErrorState
isRefreshing={fetching}
@ -90,7 +91,7 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
) : (
widgetStats && (
<>
<div className="flex items-center justify-between gap-2 p-6 pl-7">
<div className="flex items-center justify-between gap-2 mb-4">
<Link
href={`/${workspaceSlug}/workspace-views/created/${filterParams}`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
@ -134,9 +135,7 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
}}
className="h-full flex flex-col"
>
<div className="px-6">
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
</div>
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
<Tab.Panels as="div" className="h-full">
{tabsList.map((tab) => {
if (tab.key !== selectedTab) return null;
@ -158,6 +157,6 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
</>
)
)}
</div>
</Card>
);
});

View file

@ -66,7 +66,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
<>
<div className="h-full">
{isLoading ? (
<Loader className="space-y-4 mx-6 mt-7">
<Loader className="space-y-4 mt-7">
<Loader.Item height="25px" />
<Loader.Item height="25px" />
<Loader.Item height="25px" />
@ -74,7 +74,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
</Loader>
) : issuesList.length > 0 ? (
<>
<div className="mt-7 mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-12 gap-1 text-xs text-custom-text-300 pb-1">
<div className="mt-7 border-b-[0.5px] border-custom-border-200 grid grid-cols-12 gap-1 text-xs text-custom-text-300 pb-1">
<h6
className={cn("pl-1 flex items-center gap-1 col-span-7", {
"col-span-11": type === "assigned" && tab === "completed",
@ -92,7 +92,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
{type === "assigned" && tab !== "completed" && <h6 className="text-center col-span-2">Blocked by</h6>}
{type === "created" && <h6 className="text-center col-span-2">Assigned to</h6>}
</div>
<div className="px-4 pb-3 mt-2">
<div className="pb-3 mt-2">
{issuesList.map((issue) => {
const IssueListItem = ISSUE_LIST_ITEM[type][tab];

View file

@ -4,6 +4,7 @@ import Link from "next/link";
// types
import { TIssuesByPriorityWidgetFilters, TIssuesByPriorityWidgetResponse } from "@plane/types";
// components
import { Card } from "@plane/ui";
import {
DurationFilterDropdown,
IssuesByPriorityEmptyState,
@ -69,8 +70,8 @@ export const IssuesByPriorityWidget: React.FC<WidgetProps> = observer((props) =>
}));
return (
<div className="flex min-h-96 w-full flex-col overflow-hidden rounded-xl border-[0.5px] border-custom-border-200 bg-custom-background-100 py-6 duration-300 hover:shadow-custom-shadow-4xl">
<div className="flex items-center justify-between gap-2 pl-7 pr-6">
<Card>
<div className="flex items-center justify-between gap-2 mb-4">
<Link
href={`/${workspaceSlug}/workspace-views/assigned`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
@ -106,6 +107,6 @@ export const IssuesByPriorityWidget: React.FC<WidgetProps> = observer((props) =>
<IssuesByPriorityEmptyState />
</div>
)}
</div>
</Card>
);
});

View file

@ -4,6 +4,7 @@ import Link from "next/link";
// types
import { TIssuesByStateGroupsWidgetFilters, TIssuesByStateGroupsWidgetResponse, TStateGroups } from "@plane/types";
// components
import { Card } from "@plane/ui";
import {
DurationFilterDropdown,
IssuesByStateGroupEmptyState,
@ -79,14 +80,14 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
startedCount > 0
? "started"
: unStartedCount > 0
? "unstarted"
: backlogCount > 0
? "backlog"
: completedCount > 0
? "completed"
: canceledCount > 0
? "cancelled"
: null;
? "unstarted"
: backlogCount > 0
? "backlog"
: completedCount > 0
? "completed"
: canceledCount > 0
? "cancelled"
: null;
setActiveStateGroup(stateGroup);
setDefaultStateGroup(stateGroup);
@ -134,8 +135,8 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
};
return (
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 overflow-hidden min-h-96 flex flex-col">
<div className="flex items-center justify-between gap-2 pl-7 pr-6">
<Card>
<div className="flex items-center justify-between gap-2 mb-4">
<Link
href={`/${workspaceSlug}/workspace-views/assigned`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
@ -154,7 +155,7 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
/>
</div>
{totalCount > 0 ? (
<div className="flex items-center pl-10 md:pl-11 lg:pl-14 pr-11 mt-11">
<div className="flex items-center mt-11">
<div className="flex flex-col sm:flex-row md:flex-row lg:flex-row items-center justify-evenly gap-x-10 gap-y-8 w-full">
<div>
<PieGraph
@ -215,6 +216,6 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
<IssuesByStateGroupEmptyState />
</div>
)}
</div>
</Card>
);
});

View file

@ -3,6 +3,7 @@ import { observer } from "mobx-react";
import Link from "next/link";
import { TOverviewStatsWidgetResponse } from "@plane/types";
// hooks
import { Card, ECardSpacing } from "@plane/ui";
import { WidgetLoader } from "@/components/dashboard/widgets";
import { cn } from "@/helpers/common.helper";
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
@ -63,8 +64,9 @@ export const OverviewStatsWidget: React.FC<WidgetProps> = observer((props) => {
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
return (
<div
className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full grid lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-2 grid-cols-2 p-0.5 hover:shadow-custom-shadow-4xl duration-300
<Card
spacing={ECardSpacing.SM}
className="flex-row grid lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-2 grid-cols-2 space-y-0
[&>div>a>div]:border-r
[&>div:last-child>a>div]:border-0
[&>div>a>div]:border-custom-border-200
@ -93,6 +95,6 @@ export const OverviewStatsWidget: React.FC<WidgetProps> = observer((props) => {
</Link>
</div>
))}
</div>
</Card>
);
});

View file

@ -6,9 +6,8 @@ import Link from "next/link";
import { History } from "lucide-react";
// types
import { TRecentActivityWidgetResponse } from "@plane/types";
// UI
import { Avatar, getButtonStyling } from "@plane/ui";
// components
import { Card, Avatar, getButtonStyling } from "@plane/ui";
import { ActivityIcon, ActivityMessage, IssueLink } from "@/components/core";
import { RecentActivityEmptyState, WidgetLoader, WidgetProps } from "@/components/dashboard/widgets";
// helpers
@ -38,12 +37,12 @@ export const RecentActivityWidget: React.FC<WidgetProps> = observer((props) => {
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
return (
<div className="min-h-96 w-full rounded-xl border-[0.5px] border-custom-border-200 bg-custom-background-100 py-6 duration-300 hover:shadow-custom-shadow-4xl">
<Link href={redirectionLink} className="mx-7 text-lg font-semibold text-custom-text-300 hover:underline">
<Card>
<Link href={redirectionLink} className="text-lg font-semibold text-custom-text-300 hover:underline mb-4">
Your issue activities
</Link>
{widgetStats.length > 0 ? (
<div className="mx-7 mt-4 space-y-6">
<div className="mt-4 space-y-6">
{widgetStats.map((activity) => (
<div key={activity.id} className="flex gap-5">
<div className="flex-shrink-0">
@ -104,6 +103,6 @@ export const RecentActivityWidget: React.FC<WidgetProps> = observer((props) => {
<RecentActivityEmptyState />
</div>
)}
</div>
</Card>
);
});

View file

@ -1,6 +1,7 @@
import { useState } from "react";
import { Search } from "lucide-react";
// types
import { Card } from "@plane/ui";
import { WidgetProps } from "@/components/dashboard/widgets";
// components
import { DefaultCollaboratorsList } from "./default-list";
@ -14,15 +15,15 @@ export const RecentCollaboratorsWidget: React.FC<WidgetProps> = (props) => {
const [searchQuery, setSearchQuery] = useState("");
return (
<div className="w-full rounded-xl border-[0.5px] border-custom-border-200 bg-custom-background-100 duration-300 hover:shadow-custom-shadow-4xl">
<div className="flex flex-col sm:flex-row items-start justify-between px-7 pt-6">
<Card>
<div className="flex flex-col sm:flex-row items-start justify-between mb-6">
<div>
<h4 className="text-lg font-semibold text-custom-text-300">Collaborators</h4>
<p className="mt-2 text-xs font-medium text-custom-text-300">
View and find all members you collaborate with across projects
</p>
</div>
<div className="mt-5 sm:mt-0 flex min-w-72 items-center justify-start gap-2 rounded-md border border-custom-border-200 px-2.5 py-1.5 placeholder:text-custom-text-400">
<div className="mt-5 sm:mt-0 flex min-w-full md:min-w-72 items-center justify-start gap-2 rounded-md border border-custom-border-200 px-2.5 py-1.5 placeholder:text-custom-text-400">
<Search className="h-3.5 w-3.5 text-custom-text-400" />
<input
className="w-full border-none bg-transparent text-sm focus:outline-none"
@ -42,6 +43,6 @@ export const RecentCollaboratorsWidget: React.FC<WidgetProps> = (props) => {
) : (
<DefaultCollaboratorsList dashboardId={dashboardId} perPage={PER_PAGE} workspaceSlug={workspaceSlug} />
)}
</div>
</Card>
);
};

View file

@ -7,7 +7,8 @@ import { Plus } from "lucide-react";
// types
import { TRecentProjectsWidgetResponse } from "@plane/types";
// ui
import { Avatar, AvatarGroup } from "@plane/ui";
import { Avatar, AvatarGroup, Card } from "@plane/ui";
// components
import { Logo } from "@/components/common";
import { WidgetLoader, WidgetProps } from "@/components/dashboard/widgets";
@ -82,14 +83,14 @@ export const RecentProjectsWidget: React.FC<WidgetProps> = observer((props) => {
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
return (
<div className="min-h-96 w-full rounded-xl border-[0.5px] border-custom-border-200 bg-custom-background-100 py-6 duration-300 hover:shadow-custom-shadow-4xl">
<Card>
<Link
href={`/${workspaceSlug}/projects`}
className="mx-7 text-lg font-semibold text-custom-text-300 hover:underline"
className="text-lg font-semibold text-custom-text-300 hover:underline mb-4"
>
Recent projects
</Link>
<div className="mx-7 mt-4 space-y-8">
<div className="mt-4 space-y-8">
{canCreateProject && (
<button
type="button"
@ -113,6 +114,6 @@ export const RecentProjectsWidget: React.FC<WidgetProps> = observer((props) => {
<ProjectListItem key={projectId} projectId={projectId} workspaceSlug={workspaceSlug} />
))}
</div>
</div>
</Card>
);
});

View file

@ -93,7 +93,7 @@ const ButtonContent: React.FC<ButtonContentProps> = (props) => {
return (
<div
key={moduleId}
className="flex max-w-full items-center gap-1 rounded bg-custom-background-80 px-1.5 py-1 text-custom-text-200"
className="flex max-w-full items-center gap-1 rounded bg-custom-background-80 py-1 text-custom-text-200"
>
{!hideIcon && <DiceIcon className="h-2.5 w-2.5 flex-shrink-0" />}
{!hideText && (

View file

@ -2,6 +2,7 @@ import { observer } from "mobx-react";
import { Expand, Shrink } from "lucide-react";
// hooks
// helpers
import { Row } from "@plane/ui";
import { VIEWS_LIST } from "@/components/gantt-chart/data";
import { cn } from "@/helpers/common.helper";
// types
@ -26,7 +27,7 @@ export const GanttChartHeader: React.FC<Props> = observer((props) => {
const { currentView } = useGanttChart();
return (
<div className="relative flex w-full flex-shrink-0 flex-wrap items-center gap-2 whitespace-nowrap px-2.5 py-2">
<Row className="relative flex w-full flex-shrink-0 flex-wrap items-center gap-2 whitespace-nowrap py-2">
<div className="ml-auto">
<div className="ml-auto text-sm font-medium">
{blockIds ? `${blockIds.length} ${loaderTitle}` : "Loading..."}
@ -65,6 +66,6 @@ export const GanttChartHeader: React.FC<Props> = observer((props) => {
>
{fullScreenMode ? <Shrink className="h-4 w-4" /> : <Expand className="h-4 w-4" />}
</button>
</div>
</Row>
);
});

View file

@ -33,7 +33,7 @@ export const CyclesSidebarBlock: React.FC<Props> = observer((props) => {
>
<div
id={`sidebar-block-${block.id}`}
className={cn("group w-full flex items-center gap-2 pl-2 pr-4", {
className={cn("group w-full flex items-center gap-2 pr-4", {
"bg-custom-background-90": isBlockActive(block.id),
})}
style={{

View file

@ -1,5 +1,6 @@
import { observer } from "mobx-react";
// components
import { Row } from "@plane/ui";
import { MultipleSelectEntityAction } from "@/components/core";
import { useGanttChart } from "@/components/gantt-chart/hooks";
import { IssueGanttSidebarBlock } from "@/components/issues";
@ -45,8 +46,8 @@ export const IssuesSidebarBlock = observer((props: Props) => {
onMouseEnter={() => updateActiveBlockId(block.id)}
onMouseLeave={() => updateActiveBlockId(null)}
>
<div
className={cn("group w-full flex items-center gap-2 pl-2 pr-4", {
<Row
className={cn("group w-full flex items-center gap-2 pr-4", {
"bg-custom-background-90": isBlockHoveredOn,
"bg-custom-primary-100/5 hover:bg-custom-primary-100/10": isIssueSelected,
"bg-custom-primary-100/10": isIssueSelected && isBlockHoveredOn,
@ -55,8 +56,8 @@ export const IssuesSidebarBlock = observer((props: Props) => {
height: `${BLOCK_HEIGHT}px`,
}}
>
<div className="flex items-center gap-2">
{enableSelection && selectionHelpers && (
{enableSelection && selectionHelpers && (
<div className="flex items-center gap-2 absolute left-1">
<MultipleSelectEntityAction
className={cn(
"opacity-0 pointer-events-none group-hover/list-block:opacity-100 group-hover/list-block:pointer-events-auto transition-opacity",
@ -68,8 +69,8 @@ export const IssuesSidebarBlock = observer((props: Props) => {
id={block.id}
selectionHelpers={selectionHelpers}
/>
)}
</div>
</div>
)}
<div className="flex h-full flex-grow items-center justify-between gap-2 truncate">
<div className="flex-grow truncate">
<IssueGanttSidebarBlock issueId={block.data.id} />
@ -82,7 +83,7 @@ export const IssuesSidebarBlock = observer((props: Props) => {
</div>
)}
</div>
</div>
</Row>
</div>
);
});

View file

@ -1,5 +1,6 @@
import { observer } from "mobx-react";
// hooks
import { Row } from "@plane/ui";
import { BLOCK_HEIGHT } from "@/components/gantt-chart/constants";
import { useGanttChart } from "@/components/gantt-chart/hooks";
// components
@ -31,9 +32,9 @@ export const ModulesSidebarBlock: React.FC<Props> = observer((props) => {
onMouseEnter={() => updateActiveBlockId(block.id)}
onMouseLeave={() => updateActiveBlockId(null)}
>
<div
<Row
id={`sidebar-block-${block.id}`}
className={cn("group w-full flex items-center gap-2 pl-2 pr-4", {
className={cn("group w-full flex items-center gap-2 pr-4", {
"bg-custom-background-90": isBlockActive(block.id),
})}
style={{
@ -50,7 +51,7 @@ export const ModulesSidebarBlock: React.FC<Props> = observer((props) => {
</div>
)}
</div>
</div>
</Row>
</div>
);
});

View file

@ -1,6 +1,7 @@
import { RefObject } from "react";
import { observer } from "mobx-react";
// components
import { Row, ERowVariant } from "@plane/ui";
import { MultipleSelectGroupAction } from "@/components/core";
import { ChartDataType, IBlockUpdateData, IGanttBlock } from "@/components/gantt-chart";
// helpers
@ -44,27 +45,24 @@ export const GanttChartSidebar: React.FC<Props> = observer((props) => {
const isGroupSelectionEmpty = selectionHelpers.isGroupSelected(GANTT_SELECT_GROUP) === "empty";
return (
<div
<Row
// DO NOT REMOVE THE ID
id="gantt-sidebar"
className="sticky left-0 z-10 min-h-full h-max flex-shrink-0 border-r-[0.5px] border-custom-border-200 bg-custom-background-100"
style={{
width: `${SIDEBAR_WIDTH}px`,
}}
variant={ERowVariant.HUGGING}
>
<div
className="group/list-header box-border flex-shrink-0 flex items-end justify-between gap-2 border-b-[0.5px] border-custom-border-200 pb-2 pl-2 pr-4 text-sm font-medium text-custom-text-300 sticky top-0 z-10 bg-custom-background-100"
<Row
className="group/list-header box-border flex-shrink-0 flex items-end justify-between gap-2 border-b-[0.5px] border-custom-border-200 pb-2 pr-4 text-sm font-medium text-custom-text-300 sticky top-0 z-10 bg-custom-background-100"
style={{
height: `${HEADER_HEIGHT}px`,
}}
>
<div
className={cn("flex items-center gap-2", {
"pl-2": !enableSelection,
})}
>
<div className={cn("flex items-center gap-2")}>
{enableSelection && (
<div className="flex-shrink-0 flex items-center w-3.5">
<div className="flex-shrink-0 flex items-center w-3.5 absolute left-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",
@ -80,9 +78,9 @@ export const GanttChartSidebar: React.FC<Props> = observer((props) => {
<h6>{title}</h6>
</div>
<h6>Duration</h6>
</div>
</Row>
<div className="min-h-full h-max bg-custom-background-100 overflow-hidden">
<Row variant={ERowVariant.HUGGING} className="min-h-full h-max bg-custom-background-100 overflow-hidden">
{sidebarToRender &&
sidebarToRender({
title,
@ -96,8 +94,8 @@ export const GanttChartSidebar: React.FC<Props> = observer((props) => {
loadMoreBlocks,
selectionHelpers,
})}
</div>
</Row>
{quickAdd ? quickAdd : null}
</div>
</Row>
);
});

View file

@ -13,9 +13,9 @@ import {
Link,
Trash2,
MoveRight,
Copy
Copy,
} from "lucide-react";
import { Button, ControlLink, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
import { Button, ControlLink, CustomMenu, Row, TOAST_TYPE, setToast } from "@plane/ui";
// components
import {
DeclineIssueModal,
@ -245,7 +245,7 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
/>
</>
<div className="hidden relative lg:flex h-full w-full items-center justify-between gap-2 px-4">
<Row className="hidden relative lg:flex h-full w-full items-center justify-between gap-2">
<div className="flex items-center gap-4">
{isNotificationEmbed && (
<button onClick={embedRemoveCurrentNotification}>
@ -376,7 +376,7 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
)}
</div>
</div>
</div>
</Row>
<div className="lg:hidden">
<InboxIssueActionsMobileHeader

View file

@ -15,7 +15,7 @@ import {
PanelLeft,
MoveRight,
} from "lucide-react";
import { CustomHeader, CustomMenu, EHeaderVariant } from "@plane/ui";
import { Header, CustomMenu, EHeaderVariant } from "@plane/ui";
// components
import { InboxIssueStatus } from "@/components/inbox";
import { IssueUpdateStatus } from "@/components/issues";
@ -80,7 +80,7 @@ export const InboxIssueActionsMobileHeader: React.FC<Props> = observer((props) =
if (!issue || !inboxIssue) return null;
return (
<CustomHeader variant={EHeaderVariant.SECONDARY} className="flex">
<Header variant={EHeaderVariant.SECONDARY} className="justify-start">
{isNotificationEmbed && (
<button onClick={embedRemoveCurrentNotification}>
<MoveRight className="h-4 w-4 text-custom-text-300 hover:text-custom-text-200" />
@ -181,6 +181,6 @@ export const InboxIssueActionsMobileHeader: React.FC<Props> = observer((props) =
</CustomMenu>
</div>
</div>
</CustomHeader>
</Header>
);
});

View file

@ -35,8 +35,8 @@ export const InboxIssueContentProperties: React.FC<Props> = observer((props) =>
if (!issue || !issue?.id) return <></>;
return (
<div className="flex h-min w-full flex-col divide-y-2 divide-custom-border-200 overflow-hidden">
<div className="h-min w-full overflow-y-auto px-3">
<div className="flex w-full flex-col divide-y-2 divide-custom-border-200">
<div className="w-full overflow-y-auto">
<h5 className="text-sm font-medium my-4">Properties</h5>
<div className={`divide-y-2 divide-custom-border-200 ${!isEditable ? "opacity-60" : ""}`}>
<div className="flex flex-col gap-3">

View file

@ -100,7 +100,7 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
return (
<>
<div className="rounded-lg space-y-4 pl-3">
<div className="rounded-lg space-y-4">
<IssueTitleInput
workspaceSlug={workspaceSlug}
projectId={issue.project_id}
@ -141,14 +141,12 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
)}
</div>
<div className="pl-3">
<IssueAttachmentRoot
workspaceSlug={workspaceSlug}
projectId={projectId}
issueId={issue.id}
disabled={!isEditable}
/>
</div>
<IssueAttachmentRoot
workspaceSlug={workspaceSlug}
projectId={projectId}
issueId={issue.id}
disabled={!isEditable}
/>
<InboxIssueContentProperties
workspaceSlug={workspaceSlug}
@ -159,9 +157,7 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
duplicateIssueDetails={inboxIssue?.duplicate_issue_detail}
/>
<div className="pb-12 pl-3">
<IssueActivity workspaceSlug={workspaceSlug} projectId={projectId} issueId={issue.id} isIntakeIssue />
</div>
<IssueActivity workspaceSlug={workspaceSlug} projectId={projectId} issueId={issue.id} isIntakeIssue />
</>
);
});

View file

@ -2,6 +2,7 @@ import { FC, useEffect, useState } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
// components
import { ContentWrapper } from "@plane/ui";
import { InboxIssueActionsHeader, InboxIssueMainContent } from "@/components/inbox";
// constants
import { EUserProjectRoles } from "@/constants/project";
@ -83,7 +84,7 @@ export const InboxContentRoot: FC<TInboxContentRoot> = observer((props) => {
embedRemoveCurrentNotification={embedRemoveCurrentNotification}
/>
</div>
<div className="h-full w-full space-y-5 divide-y-2 divide-custom-border-200 overflow-y-auto px-6 py-5 vertical-scrollbar scrollbar-md">
<ContentWrapper className="space-y-5 divide-y-2 divide-custom-border-200">
<InboxIssueMainContent
workspaceSlug={workspaceSlug}
projectId={projectId}
@ -92,7 +93,7 @@ export const InboxContentRoot: FC<TInboxContentRoot> = observer((props) => {
isSubmitting={isSubmitting}
setIsSubmitting={setIsSubmitting}
/>
</div>
</ContentWrapper>
</div>
</>
);

View file

@ -3,6 +3,7 @@ import { observer } from "mobx-react";
import { X } from "lucide-react";
import { TInboxIssueFilterDateKeys } from "@plane/types";
// helpers
import { Tag } from "@plane/ui";
import { renderFormattedDate } from "@/helpers/date-time.helper";
// constants
import { PAST_DURATION_FILTER_OPTIONS } from "@/helpers/inbox.helper";
@ -37,7 +38,7 @@ export const InboxIssueAppliedFiltersDate: FC<InboxIssueAppliedFiltersDate> = ob
if (filteredValues.length === 0) return <></>;
return (
<div className="relative flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1">
<Tag>
<div className="text-xs text-custom-text-200">{label}</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@ -61,6 +62,6 @@ export const InboxIssueAppliedFiltersDate: FC<InboxIssueAppliedFiltersDate> = ob
>
<X className={`w-3 h-3`} />
</div>
</div>
</Tag>
);
});

View file

@ -2,6 +2,7 @@ import { FC } from "react";
import { observer } from "mobx-react";
import { X } from "lucide-react";
// hooks
import { Tag } from "@plane/ui";
import { useLabel, useProjectInbox } from "@/hooks/store";
const LabelIcons = ({ color }: { color: string }) => (
@ -23,7 +24,7 @@ export const InboxIssueAppliedFiltersLabel: FC = observer(() => {
if (filteredValues.length === 0) return <></>;
return (
<div className="relative flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1">
<Tag>
<div className="text-xs text-custom-text-200">Label</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@ -50,6 +51,6 @@ export const InboxIssueAppliedFiltersLabel: FC = observer(() => {
>
<X className={`w-3 h-3`} />
</div>
</div>
</Tag>
);
});

View file

@ -4,7 +4,7 @@ import { FC } from "react";
import { observer } from "mobx-react";
import { X } from "lucide-react";
import { TInboxIssueFilterMemberKeys } from "@plane/types";
import { Avatar } from "@plane/ui";
import { Avatar, Tag } from "@plane/ui";
// hooks
import { useMember, useProjectInbox } from "@/hooks/store";
@ -29,7 +29,7 @@ export const InboxIssueAppliedFiltersMember: FC<InboxIssueAppliedFiltersMember>
if (filteredValues.length === 0) return <></>;
return (
<div className="relative flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1">
<Tag>
<div className="text-xs text-custom-text-200">{label}</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@ -56,6 +56,6 @@ export const InboxIssueAppliedFiltersMember: FC<InboxIssueAppliedFiltersMember>
>
<X className={`w-3 h-3`} />
</div>
</div>
</Tag>
);
});

View file

@ -4,7 +4,7 @@ import { FC } from "react";
import { observer } from "mobx-react";
import { X } from "lucide-react";
import { TIssuePriorities } from "@plane/types";
import { PriorityIcon } from "@plane/ui";
import { PriorityIcon, Tag } from "@plane/ui";
// constants
import { ISSUE_PRIORITIES } from "@/constants/issue";
// hooks
@ -25,7 +25,7 @@ export const InboxIssueAppliedFiltersPriority: FC = observer(() => {
if (filteredValues.length === 0) return <></>;
return (
<div className="relative flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1">
<Tag>
<div className="text-xs text-custom-text-200">Priority</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@ -52,6 +52,6 @@ export const InboxIssueAppliedFiltersPriority: FC = observer(() => {
>
<X className={`w-3 h-3`} />
</div>
</div>
</Tag>
);
});

View file

@ -1,7 +1,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import {
InboxIssueAppliedFiltersStatus,
InboxIssueAppliedFiltersPriority,
@ -18,7 +18,7 @@ export const InboxIssueAppliedFilters: FC = observer(() => {
if (getAppliedFiltersCount === 0) return <></>;
return (
<CustomHeader variant={EHeaderVariant.TERNARY} className="flex-wrap items-center gap-1 min-h-none">
<Header variant={EHeaderVariant.TERNARY}>
{/* status */}
<InboxIssueAppliedFiltersStatus />
{/* state */}
@ -35,6 +35,6 @@ export const InboxIssueAppliedFilters: FC = observer(() => {
<InboxIssueAppliedFiltersDate filterKey="created_at" label="Created date" />
{/* updated_at */}
<InboxIssueAppliedFiltersDate filterKey="updated_at" label="Updated date" />
</CustomHeader>
</Header>
);
});

View file

@ -3,7 +3,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { X } from "lucide-react";
import { StateGroupIcon } from "@plane/ui";
import { StateGroupIcon, Tag } from "@plane/ui";
// hooks
import { useProjectInbox, useProjectState } from "@/hooks/store";
@ -22,7 +22,7 @@ export const InboxIssueAppliedFiltersState: FC = observer(() => {
if (filteredValues.length === 0) return <></>;
return (
<div className="relative flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1">
<Tag>
<div className="text-xs text-custom-text-200">State</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@ -49,6 +49,6 @@ export const InboxIssueAppliedFiltersState: FC = observer(() => {
>
<X className={`w-3 h-3`} />
</div>
</div>
</Tag>
);
});

View file

@ -3,6 +3,7 @@ import { observer } from "mobx-react";
import { X } from "lucide-react";
import { TInboxIssueStatus } from "@plane/types";
// constants
import { Tag } from "@plane/ui";
import { INBOX_STATUS } from "@/constants/inbox";
// hooks
import { useProjectInbox } from "@/hooks/store";
@ -19,7 +20,7 @@ export const InboxIssueAppliedFiltersStatus: FC = observer(() => {
if (filteredValues.length === 0) return <></>;
return (
<div className="relative flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1">
<Tag>
<div className="text-xs text-custom-text-200">Status</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@ -41,6 +42,6 @@ export const InboxIssueAppliedFiltersStatus: FC = observer(() => {
</div>
);
})}
</div>
</Tag>
);
});

View file

@ -4,7 +4,7 @@ import { FC, MouseEvent } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { Tooltip, PriorityIcon } from "@plane/ui";
import { Tooltip, PriorityIcon, Row } from "@plane/ui";
// components
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import { InboxIssueStatus } from "@/components/inbox";
@ -53,9 +53,9 @@ export const InboxIssueListItem: FC<InboxIssueListItemProps> = observer((props)
href={`/${workspaceSlug}/projects/${projectId}/inbox?currentTab=${currentTab}&inboxIssueId=${issue.id}`}
onClick={(e) => handleIssueRedirection(e, issue.id)}
>
<div
<Row
className={cn(
`flex flex-col gap-2 relative border border-t-transparent border-l-transparent border-r-transparent border-b-custom-border-200 p-4 hover:bg-custom-primary/5 cursor-pointer transition-all`,
`flex flex-col gap-2 relative border border-t-transparent border-l-transparent border-r-transparent border-b-custom-border-200 py-4 hover:bg-custom-primary/5 cursor-pointer transition-all`,
{ "border-custom-primary-100 border": selectedInboxIssueId === issue.id }
)}
>
@ -118,7 +118,7 @@ export const InboxIssueListItem: FC<InboxIssueListItemProps> = observer((props)
{/* created by */}
{createdByDetails && <ButtonAvatars showTooltip={false} userIds={createdByDetails?.id} />}
</div>
</div>
</Row>
</Link>
</>
);

View file

@ -3,7 +3,7 @@
import { FC, useCallback, useEffect, useRef, useState } from "react";
import { observer } from "mobx-react";
import { TInboxIssueCurrentTab } from "@plane/types";
import { CustomHeader, Loader, EHeaderVariant } from "@plane/ui";
import { Header, Loader, EHeaderVariant } from "@plane/ui";
// components
import { EmptyState } from "@/components/empty-state";
import { FiltersRoot, InboxIssueAppliedFilters, InboxIssueList } from "@/components/inbox";
@ -76,7 +76,7 @@ export const InboxSidebar: FC<IInboxSidebarProps> = observer((props) => {
return (
<div className="bg-custom-background-100 flex-shrink-0 w-full h-full border-r border-custom-border-300 ">
<div className="relative w-full h-full flex flex-col overflow-hidden">
<CustomHeader variant={EHeaderVariant.SECONDARY} className="flex">
<Header variant={EHeaderVariant.SECONDARY}>
{tabNavigationOptions.map((option) => (
<div
key={option?.key}
@ -108,7 +108,7 @@ export const InboxSidebar: FC<IInboxSidebarProps> = observer((props) => {
<div className="m-auto mr-0">
<FiltersRoot />
</div>
</CustomHeader>
</Header>
<InboxIssueAppliedFilters />
{loader != undefined && loader === "filter-loading" && !inboxIssuePaginationInfo?.next_page_results ? (

View file

@ -8,6 +8,7 @@ import {
IIssueFilterOptions,
TIssueKanbanFilters,
} from "@plane/types";
import { Row } from "@plane/ui";
import { CalendarMonthsDropdown, CalendarOptionsDropdown } from "@/components/issues";
// icons
import { EIssueFilterType } from "@/constants/issue";
@ -96,7 +97,7 @@ export const CalendarHeader: React.FC<ICalendarHeader> = observer((props) => {
};
return (
<div className="mb-4 flex items-center justify-between gap-2 px-3">
<Row className="mb-4 flex items-center justify-between gap-2">
<div className="flex items-center gap-1.5">
<button type="button" className="grid place-items-center" onClick={handlePrevious}>
<ChevronLeft size={16} strokeWidth={2} />
@ -116,6 +117,6 @@ export const CalendarHeader: React.FC<ICalendarHeader> = observer((props) => {
</button>
<CalendarOptionsDropdown issuesFilterStore={issuesFilterStore} updateFilters={updateFilters} />
</div>
</div>
</Row>
);
});

View file

@ -3,6 +3,7 @@ import { X } from "lucide-react";
// types
import { IIssueFilterOptions, IIssueLabel, IState } from "@plane/types";
// components
import { Tag } from "@plane/ui";
import {
AppliedCycleFilters,
AppliedDateFilters,
@ -67,100 +68,90 @@ export const AppliedFiltersList: React.FC<Props> = observer((props) => {
if (Array.isArray(value) && value.length === 0) return;
return (
<div
key={filterKey}
className="flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1 capitalize truncate"
>
<div className="flex flex-wrap items-center gap-1.5 truncate">
<span className="text-xs text-custom-text-300">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{membersFilters.includes(filterKey) && (
<AppliedMembersFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter(filterKey, val)}
values={value}
/>
)}
{dateFilters.includes(filterKey) && (
<AppliedDateFilters handleRemove={(val) => handleRemoveFilter(filterKey, val)} values={value} />
)}
{filterKey === "labels" && (
<AppliedLabelsFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("labels", val)}
labels={labels}
values={value}
/>
)}
{filterKey === "priority" && (
<AppliedPriorityFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("priority", val)}
values={value}
/>
)}
{filterKey === "state" && states && (
<AppliedStateFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("state", val)}
states={states}
values={value}
/>
)}
{filterKey === "state_group" && (
<AppliedStateGroupFilters
handleRemove={(val) => handleRemoveFilter("state_group", val)}
values={value}
/>
)}
{filterKey === "project" && (
<AppliedProjectFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("project", val)}
values={value}
/>
)}
{filterKey === "cycle" && (
<AppliedCycleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("cycle", val)}
values={value}
/>
)}
{filterKey === "module" && (
<AppliedModuleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("module", val)}
values={value}
/>
)}
{filterKey === "issue_type" && (
<AppliedIssueTypeFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("issue_type", val)}
values={value}
/>
)}
{isEditingAllowed && (
<button
type="button"
className="grid place-items-center text-custom-text-300 hover:text-custom-text-200"
onClick={() => handleRemoveFilter(filterKey, null)}
>
<X size={12} strokeWidth={2} />
</button>
)}
</div>
</div>
<Tag key={filterKey}>
<span className="text-xs text-custom-text-300">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{membersFilters.includes(filterKey) && (
<AppliedMembersFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter(filterKey, val)}
values={value}
/>
)}
{dateFilters.includes(filterKey) && (
<AppliedDateFilters handleRemove={(val) => handleRemoveFilter(filterKey, val)} values={value} />
)}
{filterKey === "labels" && (
<AppliedLabelsFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("labels", val)}
labels={labels}
values={value}
/>
)}
{filterKey === "priority" && (
<AppliedPriorityFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("priority", val)}
values={value}
/>
)}
{filterKey === "state" && states && (
<AppliedStateFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("state", val)}
states={states}
values={value}
/>
)}
{filterKey === "state_group" && (
<AppliedStateGroupFilters handleRemove={(val) => handleRemoveFilter("state_group", val)} values={value} />
)}
{filterKey === "project" && (
<AppliedProjectFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("project", val)}
values={value}
/>
)}
{filterKey === "cycle" && (
<AppliedCycleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("cycle", val)}
values={value}
/>
)}
{filterKey === "module" && (
<AppliedModuleFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("module", val)}
values={value}
/>
)}
{filterKey === "issue_type" && (
<AppliedIssueTypeFilters
editable={isEditingAllowed}
handleRemove={(val) => handleRemoveFilter("issue_type", val)}
values={value}
/>
)}
{isEditingAllowed && (
<button
type="button"
className="grid place-items-center text-custom-text-300 hover:text-custom-text-200"
onClick={() => handleRemoveFilter(filterKey, null)}
>
<X size={12} strokeWidth={2} />
</button>
)}
</Tag>
);
})}
{isEditingAllowed && (
<button
type="button"
onClick={handleClearAllFilters}
className="flex items-center gap-2 flex-shrink-0 rounded-md border border-custom-border-200 px-2 py-1 text-xs text-custom-text-300 hover:text-custom-text-200"
>
Clear all
<X size={12} strokeWidth={2} />
<button type="button" onClick={handleClearAllFilters}>
<Tag>
Clear all
<X size={12} strokeWidth={2} />
</Tag>
</button>
)}
</div>

View file

@ -29,7 +29,7 @@ export const AppliedMembersFilters: React.FC<Props> = observer((props) => {
return (
<div key={memberId} className="flex items-center gap-1 rounded bg-custom-background-80 p-1 text-xs">
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} />
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} size={"sm"} />
<span className="normal-case">{memberDetails.display_name}</span>
{editable && (
<button

View file

@ -2,7 +2,7 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { IIssueFilterOptions } from "@plane/types";
// hooks
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
@ -77,8 +77,8 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
if (Object.keys(appliedFilters).length === 0 || !workspaceSlug || !projectId || !cycleId) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<CustomHeader.LeftItem>
<Header variant={EHeaderVariant.TERNARY}>
<Header.LeftItem>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
@ -86,7 +86,7 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
labels={projectLabels ?? []}
states={projectStates}
/>
</CustomHeader.LeftItem>
</Header.LeftItem>
<SaveFilterView
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
@ -96,6 +96,6 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
display_properties: issueFilters?.displayProperties,
}}
/>
</CustomHeader>
</Header>
);
});

View file

@ -9,7 +9,7 @@ import { useParams } from "next/navigation";
import { IIssueFilterOptions, TStaticViewTypes } from "@plane/types";
//ui
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList } from "@/components/issues";
import { UpdateViewComponent } from "@/components/views/update-view-component";
import { CreateUpdateWorkspaceViewModal } from "@/components/workspace";
@ -133,7 +133,7 @@ export const GlobalViewsAppliedFiltersRoot = observer((props: Props) => {
if (areAppliedFiltersEmpty && areFiltersEqual) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<Header variant={EHeaderVariant.TERNARY}>
<CreateUpdateWorkspaceViewModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
@ -166,6 +166,6 @@ export const GlobalViewsAppliedFiltersRoot = observer((props: Props) => {
) : (
<></>
)}
</CustomHeader>
</Header>
);
});

View file

@ -2,7 +2,7 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { IIssueFilterOptions } from "@plane/types";
// hooks
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
@ -76,8 +76,8 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
if (!workspaceSlug || !projectId || !moduleId || Object.keys(appliedFilters).length === 0) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<CustomHeader.LeftItem>
<Header variant={EHeaderVariant.TERNARY}>
<Header.LeftItem>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
@ -85,7 +85,7 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
labels={projectLabels ?? []}
states={projectStates}
/>
</CustomHeader.LeftItem>
</Header.LeftItem>
<SaveFilterView
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
@ -95,6 +95,6 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
display_properties: issueFilters?.displayProperties,
}}
/>
</CustomHeader>
</Header>
);
});

View file

@ -3,7 +3,7 @@ import { useParams } from "next/navigation";
import { IIssueFilterOptions } from "@plane/types";
// hooks
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
// constants
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
@ -68,25 +68,29 @@ export const ProjectAppliedFiltersRoot: React.FC = observer(() => {
if (Object.keys(appliedFilters).length === 0) return null;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
labels={projectLabels ?? []}
states={projectStates}
/>
{isEditingAllowed && (
<SaveFilterView
workspaceSlug={workspaceSlug}
projectId={projectId}
filterParams={{
filters: appliedFilters,
display_filters: issueFilters?.displayFilters,
display_properties: issueFilters?.displayProperties,
}}
<Header variant={EHeaderVariant.TERNARY}>
<Header.LeftItem>
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
labels={projectLabels ?? []}
states={projectStates}
/>
)}
</CustomHeader>
</Header.LeftItem>
<Header.RightItem>
{isEditingAllowed && (
<SaveFilterView
workspaceSlug={workspaceSlug}
projectId={projectId}
filterParams={{
filters: appliedFilters,
display_filters: issueFilters?.displayFilters,
display_properties: issueFilters?.displayProperties,
}}
/>
)}
</Header.RightItem>
</Header>
);
});

View file

@ -8,7 +8,7 @@ import { useParams } from "next/navigation";
// types
import { IIssueFilterOptions } from "@plane/types";
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { AppliedFiltersList } from "@/components/issues";
import { CreateUpdateProjectViewModal } from "@/components/views";
import { UpdateViewComponent } from "@/components/views/update-view-component";
@ -114,7 +114,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
const isOwner = viewDetails?.owned_by === data?.id;
return (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<Header variant={EHeaderVariant.TERNARY}>
<CreateUpdateProjectViewModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
@ -128,7 +128,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
...viewFilters,
}}
/>
<CustomHeader.LeftItem>
<Header.LeftItem className="w-[70%]">
<AppliedFiltersList
appliedFilters={appliedFilters ?? {}}
handleClearAllFilters={handleClearAllFilters}
@ -137,15 +137,17 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
states={projectStates}
disableEditing={isLocked}
/>
</CustomHeader.LeftItem>
<UpdateViewComponent
isLocked={isLocked}
areFiltersEqual={!!areFiltersEqual}
isOwner={isOwner}
isAuthorizedUser={isAuthorizedUser}
setIsModalOpen={setIsModalOpen}
handleUpdateView={handleUpdateView}
/>
</CustomHeader>
</Header.LeftItem>
<Header.RightItem>
<UpdateViewComponent
isLocked={isLocked}
areFiltersEqual={!!areFiltersEqual}
isOwner={isOwner}
isAuthorizedUser={isAuthorizedUser}
setIsModalOpen={setIsModalOpen}
handleUpdateView={handleUpdateView}
/>
</Header.RightItem>
</Header>
);
});

View file

@ -192,7 +192,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
<DropIndicator isVisible={!isCurrentBlockDragging && isDraggingOverBlock} />
<div
// make Z-index higher at the beginning of drag, to have a issue drag image of issue block without any overlaps
className={cn("group/kanban-block relative p-1.5", { "z-[1]": isCurrentBlockDragging })}
className={cn("group/kanban-block relative mb-2", { "z-[1]": isCurrentBlockDragging })}
onDragStart={() => {
if (isDragAllowed) setIsCurrentBlockDragging(true);
else

View file

@ -14,6 +14,7 @@ import {
} from "@plane/types";
// constants
// hooks
import { ContentWrapper } from "@plane/ui";
import { useCycle, useKanbanView, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store";
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
// types
@ -134,7 +135,7 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
const isGroupByCreatedBy = group_by === "created_by";
return (
<div className={`relative w-full flex gap-2 px-2 ${sub_group_by ? "h-full" : "h-full"}`}>
<ContentWrapper className={`flex-row relative gap-4`}>
{list &&
list.length > 0 &&
list.map((subList: IGroupByColumn) => {
@ -149,7 +150,7 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
} `}
>
{sub_group_by === null && (
<div className="sticky top-0 z-[2] w-full flex-shrink-0 bg-custom-background-90 py-1">
<div className="sticky top-0 z-[2] w-full flex-shrink-0 bg-custom-background-90 py-1 mb-1">
<HeaderGroupByCard
sub_group_by={sub_group_by}
group_by={group_by}
@ -193,6 +194,6 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
</div>
);
})}
</div>
</ContentWrapper>
);
});

View file

@ -103,11 +103,11 @@ export const HeaderGroupByCard: FC<IHeaderGroupByCard> = observer((props) => {
/>
)}
<div
className={`relative flex flex-shrink-0 gap-2 p-1.5 ${
className={`relative flex flex-shrink-0 gap-2 py-1.5 ${
verticalAlignPosition ? `w-[44px] flex-col items-center` : `w-full flex-row items-center`
}`}
>
<div className="flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center overflow-hidden rounded-sm">
<div className="flex h-[20px] flex-shrink-0 items-center justify-center overflow-hidden rounded-sm">
{icon ? icon : <Circle width={14} strokeWidth={2} />}
</div>

View file

@ -217,8 +217,8 @@ export const KanbanGroup = observer((props: IKanbanGroup) => {
const isSubGroup = !!sub_group_id && sub_group_id !== "null";
const issueIds = isSubGroup
? (groupedIssueIds as TSubGroupedIssues)?.[groupId]?.[sub_group_id] ?? []
: (groupedIssueIds as TGroupedIssues)?.[groupId] ?? [];
? ((groupedIssueIds as TSubGroupedIssues)?.[groupId]?.[sub_group_id] ?? [])
: ((groupedIssueIds as TGroupedIssues)?.[groupId] ?? []);
const groupIssueCount = getGroupIssueCount(groupId, sub_group_id, false) ?? 0;

View file

@ -9,7 +9,7 @@ import { ChevronRight } from "lucide-react";
// types
import { TIssue, IIssueDisplayProperties, TIssueMap } from "@plane/types";
// ui
import { Spinner, Tooltip, ControlLink, setToast, TOAST_TYPE } from "@plane/ui";
import { Spinner, Tooltip, ControlLink, setToast, TOAST_TYPE, Row } from "@plane/ui";
// components
import { MultipleSelectEntityAction } from "@/components/core";
import { IssueProperties } from "@/components/issues/issue-layouts/properties";
@ -130,13 +130,13 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
};
//TODO: add better logic. This is to have a min width for ID/Key based on the length of project identifier
const keyMinWidth = ((projectIdentifier?.length ?? 0) + 5) * 7;
const keyMinWidth = (projectIdentifier?.length ?? 0) * 7;
return (
<div
<Row
ref={issueRef}
className={cn(
"group/list-block min-h-11 relative flex flex-col gap-3 bg-custom-background-100 hover:bg-custom-background-90 p-3 pl-1.5 text-sm transition-colors border border-transparent",
"group/list-block min-h-11 relative flex flex-col gap-3 bg-custom-background-100 hover:bg-custom-background-90 py-3 text-sm transition-colors border border-transparent",
{
"border-custom-primary-70": getIsIssuePeeked(issue.id) && peekIssue?.nestingLevel === nestingLevel,
"border-custom-border-400": isIssueActive,
@ -173,7 +173,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
disabled={issue.project_id === projectId}
renderByDefault={false}
>
<div className="flex-shrink-0 grid place-items-center w-3.5">
<div className="flex-shrink-0 grid place-items-center w-3.5 absolute left-1">
<MultipleSelectEntityAction
className={cn(
"opacity-0 pointer-events-none group-hover/list-block:opacity-100 group-hover/list-block:pointer-events-auto transition-opacity",
@ -190,7 +190,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
</Tooltip>
)}
{displayProperties && displayProperties?.key && (
<div className="flex-shrink-0 pl-2" style={{ minWidth: `${keyMinWidth}px` }}>
<div className="flex-shrink-0" style={{ minWidth: `${keyMinWidth}px` }}>
{issue.project_id && (
<IssueIdentifier
issueId={issueId}
@ -293,6 +293,6 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
</div>
)}
</div>
</div>
</Row>
);
});

View file

@ -86,12 +86,12 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => {
return (
<>
<div className="group/list-header relative w-full flex-shrink-0 flex items-center gap-2 py-1.5">
<div className="group/list-header w-full flex-shrink-0 flex items-center gap-2 py-1.5">
{canSelectIssues && (
<div className="flex-shrink-0 flex items-center w-3.5">
<div className="flex-shrink-0 flex items-center w-3.5 absolute left-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",
"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,
}
@ -106,8 +106,10 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => {
{icon ?? <CircleDashed className="size-3.5" strokeWidth={2} />}
</div>
<div className="relative flex w-full flex-row items-center gap-1 overflow-hidden cursor-pointer"
onClick={toggleListGroup}>
<div
className="relative flex w-full flex-row items-center gap-1 overflow-hidden cursor-pointer"
onClick={toggleListGroup}
>
<div className="inline-block line-clamp-1 truncate font-medium text-custom-text-100">{title}</div>
<div className="pl-2 text-sm font-medium text-custom-text-300">{count || 0}</div>
</div>

View file

@ -14,7 +14,7 @@ import {
TIssue,
IIssueDisplayProperties,
} from "@plane/types";
import { setToast, TOAST_TYPE } from "@plane/ui";
import { Row, setToast, TOAST_TYPE } from "@plane/ui";
// components
import { ListLoaderItemRow } from "@/components/ui";
// constants
@ -230,7 +230,7 @@ export const ListGroup = observer((props: Props) => {
"border-custom-error-200": isDraggingOverColumn && !!group.isDropDisabled,
})}
>
<div className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 pl-2 pr-3 py-1">
<Row className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 pr-3 py-1">
<HeaderGroupByCard
groupID={group.id}
icon={group.icon}
@ -243,7 +243,7 @@ export const ListGroup = observer((props: Props) => {
selectionHelpers={selectionHelpers}
toggleListGroup={toggleListGroup}
/>
</div>
</Row>
{shouldExpand && (
<div className="relative">
<GroupDragOverlay

View file

@ -33,6 +33,7 @@ export interface IIssuePropertyLabels {
placeholderText?: string;
onClose?: () => void;
renderByDefault?: boolean;
fullWidth?: boolean;
}
export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((props) => {
@ -52,6 +53,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
noLabelBorder = false,
placeholderText,
renderByDefault = true,
fullWidth = false,
} = props;
// router
const { workspaceSlug: routerWorkspaceSlug } = useParams();
@ -149,7 +151,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase()));
const label = (
<div className="flex h-5 w-full flex-wrap items-center gap-2 overflow-hidden">
<div className="flex h-full w-full flex-wrap items-center gap-2 overflow-hidden">
{value.length > 0 ? (
value.length <= maxRender ? (
<>
@ -168,7 +170,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
key={label?.id}
className={`flex overflow-hidden hover:bg-custom-background-80 ${
!disabled && "cursor-pointer"
} h-full max-w-full flex-shrink-0 items-center rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 text-xs`}
} h-full ${fullWidth && "w-full"} max-w-full flex-shrink-0 items-center rounded px-2.5 text-xs ${noLabelBorder ? "rounded-none" : "border-[0.5px] border-custom-border-300"}`}
>
<div className="flex max-w-full items-center gap-1.5 overflow-hidden text-custom-text-200">
<span
@ -185,9 +187,9 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
</>
) : (
<div
className={`flex h-full flex-shrink-0 items-center rounded border-[0.5px] border-custom-border-300 px-2.5 py-1 text-xs ${
className={`flex h-full ${fullWidth && "w-full"} flex-shrink-0 items-center rounded px-2.5 text-xs ${
disabled ? "cursor-not-allowed" : "cursor-pointer"
}`}
} ${noLabelBorder ? "rounded-none" : "border-[0.5px] border-custom-border-300"}`}
>
<Tooltip
isMobile={isMobile}
@ -215,8 +217,8 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
renderByDefault={false}
>
<div
className={`flex h-full items-center justify-center gap-2 rounded px-2.5 py-1 text-xs hover:bg-custom-background-80 ${
noLabelBorder ? "" : "border-[0.5px] border-custom-border-300"
className={`flex h-full ${fullWidth && "w-full"} items-center justify-center gap-2 rounded px-2.5 py-1 text-xs hover:bg-custom-background-80 ${
noLabelBorder ? "rounded-none" : "border-[0.5px] border-custom-border-300"
}`}
>
<Tags className="h-3.5 w-3.5" strokeWidth={2} />
@ -231,7 +233,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
<button
ref={setReferenceElement}
type="button"
className={`clickable flex w-full items-center justify-between gap-1 text-xs ${
className={`clickable flex w-full h-full items-center justify-between gap-1 text-xs ${fullWidth && "hover:bg-custom-background-80"} ${
disabled
? "cursor-not-allowed text-custom-text-200"
: value.length <= maxRender
@ -249,7 +251,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
<ComboDropDown
as="div"
ref={dropdownRef}
className={`w-auto max-w-full flex-shrink-0 text-left ${className}`}
className={`w-auto max-w-full h-full flex-shrink-0 text-left ${className}`}
value={value}
onChange={onChange}
disabled={disabled}
@ -261,7 +263,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
{isOpen && (
<Combobox.Options className="fixed z-10" static>
<div
className={`z-10 my-1 w-48 whitespace-nowrap rounded border border-custom-border-300 bg-custom-background-100 px-2 py-2.5 text-xs shadow-custom-shadow-rg focus:outline-none ${optionsClassName}`}
className={`z-10 my-1 w-48 h-auto whitespace-nowrap rounded border border-custom-border-300 bg-custom-background-100 px-2 py-2.5 text-xs shadow-custom-shadow-rg focus:outline-none ${optionsClassName}`}
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}

View file

@ -1,6 +1,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { PlusIcon } from "lucide-react";
import { Row } from "@plane/ui";
import { TQuickAddIssueButton } from "../root";
export const GanttQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
@ -9,11 +10,13 @@ export const GanttQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((prop
return (
<button
type="button"
className="sticky bottom-0 z-[1] flex w-full cursor-pointer items-center gap-2 border-t-[1px] border-custom-border-200 bg-custom-background-100 px-3 pt-2 text-custom-text-350 hover:text-custom-text-300"
className="sticky bottom-0 z-[1] flex w-full cursor-pointer items-center border-t-[1px] border-custom-border-200 bg-custom-background-100 text-custom-text-350 hover:text-custom-text-300"
onClick={onClick}
>
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
<span className="text-sm font-medium">New Issue</span>
<Row className="flex py-2 gap-2">
<PlusIcon className="h-3.5 w-3.5 stroke-2 my-auto" />
<span className="text-sm font-medium">New Issue</span>
</Row>
</button>
);
});

View file

@ -1,18 +1,19 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { PlusIcon } from "lucide-react";
import { Row } from "@plane/ui";
import { TQuickAddIssueButton } from "../root";
export const ListQuickAddIssueButton: FC<TQuickAddIssueButton> = observer((props) => {
const { onClick } = props;
return (
<div
className="flex w-full cursor-pointer items-center gap-2 px-2 py-3 text-custom-text-350 hover:text-custom-text-300"
<Row
className="flex w-full cursor-pointer items-center gap-2 py-3 text-custom-text-350 hover:text-custom-text-300"
onClick={onClick}
>
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
<span className="text-sm font-medium">New Issue</span>
</div>
</Row>
);
});

View file

@ -1,9 +1,10 @@
import React from "react"
import React from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import useSWR from "swr";
// mobx store
// components
import { Row, ERowVariant } from "@plane/ui";
import {
IssuePeekOverview,
ModuleAppliedFiltersRoot,
@ -62,9 +63,9 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
<IssuesStoreContext.Provider value={EIssuesStoreType.MODULE}>
<div className="relative flex h-full w-full flex-col overflow-hidden">
<ModuleAppliedFiltersRoot />
<div className="h-full w-full overflow-auto">
<Row variant={ERowVariant.HUGGING} className="h-full w-full overflow-auto">
<ModuleIssueLayout activeLayout={activeLayout} moduleId={moduleId?.toString()} />
</div>
</Row>
{/* peek overview */}
<IssuePeekOverview />
</div>

View file

@ -36,7 +36,7 @@ export const SpreadsheetAssigneeColumn: React.FC<Props> = observer((props: Props
buttonVariant={
issue?.assignee_ids && issue.assignee_ids.length > 1 ? "transparent-without-text" : "transparent-with-text"
}
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -2,6 +2,7 @@ import React from "react";
import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
import { Row } from "@plane/ui";
type Props = {
issue: TIssue;
@ -11,8 +12,8 @@ export const SpreadsheetAttachmentColumn: React.FC<Props> = observer((props) =>
const { issue } = props;
return (
<div className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
{issue?.attachment_count} {issue?.attachment_count === 1 ? "attachment" : "attachments"}
</div>
</Row>
);
});

View file

@ -3,6 +3,7 @@ import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
// helpers
import { Row } from "@plane/ui";
import { renderFormattedDate } from "@/helpers/date-time.helper";
type Props = {
@ -13,8 +14,8 @@ export const SpreadsheetCreatedOnColumn: React.FC<Props> = observer((props: Prop
const { issue } = props;
return (
<div className="flex h-11 w-full items-center justify-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
{renderFormattedDate(issue.created_at)}
</div>
</Row>
);
});

View file

@ -54,8 +54,8 @@ export const SpreadsheetCycleColumn: React.FC<Props> = observer((props) => {
disabled={disabled}
placeholder="Select cycle"
buttonVariant="transparent-with-text"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent px-0"
onClose={onClose}
/>
</div>

View file

@ -48,7 +48,7 @@ export const SpreadsheetDueDateColumn: React.FC<Props> = observer((props: Props)
buttonVariant="transparent-with-text"
buttonContainerClassName="w-full"
buttonClassName={cn(
"rounded-none text-left group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10",
"rounded-none text-left group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x",
{
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
}

View file

@ -25,7 +25,7 @@ export const SpreadsheetEstimateColumn: React.FC<Props> = observer((props: Props
projectId={issue.project_id ?? undefined}
disabled={disabled}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -11,7 +11,7 @@ import {
MoveRight,
} from "lucide-react";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, TIssueOrderByOptions } from "@plane/types";
import { CustomMenu } from "@plane/ui";
import { CustomMenu, Row } from "@plane/ui";
//hooks
import { SPREADSHEET_PROPERTY_DETAILS } from "@/constants/spreadsheet";
import useLocalStorage from "@/hooks/use-local-storage";
@ -51,7 +51,7 @@ export const HeaderColumn = (props: Props) => {
customButtonTabIndex={-1}
className="!w-full"
customButton={
<div className="flex w-full cursor-pointer items-center justify-between gap-1.5 py-2 text-sm text-custom-text-200 hover:text-custom-text-100">
<Row className="flex w-full cursor-pointer items-center justify-between gap-1.5 py-2 text-sm text-custom-text-200 hover:text-custom-text-100">
<div className="flex items-center gap-1.5">
{<propertyDetails.icon className="h-4 w-4 text-custom-text-400" />}
{propertyDetails.title}
@ -64,7 +64,7 @@ export const HeaderColumn = (props: Props) => {
)}
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</div>
</div>
</Row>
}
onMenuClose={onClose}
placement="bottom-start"

View file

@ -22,18 +22,22 @@ export const SpreadsheetLabelColumn: React.FC<Props> = observer((props: Props) =
const defaultLabelOptions = issue?.label_ids?.map((id) => labelMap[id]) || [];
return (
<IssuePropertyLabels
projectId={issue.project_id ?? null}
value={issue.label_ids}
defaultOptions={defaultLabelOptions}
onChange={(data) => onChange(issue, { label_ids: data }, { changed_property: "labels", change_details: data })}
className="h-11 w-full border-b-[0.5px] border-custom-border-200"
buttonClassName="px-2.5 h-full group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
hideDropdownArrow
maxRender={1}
disabled={disabled}
placeholderText="Select labels"
onClose={onClose}
/>
<div className="h-11 border-b-[0.5px] border-custom-border-200 w-full">
<IssuePropertyLabels
projectId={issue.project_id ?? null}
value={issue.label_ids}
defaultOptions={defaultLabelOptions}
onChange={(data) => onChange(issue, { label_ids: data }, { changed_property: "labels", change_details: data })}
className="h-full w-full "
buttonClassName="px-page-x w-full h-full group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 rounded-none"
hideDropdownArrow
maxRender={1}
disabled={disabled}
placeholderText="Select labels"
onClose={onClose}
noLabelBorder
fullWidth
/>
</div>
);
});

View file

@ -2,6 +2,7 @@ import React from "react";
import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
import { Row } from "@plane/ui";
type Props = {
issue: TIssue;
@ -11,8 +12,8 @@ export const SpreadsheetLinkColumn: React.FC<Props> = observer((props: Props) =>
const { issue } = props;
return (
<div className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x">
{issue?.link_count} {issue?.link_count === 1 ? "link" : "links"}
</div>
</Row>
);
});

View file

@ -64,8 +64,8 @@ export const SpreadsheetModuleColumn: React.FC<Props> = observer((props) => {
disabled={disabled}
placeholder="Select modules"
buttonVariant="transparent-with-text"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent"
buttonContainerClassName="w-full relative flex items-center p-2 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonClassName="relative leading-4 h-4.5 bg-transparent hover:bg-transparent !px-0"
onClose={onClose}
multiple
showCount

View file

@ -22,7 +22,7 @@ export const SpreadsheetPriorityColumn: React.FC<Props> = observer((props: Props
onChange={(data) => onChange(issue, { priority: data }, { changed_property: "priority", change_details: data })}
disabled={disabled}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -38,7 +38,7 @@ export const SpreadsheetStartDateColumn: React.FC<Props> = observer((props: Prop
placeholder="Start date"
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
/>

View file

@ -23,7 +23,7 @@ export const SpreadsheetStateColumn: React.FC<Props> = observer((props) => {
onChange={(data) => onChange(issue, { state_id: data }, { changed_property: "state", change_details: data })}
disabled={disabled}
buttonVariant="transparent-with-text"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10"
buttonClassName="text-left rounded-none group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10 px-page-x"
buttonContainerClassName="w-full"
onClose={onClose}
showTooltip

View file

@ -4,6 +4,7 @@ import { useParams } from "next/navigation";
// types
import { TIssue } from "@plane/types";
// helpers
import { Row } from "@plane/ui";
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppRouter } from "@/hooks/use-app-router";
@ -22,20 +23,22 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
const subIssueCount = issue?.sub_issues_count ?? 0;
const redirectToIssueDetail = () => {
router.push(`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${issue.id}#sub-issues`);
router.push(
`/${workspaceSlug?.toString()}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${issue.id}#sub-issues`
);
};
return (
<div
<Row
onClick={subIssueCount ? redirectToIssueDetail : () => {}}
className={cn(
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10",
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 py-1 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10",
{
"cursor-pointer": subIssueCount,
}
)}
>
{subIssueCount} {subIssueCount === 1 ? "sub-issue" : "sub-issues"}
</div>
</Row>
);
});

View file

@ -3,6 +3,7 @@ import { observer } from "mobx-react";
// types
import { TIssue } from "@plane/types";
// helpers
import { Row } from "@plane/ui";
import { renderFormattedDate } from "@/helpers/date-time.helper";
type Props = {
@ -13,8 +14,8 @@ export const SpreadsheetUpdatedOnColumn: React.FC<Props> = observer((props: Prop
const { issue } = props;
return (
<div className="flex h-11 w-full items-center justify-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
<Row className="flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 text-xs hover:bg-custom-background-80 group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10">
{renderFormattedDate(issue.updated_at)}
</div>
</Row>
);
});

View file

@ -7,7 +7,7 @@ import { ChevronRight, MoreHorizontal } from "lucide-react";
// types
import { IIssueDisplayProperties, TIssue } from "@plane/types";
// ui
import { ControlLink, Tooltip } from "@plane/ui";
import { ControlLink, Row, Tooltip } from "@plane/ui";
// components
import { MultipleSelectEntityAction } from "@/components/core";
import RenderIfVisible from "@/components/core/render-if-visible-HOC";
@ -237,7 +237,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
id={`issue-${issueId}`}
ref={cellRef}
tabIndex={0}
className="sticky left-0 z-10 group/list-block bg-custom-background-100"
className="relative md:sticky left-0 z-10 group/list-block bg-custom-background-100"
>
<ControlLink
href={`/${workspaceSlug}/projects/${issueDetail.project_id}/issues/${issueId}`}
@ -253,97 +253,99 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
)}
disabled={!!issueDetail?.tempId}
>
<div className="flex items-center gap-0.5 min-w-min py-2.5 pl-2">
{/* select checkbox */}
{projectId && canSelectIssues && (
<Tooltip
tooltipContent={
<>
Only issues within the current
<br />
project can be selected.
</>
}
disabled={issueDetail.project_id === projectId}
>
<div className="flex-shrink-0 grid place-items-center w-3.5 mr-1">
<MultipleSelectEntityAction
className={cn(
"opacity-0 pointer-events-none group-hover/list-block:opacity-100 group-hover/list-block:pointer-events-auto transition-opacity",
{
"opacity-100 pointer-events-auto": isIssueSelected,
}
)}
groupId={SPREADSHEET_SELECT_GROUP}
id={issueDetail.id}
selectionHelpers={selectionHelpers}
disabled={issueDetail.project_id !== projectId}
/>
</div>
</Tooltip>
)}
{/* sub issues indentation */}
<div style={nestingLevel !== 0 ? { width: subIssueIndentation } : {}} />
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="key">
<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"
/>
)}
</p>
</div>
</WithDisplayPropertiesHOC>
{/* sub-issues chevron */}
<div className="grid place-items-center size-4">
{subIssuesCount > 0 && (
<button
type="button"
className="grid place-items-center size-4 rounded-sm text-custom-text-400 hover:text-custom-text-300"
onClick={handleToggleExpand}
<Row className="flex item-center flex-row w-full">
<div className="flex items-center gap-0.5 min-w-min py-2.5">
{/* select checkbox */}
{projectId && canSelectIssues && (
<Tooltip
tooltipContent={
<>
Only issues within the current
<br />
project can be selected.
</>
}
disabled={issueDetail.project_id === projectId}
>
<ChevronRight
className={cn("size-4", {
"rotate-90": isExpanded,
})}
strokeWidth={2.5}
/>
</button>
)}
</div>
</div>
<div className="flex items-center gap-2 justify-between h-full w-full pr-4 pl-1 truncate">
<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 className="flex-shrink-0 grid place-items-center w-3.5 mr-1 absolute left-1">
<MultipleSelectEntityAction
className={cn(
"opacity-0 pointer-events-none group-hover/list-block:opacity-100 group-hover/list-block:pointer-events-auto transition-opacity",
{
"opacity-100 pointer-events-auto": isIssueSelected,
}
)}
groupId={SPREADSHEET_SELECT_GROUP}
id={issueDetail.id}
selectionHelpers={selectionHelpers}
disabled={issueDetail.project_id !== projectId}
/>
</div>
</Tooltip>
)}
{/* sub issues indentation */}
{nestingLevel !== 0 && <div style={{ width: subIssueIndentation }} />}
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="key">
<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"
/>
)}
</p>
</div>
</WithDisplayPropertiesHOC>
{/* sub-issues chevron */}
<div className="grid place-items-center size-4">
{subIssuesCount > 0 && (
<button
type="button"
className="grid place-items-center size-4 rounded-sm text-custom-text-400 hover:text-custom-text-300"
onClick={handleToggleExpand}
>
<ChevronRight
className={cn("size-4", {
"rotate-90": isExpanded,
})}
strokeWidth={2.5}
/>
</button>
)}
</div>
</div>
<div
className={`hidden group-hover:block ${isMenuActive ? "!block" : ""}`}
onClick={(e) => e.stopPropagation()}
>
{quickActions({
issue: issueDetail,
parentRef: cellRef,
customActionButton,
portalElement: portalElement.current,
})}
<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={`hidden group-hover:block ${isMenuActive ? "!block" : ""}`}
onClick={(e) => e.stopPropagation()}
>
{quickActions({
issue: issueDetail,
parentRef: cellRef,
customActionButton,
portalElement: portalElement.current,
})}
</div>
</div>
</div>
</Row>
</ControlLink>
</td>
{/* Rest of the columns */}

View file

@ -28,7 +28,7 @@ export const SpreadsheetHeaderColumn = observer((props: Props) => {
shouldRenderProperty={() => shouldRenderProperty}
>
<th
className="h-11 w-full min-w-36 max-w-48 items-center bg-custom-background-90 text-sm font-medium px-4 py-1 border border-b-0 border-t-0 border-custom-border-100"
className="h-11 w-full min-w-36 max-w-48 items-center bg-custom-background-90 text-sm font-medium py-1 border border-b-0 border-t-0 border-custom-border-100"
ref={tableHeaderCellRef}
tabIndex={0}
>

View file

@ -3,6 +3,7 @@ import { useParams } from "next/navigation";
// ui
import { IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@plane/types";
// components
import { Row } from "@plane/ui";
import { MultipleSelectGroupAction } from "@/components/core";
import { SpreadsheetHeaderColumn } from "@/components/issues/issue-layouts";
// constants
@ -43,24 +44,26 @@ export const SpreadsheetHeader = observer((props: Props) => {
<thead className="sticky top-0 left-0 z-[12] border-b-[0.5px] border-custom-border-100">
<tr>
<th
className="group/list-header sticky left-0 z-[15] h-11 w-[28rem] flex items-center gap-1 bg-custom-background-90 text-sm font-medium before:absolute before:h-full before:right-0 before:border-[0.5px] before:border-custom-border-100 pl-2"
className="group/list-header sticky left-0 z-[15] h-11 w-[28rem] 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"
tabIndex={-1}
>
{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="flex h-full w-full flex-grow items-center py-2.5">Issues</span>
<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">Issues</span>
</Row>
</th>
{spreadsheetColumnsList.map((property) => (

View file

@ -275,14 +275,14 @@ export const CreateUpdateIssueModalBase: React.FC<IssuesModalProps> = observer((
let response: TIssue | undefined = undefined;
try{
try {
if (!data?.id) response = await handleCreateIssue(payload, is_draft_issue);
else response = await handleUpdateIssue(payload);
}catch(error){
} catch (error) {
throw error;
}finally{
if (response != undefined && onSubmit) await onSubmit(response)
}
} finally {
if (response != undefined && onSubmit) await onSubmit(response);
}
};
const handleFormChange = (formData: Partial<TIssue> | null) => setChangesMade(formData);

View file

@ -158,7 +158,6 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
}, [data, projectId]);
const handleFormSubmit = async (formData: Partial<TIssue>, is_draft_issue = false) => {
// Check if the editor is ready to discard
if (!editorRef.current?.isEditorReadyToDiscard()) {
setToast({
@ -190,9 +189,9 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
// this condition helps to move the issues from draft to project issues
if (formData.hasOwnProperty("is_draft")) submitData.is_draft = formData.is_draft;
await onSubmit(submitData, is_draft_issue)
.then(() =>{
.then(() => {
setGptAssistantModal(false);
reset({
...defaultValues,
@ -203,8 +202,9 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
});
editorRef?.current?.clearEditor();
})
.catch((error) => {})
.catch((error) => {
console.error(error);
});
};
const condition =

View file

@ -29,7 +29,7 @@ export const AppliedMembersFilters: React.FC<Props> = observer((props) => {
return (
<div key={memberId} className="flex items-center gap-1 rounded bg-custom-background-80 p-1 text-xs">
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} />
<Avatar name={memberDetails.display_name} src={memberDetails.avatar} showTooltip={false} size={"sm"} />
<span className="normal-case">{memberDetails.display_name}</span>
{editable && (
<button

View file

@ -1,7 +1,7 @@
import { X } from "lucide-react";
import { TModuleDisplayFilters, TModuleFilters } from "@plane/types";
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant, Tag } from "@plane/ui";
import { AppliedDateFilters, AppliedMembersFilters, AppliedStatusFilters } from "@/components/modules";
// helpers
import { replaceUnderscoreIfSnakeCase } from "@/helpers/string.helper";
@ -37,8 +37,8 @@ export const ModuleAppliedFiltersList: React.FC<Props> = (props) => {
const isEditingAllowed = alwaysAllowEditing;
return (
<CustomHeader variant={EHeaderVariant.TERNARY} className="flex flex-wrap gap-2">
<CustomHeader.LeftItem>
<Header variant={EHeaderVariant.TERNARY}>
<div className="flex gap-2 flex-wrap">
{Object.entries(appliedFilters).map(([key, value]) => {
const filterKey = key as keyof TModuleFilters;
@ -46,10 +46,7 @@ export const ModuleAppliedFiltersList: React.FC<Props> = (props) => {
if (Array.isArray(value) && value.length === 0) return;
return (
<div
key={filterKey}
className="flex flex-wrap items-center gap-2 rounded-md border border-custom-border-200 px-2 capitalize"
>
<Tag key={filterKey}>
<div className="flex flex-wrap items-center gap-1.5">
<span className="text-xs text-custom-text-300">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{filterKey === "status" && (
@ -83,7 +80,7 @@ export const ModuleAppliedFiltersList: React.FC<Props> = (props) => {
</button>
)}
</div>
</div>
</Tag>
);
})}
{!isArchived && isFavoriteFilterApplied && (
@ -114,16 +111,14 @@ export const ModuleAppliedFiltersList: React.FC<Props> = (props) => {
</div>
)}
{isEditingAllowed && (
<button
type="button"
onClick={handleClearAllFilters}
className="flex items-center gap-2 rounded-md border border-custom-border-200 px-2 py-1 text-xs text-custom-text-300 hover:text-custom-text-200"
>
Clear all
<X size={12} strokeWidth={2} />
<button type="button" onClick={handleClearAllFilters}>
<Tag>
Clear all
<X size={12} strokeWidth={2} />
</Tag>
</button>
)}
</CustomHeader.LeftItem>
</CustomHeader>
</div>
</Header>
);
};

View file

@ -57,22 +57,20 @@ export const ModulesListGanttChartView: React.FC = observer(() => {
if (!filteredModuleIds) return null;
return (
<div className="h-full w-full overflow-y-auto">
<GanttChartRoot
title="Modules"
loaderTitle="Modules"
blockIds={filteredModuleIds}
getBlockById={getBlockById}
sidebarToRender={(props) => <ModuleGanttSidebar {...props} />}
blockUpdateHandler={(block, payload) => handleModuleUpdate(block, payload)}
blockToRender={(data: IModule) => <ModuleGanttBlock moduleId={data.id} />}
enableBlockLeftResize={isAllowed}
enableBlockRightResize={isAllowed}
enableBlockMove={isAllowed}
enableReorder={isAllowed && displayFilters?.order_by === "sort_order"}
enableAddBlock={isAllowed}
showAllBlocks
/>
</div>
<GanttChartRoot
title="Modules"
loaderTitle="Modules"
blockIds={filteredModuleIds}
getBlockById={getBlockById}
sidebarToRender={(props) => <ModuleGanttSidebar {...props} />}
blockUpdateHandler={(block, payload) => handleModuleUpdate(block, payload)}
blockToRender={(data: IModule) => <ModuleGanttBlock moduleId={data.id} />}
enableBlockLeftResize={isAllowed}
enableBlockRightResize={isAllowed}
enableBlockMove={isAllowed}
enableReorder={isAllowed && displayFilters?.order_by === "sort_order"}
enableAddBlock={isAllowed}
showAllBlocks
/>
);
});

View file

@ -7,7 +7,7 @@ import { useParams, usePathname, useSearchParams } from "next/navigation";
import { CalendarCheck2, CalendarClock, Info, MoveRight, SquareUser } from "lucide-react";
// ui
import { IModule } from "@plane/types";
import { FavoriteStar, LayersIcon, LinearProgressIndicator, Tooltip, setPromiseToast } from "@plane/ui";
import { Card, FavoriteStar, LayersIcon, LinearProgressIndicator, Tooltip, setPromiseToast } from "@plane/ui";
// components
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import { ModuleQuickActions } from "@/components/modules";
@ -176,7 +176,7 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
return (
<div className="relative">
<Link ref={parentRef} href={`/${workspaceSlug}/projects/${moduleDetails.project_id}/modules/${moduleDetails.id}`}>
<div className="flex h-44 w-full flex-col justify-between rounded border border-custom-border-100 bg-custom-background-100 p-4 text-sm hover:shadow-md">
<Card>
<div>
<div className="flex items-center justify-between gap-2">
<Tooltip tooltipContent={moduleDetails.name} position="top" isMobile={isMobile}>
@ -200,7 +200,6 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
</div>
</div>
</div>
<div className="flex flex-col gap-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1.5 text-custom-text-200">
@ -232,7 +231,7 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
)}
</div>
</div>
</div>
</Card>
</Link>
<div className="absolute right-4 bottom-[18px] flex items-center gap-1.5">
{isEditingAllowed && (

View file

@ -2,6 +2,7 @@ import { observer } from "mobx-react";
import Image from "next/image";
import { useParams, useSearchParams } from "next/navigation";
// components
import { ContentWrapper, Row, ERowVariant } from "@plane/ui";
import { ListLayout } from "@/components/core/list";
import { EmptyState } from "@/components/empty-state";
import { ModuleCardItem, ModuleListItem, ModulePeekOverview, ModulesListGanttChartView } from "@/components/modules";
@ -67,44 +68,34 @@ export const ModulesListView: React.FC = observer(() => {
);
return (
<>
<ContentWrapper variant={ERowVariant.HUGGING}>
{displayFilters?.layout === "list" && (
<div className="h-full overflow-y-auto">
<div className="flex h-full w-full justify-between">
<ListLayout>
{filteredModuleIds.map((moduleId) => (
<ModuleListItem key={moduleId} moduleId={moduleId} />
))}
</ListLayout>
<ModulePeekOverview
projectId={projectId?.toString() ?? ""}
workspaceSlug={workspaceSlug?.toString() ?? ""}
/>
</div>
<div className="flex h-full w-full justify-between">
<ListLayout>
{filteredModuleIds.map((moduleId) => (
<ModuleListItem key={moduleId} moduleId={moduleId} />
))}
</ListLayout>
<ModulePeekOverview projectId={projectId?.toString() ?? ""} workspaceSlug={workspaceSlug?.toString() ?? ""} />
</div>
)}
{displayFilters?.layout === "board" && (
<div className="h-full w-full">
<div className="flex h-full w-full justify-between">
<div
className={`grid h-full w-full grid-cols-1 gap-6 overflow-y-auto p-8 ${
peekModule
? "lg:grid-cols-1 xl:grid-cols-2 3xl:grid-cols-3"
: "lg:grid-cols-2 xl:grid-cols-3 3xl:grid-cols-4"
} auto-rows-max transition-all vertical-scrollbar scrollbar-lg`}
>
{filteredModuleIds.map((moduleId) => (
<ModuleCardItem key={moduleId} moduleId={moduleId} />
))}
</div>
<ModulePeekOverview
projectId={projectId?.toString() ?? ""}
workspaceSlug={workspaceSlug?.toString() ?? ""}
/>
<Row className="flex h-full w-full justify-between py-page-y">
<div
className={`grid h-full w-full grid-cols-1 gap-6 overflow-y-auto ${
peekModule
? "lg:grid-cols-1 xl:grid-cols-2 3xl:grid-cols-3"
: "lg:grid-cols-2 xl:grid-cols-3 3xl:grid-cols-4"
} auto-rows-max transition-all vertical-scrollbar scrollbar-lg`}
>
{filteredModuleIds.map((moduleId) => (
<ModuleCardItem key={moduleId} moduleId={moduleId} />
))}
</div>
</div>
<ModulePeekOverview projectId={projectId?.toString() ?? ""} workspaceSlug={workspaceSlug?.toString() ?? ""} />
</Row>
)}
{displayFilters?.layout === "gantt" && <ModulesListGanttChartView />}
</>
</ContentWrapper>
);
});

View file

@ -2,6 +2,7 @@ import { useEffect } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// components
import { ContentWrapper } from "@plane/ui";
import { DashboardWidgets } from "@/components/dashboard";
import { EmptyState } from "@/components/empty-state";
import { IssuePeekOverview } from "@/components/issues";
@ -64,19 +65,16 @@ export const WorkspaceDashboardView = observer(() => {
<>
{joinedProjectIds.length > 0 || loader ? (
<>
<IssuePeekOverview shouldReplaceIssueOnFetch={false} />
<div
className={cn(
"space-y-7 md:p-7 p-3 bg-custom-background-90 h-full w-full flex flex-col overflow-y-auto",
{
"vertical-scrollbar scrollbar-lg": windowWidth >= 768,
}
)}
<IssuePeekOverview />
<ContentWrapper
className={cn("gap-7", {
"vertical-scrollbar scrollbar-lg": windowWidth >= 768,
})}
>
{currentUser && <UserGreetingsView user={currentUser} />}
<DashboardWidgets />
</div>
</ContentWrapper>
</>
) : (
<EmptyState

View file

@ -16,6 +16,7 @@ import {
// types
import { IUserLite } from "@plane/types";
// components
import { Row } from "@plane/ui";
import { PageContentBrowser, PageContentLoader, PageEditorTitle } from "@/components/pages";
// helpers
import { cn, LIVE_URL } from "@/helpers/common.helper";
@ -69,7 +70,7 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
project: { getProjectMemberIds },
} = useMember();
// derived values
const workspaceId = workspaceSlug ? getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "" : "";
const workspaceId = workspaceSlug ? (getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "") : "";
const pageId = page?.id;
const pageTitle = page?.name ?? "";
const pageDescription = page?.description_html;
@ -135,8 +136,8 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
return (
<div className="flex items-center h-full w-full overflow-y-auto">
<div
className={cn("sticky top-0 hidden h-full flex-shrink-0 -translate-x-full p-5 duration-200 md:block", {
<Row
className={cn("sticky top-0 hidden h-full flex-shrink-0 -translate-x-full py-5 duration-200 md:block", {
"translate-x-0": sidePeekVisible,
"w-[10rem] lg:w-[14rem]": !isFullWidth,
"w-[5%]": isFullWidth,
@ -148,7 +149,7 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
markings={markings}
/>
)}
</div>
</Row>
<div
className={cn("h-full w-full pt-5 duration-200", {
"md:w-[calc(100%-10rem)] xl:w-[calc(100%-28rem)]": !isFullWidth,

View file

@ -1,7 +1,7 @@
import { observer } from "mobx-react";
import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/editor";
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages";
// hooks
import { usePageFilters } from "@/hooks/use-page-filters";
@ -43,7 +43,7 @@ export const PageEditorMobileHeaderRoot: React.FC<Props> = observer((props) => {
return (
<>
<CustomHeader variant={EHeaderVariant.SECONDARY} className="flex justify-between">
<Header variant={EHeaderVariant.SECONDARY}>
<div className="flex-shrink-0 my-auto">
<PageSummaryPopover
editorRef={isContentEditable ? editorRef.current : readOnlyEditorRef.current}
@ -60,12 +60,12 @@ export const PageEditorMobileHeaderRoot: React.FC<Props> = observer((props) => {
page={page}
readOnlyEditorRef={readOnlyEditorRef}
/>
</CustomHeader>
<CustomHeader variant={EHeaderVariant.TERNARY}>
</Header>
<Header variant={EHeaderVariant.TERNARY}>
{(editorReady || readOnlyEditorReady) && isContentEditable && editorRef.current && (
<PageToolbar editorRef={editorRef?.current} />
)}
</CustomHeader>
</Header>
</>
);
});

View file

@ -1,7 +1,7 @@
import { observer } from "mobx-react";
import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/editor";
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { PageEditorMobileHeaderRoot, PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages";
// helpers
import { cn } from "@/helpers/common.helper";
@ -45,19 +45,26 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
return (
<>
<CustomHeader variant={EHeaderVariant.SECONDARY} className="hidden md:flex justify-between">
<div className={cn("flex-shrink-0 my-auto")}>
<PageSummaryPopover
editorRef={isContentEditable ? editorRef.current : readOnlyEditorRef.current}
isFullWidth={isFullWidth}
markings={markings}
sidePeekVisible={sidePeekVisible}
setSidePeekVisible={setSidePeekVisible}
/>
</div>
{(editorReady || readOnlyEditorReady) && isContentEditable && editorRef.current && (
<PageToolbar editorRef={editorRef?.current} />
)}
<Header variant={EHeaderVariant.SECONDARY} showOnMobile={false}>
<Header.LeftItem className="gap-0 w-full">
<div
className={cn("flex-shrink-0 my-auto", {
"w-40 lg:w-56": !isFullWidth,
"w-[5%]": isFullWidth,
})}
>
<PageSummaryPopover
editorRef={isContentEditable ? editorRef.current : readOnlyEditorRef.current}
isFullWidth={isFullWidth}
markings={markings}
sidePeekVisible={sidePeekVisible}
setSidePeekVisible={setSidePeekVisible}
/>
</div>
{(editorReady || readOnlyEditorReady) && isContentEditable && editorRef.current && (
<PageToolbar editorRef={editorRef?.current} />
)}
</Header.LeftItem>
<PageExtraOptions
editorRef={editorRef}
handleDuplicatePage={handleDuplicatePage}
@ -65,7 +72,7 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
page={page}
readOnlyEditorRef={readOnlyEditorRef}
/>
</CustomHeader>
</Header>
<div className="md:hidden">
<PageEditorMobileHeaderRoot
editorRef={editorRef}

View file

@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { ListFilter } from "lucide-react";
import { TPageFilterProps, TPageNavigationTabs } from "@plane/types";
// components
import { CustomHeader, EHeaderVariant } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { FiltersDropdown } from "@/components/issues";
import {
PageAppliedFiltersList,
@ -50,11 +50,11 @@ export const PagesListHeaderRoot: React.FC<Props> = observer((props) => {
return (
<>
<CustomHeader variant={EHeaderVariant.SECONDARY} className="flex">
<CustomHeader.LeftItem>
<Header variant={EHeaderVariant.SECONDARY}>
<Header.LeftItem>
<PageTabNavigation workspaceSlug={workspaceSlug} projectId={projectId} pageType={pageType} />
</CustomHeader.LeftItem>
<CustomHeader.RightItem>
</Header.LeftItem>
<Header.RightItem className="items-center">
<PageSearchInput
searchQuery={filters.searchQuery}
updateSearchQuery={(val) => updateFilters("searchQuery", val)}
@ -79,17 +79,17 @@ export const PagesListHeaderRoot: React.FC<Props> = observer((props) => {
memberIds={workspaceMemberIds ?? undefined}
/>
</FiltersDropdown>
</CustomHeader.RightItem>
</CustomHeader>
</Header.RightItem>
</Header>
{calculateTotalFilters(filters?.filters ?? {}) !== 0 && (
<CustomHeader variant={EHeaderVariant.TERNARY}>
<Header variant={EHeaderVariant.TERNARY}>
<PageAppliedFiltersList
appliedFilters={filters.filters ?? {}}
handleClearAllFilters={clearAllFilters}
handleRemoveFilter={handleRemoveFilter}
alwaysAllowEditing
/>
</CustomHeader>
</Header>
)}
</>
);

Some files were not shown because too many files have changed in this diff Show more