Merge pull request #451 from makeplane/sync/ce-ee

sync: community changes
This commit is contained in:
sriram veeraghanta
2024-06-20 17:21:12 +05:30
committed by GitHub
36 changed files with 215 additions and 140 deletions

View File

@@ -4,7 +4,7 @@ on:
workflow_dispatch:
push:
branches:
- develop
- preview
env:
SOURCE_BRANCH_NAME: ${{ github.ref_name }}

View File

@@ -3,18 +3,12 @@ from rest_framework import serializers
# Module imports
from .base import DynamicBaseSerializer
from .workspace import WorkspaceLiteSerializer
from .project import ProjectLiteSerializer
from plane.db.models import IssueView
from plane.utils.issue_filters import issue_filters
class IssueViewSerializer(DynamicBaseSerializer):
is_favorite = serializers.BooleanField(read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(
source="workspace", read_only=True
)
class Meta:
model = IssueView
@@ -24,6 +18,8 @@ class IssueViewSerializer(DynamicBaseSerializer):
"project",
"query",
"owned_by",
"access",
"is_locked",
]
def create(self, validated_data):

View File

@@ -69,11 +69,40 @@ class WorkspaceViewViewSet(BaseViewSet):
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project__isnull=True)
.filter(Q(owned_by=self.request.user) | Q(access=1))
.select_related("workspace")
.order_by(self.request.GET.get("order_by", "-created_at"))
.distinct()
)
def partial_update(self, request, slug, pk):
workspace_view = IssueView.objects.get(
pk=pk,
workspace__slug=slug,
)
if workspace_view.is_locked:
return Response(
{"error": "view is locked"},
status=status.HTTP_400_BAD_REQUEST,
)
# Only update the view if owner is updating
if workspace_view.owned_by_id != request.user.id:
return Response(
{"error": "Only the owner of the view can update the view"},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = IssueViewSerializer(
workspace_view, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class WorkspaceViewIssuesViewSet(BaseViewSet):
permission_classes = [
@@ -294,6 +323,7 @@ class IssueViewViewSet(BaseViewSet):
project__project_projectmember__is_active=True,
project__archived_at__isnull=True,
)
.filter(Q(owned_by=self.request.user) | Q(access=1))
.select_related("project")
.select_related("workspace")
.annotate(is_favorite=Exists(subquery))
@@ -313,6 +343,33 @@ class IssueViewViewSet(BaseViewSet):
).data
return Response(views, status=status.HTTP_200_OK)
def partial_update(self, request, slug, project_id, pk):
issue_view = IssueView.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id
)
if issue_view.is_locked:
return Response(
{"error": "view is locked"},
status=status.HTTP_400_BAD_REQUEST,
)
# Only update the view if owner is updating
if issue_view.owned_by_id != request.user.id:
return Response(
{"error": "Only the owner of the view can update the view"},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = IssueViewSerializer(
issue_view, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class IssueViewFavoriteViewSet(BaseViewSet):
model = UserFavorite

View File

@@ -2,7 +2,6 @@
from django.db.models import (
Q,
Count,
Sum,
)
# Third party modules
@@ -87,29 +86,6 @@ class WorkspaceCyclesEndpoint(BaseAPIView):
),
)
)
.annotate(
total_estimates=Sum("issue_cycle__issue__estimate_point")
)
.annotate(
completed_estimates=Sum(
"issue_cycle__issue__estimate_point",
filter=Q(
issue_cycle__issue__state__group="completed",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
started_estimates=Sum(
"issue_cycle__issue__estimate_point",
filter=Q(
issue_cycle__issue__state__group="started",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.order_by(self.kwargs.get("order_by", "-created_at"))
.distinct()
)

View File

@@ -4,9 +4,10 @@ import { ChevronRight } from "lucide-react";
type BreadcrumbsProps = {
children: React.ReactNode;
onBack?: () => void;
isLoading?: boolean;
};
const Breadcrumbs = ({ children, onBack }: BreadcrumbsProps) => {
const Breadcrumbs = ({ children, onBack, isLoading = false }: BreadcrumbsProps) => {
const [isSmallScreen, setIsSmallScreen] = React.useState(false);
React.useEffect(() => {
@@ -21,6 +22,13 @@ const Breadcrumbs = ({ children, onBack }: BreadcrumbsProps) => {
const childrenArray = React.Children.toArray(children);
const BreadcrumbItemLoader = (
<div className="flex items-center gap-1 animate-pulse">
<span className="h-5 w-5 bg-custom-background-80 rounded" />
<span className="h-5 w-16 bg-custom-background-80 rounded" />
</div>
);
return (
<div className="flex items-center space-x-2 overflow-hidden">
{!isSmallScreen && (
@@ -33,7 +41,7 @@ const Breadcrumbs = ({ children, onBack }: BreadcrumbsProps) => {
</div>
)}
<div className={`flex items-center gap-2.5 ${isSmallScreen && index > 0 ? "hidden sm:flex" : "flex"}`}>
{child}
{isLoading ? BreadcrumbItemLoader : child}
</div>
</React.Fragment>
))}
@@ -50,7 +58,9 @@ const Breadcrumbs = ({ children, onBack }: BreadcrumbsProps) => {
)}
<ChevronRight className="h-3.5 w-3.5 flex-shrink-0 text-custom-text-400" aria-hidden="true" />
</div>
<div className="flex items-center gap-2.5">{childrenArray[childrenArray.length - 1]}</div>
<div className="flex items-center gap-2.5">
{isLoading ? BreadcrumbItemLoader : childrenArray[childrenArray.length - 1]}
</div>
</>
)}
{isSmallScreen && childrenArray.length === 1 && childrenArray}

View File

@@ -1,6 +1,7 @@
import React from "react";
import { Star } from "lucide-react";
// helpers
import { cn } from "@/helpers/common.helper";
import { cn } from "../helpers";
type Props = {
buttonClassName?: string;

View File

@@ -1,21 +1,22 @@
export * from "./avatar";
export * from "./breadcrumbs";
export * from "./badge";
export * from "./breadcrumbs";
export * from "./button";
export * from "./emoji";
export * from "./dropdowns";
export * from "./control-link";
export * from "./dropdown";
export * from "./dropdowns";
export * from "./emoji";
export * from "./form-fields";
export * from "./hooks";
export * from "./icons";
export * from "./modals";
export * from "./progress";
export * from "./spinners";
export * from "./tooltip";
export * from "./loader";
export * from "./control-link";
export * from "./toast";
export * from "./drag-handle";
export * from "./typography";
export * from "./drop-indicator";
export * from "./sortable";
export * from "./hooks";
export * from "./spinners";
export * from "./toast";
export * from "./tooltip";
export * from "./typography";
export * from "./drag-handle";
export * from "./drop-indicator";
export * from "./favorite-star";
export * from "./loader";

3
web/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Sentry Config File
.env.sentry-build-plugin

View File

@@ -25,7 +25,7 @@ export const ProjectArchivesHeader: FC = observer(() => {
const {
issuesFilter: { issueFilters },
} = useIssues(EIssuesStoreType.ARCHIVED);
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
// hooks
const { isMobile } = usePlatformOS();
@@ -42,7 +42,7 @@ export const ProjectArchivesHeader: FC = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2.5">
<Breadcrumbs onBack={router.back}>
<Breadcrumbs onBack={router.back} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -21,7 +21,7 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
// router
const { workspaceSlug, projectId, archivedIssueId } = useParams();
// store hooks
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { data: issueDetails } = useSWR(
workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId as string) : null,
@@ -39,7 +39,7 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs>
<Breadcrumbs isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -15,7 +15,12 @@ import { ProjectAnalyticsModal } from "@/components/analytics";
import { BreadcrumbLink, Logo } from "@/components/common";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// constants
import { EIssueFilterType, EIssueLayoutTypes, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
import {
EIssueFilterType,
EIssueLayoutTypes,
EIssuesStoreType,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { cn } from "@/helpers/common.helper";
@@ -79,7 +84,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { projectStates } = useProjectState();
const { projectLabels } = useLabel();
const {
@@ -160,7 +165,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
<div className="relative z-[15] w-full items-center gap-x-2 gap-y-4">
<div className="flex justify-between bg-custom-sidebar-background-100 p-4">
<div className="flex items-center gap-2">
<Breadcrumbs onBack={router.back}>
<Breadcrumbs onBack={router.back} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
@@ -209,8 +214,9 @@ export const CycleIssuesHeader: React.FC = observer(() => {
{issuesCount && issuesCount > 0 ? (
<Tooltip
isMobile={isMobile}
tooltipContent={`There are ${issuesCount} ${issuesCount > 1 ? "issues" : "issue"
} in this cycle`}
tooltipContent={`There are ${issuesCount} ${
issuesCount > 1 ? "issues" : "issue"
} in this cycle`}
position="bottom"
>
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">

View File

@@ -24,7 +24,7 @@ export const CyclesListHeader: FC = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const canUserCreateCycle =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
@@ -33,7 +33,7 @@ export const CyclesListHeader: FC = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs onBack={router.back}>
<Breadcrumbs onBack={router.back} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -11,7 +11,12 @@ import { Breadcrumbs, LayersIcon, Tooltip } from "@plane/ui";
import { BreadcrumbLink, Logo } from "@/components/common";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// constants
import { EIssueFilterType, EIssuesStoreType, EIssueLayoutTypes, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
import {
EIssueFilterType,
EIssuesStoreType,
EIssueLayoutTypes,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
// helpers
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
@@ -25,7 +30,7 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
const {
issuesFilter: { issueFilters, updateFilters },
} = useIssues(EIssuesStoreType.DRAFT);
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { projectStates } = useProjectState();
const { projectLabels } = useLabel();
const {
@@ -91,7 +96,7 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2.5">
<Breadcrumbs>
<Breadcrumbs isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -18,14 +18,14 @@ export const ProjectInboxHeader: FC = observer(() => {
// router
const { workspaceSlug, projectId } = useParams();
// store hooks
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader: currentProjectDetailsLoader } = useProject();
const { loader } = useProjectInbox();
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-4">
<Breadcrumbs>
<Breadcrumbs isLoading={currentProjectDetailsLoader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -19,7 +19,7 @@ export const ProjectIssueDetailsHeader = observer(() => {
const router = useAppRouter();
const { workspaceSlug, projectId, issueId } = useParams();
// store hooks
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { issueDetailSidebarCollapsed, toggleIssueDetailSidebar } = useAppTheme();
const {
issue: { getIssueById },
@@ -32,7 +32,7 @@ export const ProjectIssueDetailsHeader = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs onBack={router.back}>
<Breadcrumbs onBack={router.back} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -14,7 +14,12 @@ import { ProjectAnalyticsModal } from "@/components/analytics";
import { BreadcrumbLink, Logo } from "@/components/common";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// constants
import { EIssueFilterType, EIssuesStoreType, EIssueLayoutTypes, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
import {
EIssueFilterType,
EIssuesStoreType,
EIssueLayoutTypes,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { SPACE_BASE_URL } from "@/helpers/common.helper";
@@ -52,7 +57,7 @@ export const ProjectIssuesHeader = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { projectStates } = useProjectState();
const { projectLabels } = useLabel();
const { isMobile } = usePlatformOS();
@@ -122,7 +127,7 @@ export const ProjectIssuesHeader = observer(() => {
<div className="relative z-[15] flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2.5">
<Breadcrumbs onBack={() => router.back()}>
<Breadcrumbs onBack={() => router.back()} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
@@ -178,7 +183,8 @@ export const ProjectIssuesHeader = observer(() => {
</div>
<div className="items-center gap-2 hidden md:flex">
<LayoutSelection
layouts={[EIssueLayoutTypes.LIST,
layouts={[
EIssueLayoutTypes.LIST,
EIssueLayoutTypes.KANBAN,
EIssueLayoutTypes.CALENDAR,
EIssueLayoutTypes.SPREADSHEET,

View File

@@ -15,7 +15,12 @@ import { ProjectAnalyticsModal } from "@/components/analytics";
import { BreadcrumbLink, Logo } from "@/components/common";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// constants
import { EIssuesStoreType, EIssueFilterType, EIssueLayoutTypes, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
import {
EIssuesStoreType,
EIssueFilterType,
EIssueLayoutTypes,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { cn } from "@/helpers/common.helper";
@@ -81,7 +86,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { projectLabels } = useLabel();
const { projectStates } = useProjectState();
const {
@@ -160,7 +165,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
<div className="relative z-[15] items-center gap-x-2 gap-y-4">
<div className="flex justify-between bg-custom-sidebar-background-100 p-4">
<div className="flex items-center gap-2">
<Breadcrumbs onBack={router.back}>
<Breadcrumbs onBack={router.back} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
@@ -209,8 +214,9 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
{issuesCount && issuesCount > 0 ? (
<Tooltip
isMobile={isMobile}
tooltipContent={`There are ${issuesCount} ${issuesCount > 1 ? "issues" : "issue"
} in this module`}
tooltipContent={`There are ${issuesCount} ${
issuesCount > 1 ? "issues" : "issue"
} in this module`}
position="bottom"
>
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">

View File

@@ -23,7 +23,7 @@ export const ModulesListHeader: React.FC = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
// auth
const canUserCreateModule =
@@ -33,7 +33,7 @@ export const ModulesListHeader: React.FC = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs onBack={router.back}>
<Breadcrumbs onBack={router.back} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -28,7 +28,7 @@ export const PageDetailsHeader = observer(() => {
// state
const [isOpen, setIsOpen] = useState(false);
// store hooks
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { isContentEditable, isSubmitting, name, logo_props, updatePageLogo } = usePage(pageId?.toString() ?? "");
// use platform
const { platform } = usePlatformOS();
@@ -59,7 +59,7 @@ export const PageDetailsHeader = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs>
<Breadcrumbs isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -23,7 +23,7 @@ export const PagesListHeader = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { setTrackElement } = useEventTracker();
const canUserCreatePage =
@@ -33,7 +33,7 @@ export const PagesListHeader = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs>
<Breadcrumbs isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -22,7 +22,7 @@ export const ProjectSettingHeader: FC = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
if (currentProjectRole && currentProjectRole <= EUserProjectRoles.VIEWER) return null;
@@ -31,7 +31,7 @@ export const ProjectSettingHeader: FC = observer(() => {
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<div className="z-50">
<Breadcrumbs onBack={router.back}>
<Breadcrumbs onBack={router.back} isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -12,7 +12,12 @@ import { Breadcrumbs, Button, CustomMenu, PhotoFilterIcon } from "@plane/ui";
import { BreadcrumbLink, Logo } from "@/components/common";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues";
// constants
import { EIssuesStoreType, EIssueFilterType, EIssueLayoutTypes, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
import {
EIssuesStoreType,
EIssueFilterType,
EIssueLayoutTypes,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { calculateTotalFilters } from "@/helpers/filter.helper";
@@ -42,7 +47,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const { projectViewIds, getViewById } = useProjectView();
const { projectStates } = useProjectState();
const { projectLabels } = useLabel();
@@ -131,7 +136,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
return (
<div className="relative z-[15] flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex items-center gap-2">
<Breadcrumbs>
<Breadcrumbs isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -20,7 +20,7 @@ export const ProjectViewsHeader = observer(() => {
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails } = useProject();
const { currentProjectDetails, loader } = useProject();
const canUserCreateIssue =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
@@ -30,7 +30,7 @@ export const ProjectViewsHeader = observer(() => {
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs>
<Breadcrumbs isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -11,13 +11,13 @@ import { BreadcrumbLink } from "@/components/common";
import { useWorkspace } from "@/hooks/store";
export const WorkspaceSettingHeader: FC = observer(() => {
const { currentWorkspace } = useWorkspace();
const { currentWorkspace, loader } = useWorkspace();
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs>
<Breadcrumbs isLoading={loader}>
<Breadcrumbs.BreadcrumbItem
type="text"
link={

View File

@@ -1,49 +1,37 @@
"use client";
// import { useEffect } from "react";
// import * as Sentry from "@sentry/nextjs";
// services
import { Button } from "@plane/ui";
// ui
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// helpers
// import { API_BASE_URL } from "@/helpers/common.helper";
import { API_BASE_URL } from "@/helpers/common.helper";
// hooks
import { useAppRouter } from "@/hooks/use-app-router";
// layouts
import DefaultLayout from "@/layouts/default-layout";
//
// import { AuthService } from "@/services/auth.service";
// layouts
// ui
// services
import { AuthService } from "@/services/auth.service";
// services
// const authService = new AuthService();
const authService = new AuthService();
// type props = {
// error: Error & { digest?: string };
// };
// TODO: adding error sentry logging.
// const CustomErrorComponent = ({ error }: props) => {
const CustomErrorComponent = () => {
// const router = useAppRouter();
// useEffect(() => {
// Sentry.captureException(error);
// }, [error]);
export default function CustomErrorComponent() {
const router = useAppRouter();
const handleRefresh = () => {
window.location.reload();
};
const handleSignOut = async () => {
// await authService
// .signOut(API_BASE_URL)
// .catch(() =>
// setToast({
// type: TOAST_TYPE.ERROR,
// title: "Error!",
// message: "Failed to sign out. Please try again.",
// })
// )
// .finally(() => router.push("/"));
await authService
.signOut(API_BASE_URL)
.catch(() =>
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Failed to sign out. Please try again.",
})
)
.finally(() => router.push("/"));
};
return (
@@ -84,6 +72,4 @@ const CustomErrorComponent = () => {
</div>
</DefaultLayout>
);
};
export default CustomErrorComponent;
}

23
web/app/global-error.tsx Normal file
View File

@@ -0,0 +1,23 @@
"use client";
import { useEffect } from "react";
import * as Sentry from "@sentry/nextjs";
import NextError from "next/error";
export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<html>
<body>
{/* `NextError` is the default Next.js error page component. Its type
definition requires a `statusCode` prop. However, since the App Router
does not expose status codes for errors, we simply pass 0 to render a
generic error message. */}
<NextError statusCode={0} />
</body>
</html>
);
}

View File

@@ -3,7 +3,6 @@ export * from "./modals";
export * from "./multiple-select";
export * from "./sidebar";
export * from "./activity";
export * from "./favorite-star";
export * from "./theme";
export * from "./image-picker-popover";
export * from "./page-title";

View File

@@ -6,9 +6,8 @@ import Link from "next/link";
import { useParams } from "next/navigation";
import { Users } from "lucide-react";
// ui
import { Avatar, AvatarGroup, setPromiseToast } from "@plane/ui";
import { Avatar, AvatarGroup, FavoriteStar, setPromiseToast } from "@plane/ui";
// components
import { FavoriteStar } from "@/components/core";
import { CycleQuickActions } from "@/components/cycles";
// constants
import { CYCLE_FAVORITED, CYCLE_UNFAVORITED } from "@/constants/event-tracker";

View File

@@ -8,9 +8,8 @@ import { CalendarCheck2, CalendarClock, Info, MoveRight } from "lucide-react";
// types
import type { TCycleGroups } from "@plane/types";
// ui
import { Avatar, AvatarGroup, Tooltip, LayersIcon, CycleGroupIcon, setPromiseToast } from "@plane/ui";
import { Avatar, AvatarGroup, Tooltip, LayersIcon, CycleGroupIcon, setPromiseToast, FavoriteStar } from "@plane/ui";
// components
import { FavoriteStar } from "@/components/core";
import { CycleQuickActions } from "@/components/cycles";
// constants
import { CYCLE_STATUS } from "@/constants/cycle";

View File

@@ -6,9 +6,8 @@ import { CalendarCheck2, CalendarClock, MoveRight, Users } from "lucide-react";
// types
import { ICycle, TCycleGroups } from "@plane/types";
// ui
import { Avatar, AvatarGroup, Tooltip, setPromiseToast } from "@plane/ui";
import { Avatar, AvatarGroup, FavoriteStar, Tooltip, setPromiseToast } from "@plane/ui";
// components
import { FavoriteStar } from "@/components/core";
import { CycleQuickActions } from "@/components/cycles";
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
// constants

View File

@@ -6,9 +6,8 @@ import Link from "next/link";
import { useParams, usePathname, useSearchParams } from "next/navigation";
import { CalendarCheck2, CalendarClock, Info, MoveRight, SquareUser } from "lucide-react";
// ui
import { LayersIcon, Tooltip, setPromiseToast } from "@plane/ui";
import { FavoriteStar, LayersIcon, Tooltip, setPromiseToast } from "@plane/ui";
// components
import { FavoriteStar } from "@/components/core";
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import { ModuleQuickActions } from "@/components/modules";
// constants

View File

@@ -8,9 +8,8 @@ import { CalendarCheck2, CalendarClock, MoveRight, SquareUser } from "lucide-rea
// types
import { IModule } from "@plane/types";
// ui
import { Tooltip, setPromiseToast } from "@plane/ui";
import { FavoriteStar, Tooltip, setPromiseToast } from "@plane/ui";
// components
import { FavoriteStar } from "@/components/core";
import { ModuleQuickActions } from "@/components/modules";
// constants
import { MODULE_FAVORITED, MODULE_UNFAVORITED } from "@/constants/event-tracker";

View File

@@ -4,9 +4,8 @@ import React, { FC } from "react";
import { observer } from "mobx-react";
import { Earth, Info, Lock, Minus } from "lucide-react";
// ui
import { Avatar, TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
import { Avatar, FavoriteStar, TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
// components
import { FavoriteStar } from "@/components/core";
import { PageQuickActions } from "@/components/pages/dropdowns";
// helpers
import { renderFormattedDate } from "@/helpers/date-time.helper";

View File

@@ -18,10 +18,10 @@ import {
setPromiseToast,
ContextMenu,
TContextMenuItem,
FavoriteStar,
} from "@plane/ui";
// components
import { Logo } from "@/components/common";
import { FavoriteStar } from "@/components/core";
import { ArchiveRestoreProjectModal, DeleteProjectModal, JoinProjectModal } from "@/components/project";
// constants
import { EUserProjectRoles } from "@/constants/project";

View File

@@ -3,8 +3,9 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// types
import { IProjectView } from "@plane/types";
// ui
import { FavoriteStar } from "@plane/ui";
// components
import { FavoriteStar } from "@/components/core";
import { DeleteProjectViewModal, CreateUpdateProjectViewModal, ViewQuickActions } from "@/components/views";
// constants
import { EUserProjectRoles } from "@/constants/project";

View File

@@ -7,7 +7,7 @@
"develop": "next dev --port 3000",
"build": "next build",
"start": "next start",
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
"lint": "next lint --dir .",
"export": "next export",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
},