This commit is contained in:
DCCONSTRUCTIONS
2026-04-18 18:39:25 +03:00
commit 3ba092b60c
4944 changed files with 497564 additions and 0 deletions
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
// local components
import { useProjectNavigationPreferences } from "@/hooks/use-navigation-preferences";
import { ProjectBreadcrumb } from "./project";
type TCommonProjectBreadcrumbProps = {
workspaceSlug: string;
projectId: string;
};
export function CommonProjectBreadcrumbs(props: TCommonProjectBreadcrumbProps) {
const { workspaceSlug, projectId } = props;
// preferences
const { preferences: projectPreferences } = useProjectNavigationPreferences();
if (projectPreferences.navigationMode === "TABBED") return null;
return <ProjectBreadcrumb workspaceSlug={workspaceSlug} projectId={projectId} />;
}
@@ -0,0 +1,66 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { ReactNode } from "react";
import { observer } from "mobx-react";
// plane imports
import type { EProjectFeatureKey } from "@plane/constants";
import { Breadcrumbs } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
import type { TNavigationItem } from "@/components/workspace/sidebar/project-navigation";
// hooks
import { useProject } from "@/hooks/store/use-project";
// local imports
import { getProjectFeatureNavigation } from "../projects/navigation/helper";
type TProjectFeatureBreadcrumbProps = {
workspaceSlug: string;
projectId: string;
featureKey: EProjectFeatureKey;
isLast?: boolean;
additionalNavigationItems?: TNavigationItem[];
};
export const ProjectFeatureBreadcrumb = observer(function ProjectFeatureBreadcrumb(
props: TProjectFeatureBreadcrumbProps
) {
const { workspaceSlug, projectId, featureKey, isLast = false, additionalNavigationItems } = props;
// store hooks
const { getPartialProjectById } = useProject();
// derived values
const project = getPartialProjectById(projectId);
if (!project) return null;
const navigationItems = getProjectFeatureNavigation(workspaceSlug, projectId, project);
// if additional navigation items are provided, add them to the navigation items
const allNavigationItems = [...(additionalNavigationItems || []), ...navigationItems];
const currentNavigationItem = allNavigationItems.find((item) => item.key === featureKey);
const icon = currentNavigationItem?.icon as ReactNode;
const name = currentNavigationItem?.name;
const href = currentNavigationItem?.href;
return (
<>
<Breadcrumbs.Item
component={
<BreadcrumbLink
key={featureKey}
label={name}
isLast={isLast}
href={href}
icon={<Breadcrumbs.Icon>{icon}</Breadcrumbs.Icon>}
/>
}
showSeparator={false}
isLast={isLast}
/>
</>
);
});
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { observer } from "mobx-react";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ProjectIcon } from "@plane/propel/icons";
// plane imports
import type { ICustomSearchSelectOption } from "@plane/types";
import { BreadcrumbNavigationSearchDropdown, Breadcrumbs } from "@plane/ui";
import { SwitcherLabel } from "@/components/common/switcher-label";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useAppRouter } from "@/hooks/use-app-router";
import type { TProject } from "@/plane-web/types";
type TProjectBreadcrumbProps = {
workspaceSlug: string;
projectId: string;
handleOnClick?: () => void;
};
export const ProjectBreadcrumb = observer(function ProjectBreadcrumb(props: TProjectBreadcrumbProps) {
const { workspaceSlug, projectId, handleOnClick } = props;
// router
const router = useAppRouter();
// store hooks
const { joinedProjectIds, getPartialProjectById } = useProject();
const currentProjectDetails = getPartialProjectById(projectId);
// store hooks
if (!currentProjectDetails) return null;
// derived values
const switcherOptions = joinedProjectIds
.map((projectId) => {
const project = getPartialProjectById(projectId);
return {
value: projectId,
query: project?.name,
content: (
<SwitcherLabel
name={project?.name}
logo_props={project?.logo_props}
LabelIcon={ProjectIcon}
type="material"
/>
),
};
})
.filter((option) => option !== undefined) as ICustomSearchSelectOption[];
// helpers
const renderIcon = (projectDetails: TProject) => (
<span className="grid size-4 flex-shrink-0 place-items-center">
<Logo logo={projectDetails.logo_props} size={14} />
</span>
);
return (
<>
<Breadcrumbs.Item
component={
<BreadcrumbNavigationSearchDropdown
selectedItem={currentProjectDetails.id}
navigationItems={switcherOptions}
onChange={(value: string) => {
router.push(`/${workspaceSlug}/projects/${value}/issues`);
}}
title={currentProjectDetails?.name}
icon={renderIcon(currentProjectDetails)}
handleOnClick={() => {
if (handleOnClick) handleOnClick();
else router.push(`/${workspaceSlug}/projects/${currentProjectDetails.id}/issues/`);
}}
shouldTruncate
/>
}
showSeparator={false}
/>
</>
);
});