[WEB-4050] feat: breadcrumbs revamp (#7188)
* chore: project feature enum added * feat: revamp breadcrumb and add navigation dropdown component * chore: custom search select component refactoring * chore: breadcrumb stories added * chore: switch label and breadcrumb link component refactor * chore: project navigation helper function added * chore: common breadcrumb component added * chore: breadcrumb refactoring * chore: code refactor * chore: code refactor * fix: build error * fix: nprogress and button tooltip * chore: code refactor * chore: workspace view breadcrumb improvements * chore: code refactor * chore: code refactor * chore: code refactor * chore: code refactor --------- Co-authored-by: vamsikrishnamathala <matalav55@gmail.com>
This commit is contained in:
parent
64fd0b2830
commit
2b7a17b484
44 changed files with 1251 additions and 581 deletions
|
|
@ -8,7 +8,6 @@ import { DEFAULT_GLOBAL_VIEWS_LIST } from "@plane/constants";
|
|||
// components
|
||||
import { PageHead } from "@/components/core";
|
||||
import { AllIssueLayoutRoot, GlobalViewsAppliedFiltersRoot } from "@/components/issues";
|
||||
import { GlobalViewsHeader } from "@/components/workspace";
|
||||
// constants
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store";
|
||||
|
|
@ -32,7 +31,6 @@ const GlobalViewIssuesPage = observer(() => {
|
|||
<PageHead title={pageTitle} />
|
||||
<div className="h-full overflow-hidden bg-custom-background-100">
|
||||
<div className="flex h-full w-full flex-col border-b border-custom-border-300">
|
||||
<GlobalViewsHeader />
|
||||
{globalViewId && (
|
||||
<GlobalViewsAppliedFiltersRoot globalViewId={globalViewId.toString()} isLoading={isLoading} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -5,32 +5,49 @@ import { observer } from "mobx-react";
|
|||
import { useParams } from "next/navigation";
|
||||
import { Layers } from "lucide-react";
|
||||
// plane constants
|
||||
import { EIssueFilterType, EIssueLayoutTypes, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
|
||||
import {
|
||||
DEFAULT_GLOBAL_VIEWS_LIST,
|
||||
EIssueFilterType,
|
||||
EIssuesStoreType,
|
||||
ISSUE_DISPLAY_FILTERS_BY_PAGE,
|
||||
EIssueLayoutTypes
|
||||
} from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// types
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types";
|
||||
import {
|
||||
ICustomSearchSelectOption,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
} from "@plane/types";
|
||||
// ui
|
||||
import { Breadcrumbs, Button, Header } from "@plane/ui";
|
||||
import { Breadcrumbs, Button, Header, BreadcrumbNavigationSearchDropdown } from "@plane/ui";
|
||||
// components
|
||||
import { isIssueFilterActive } from "@plane/utils";
|
||||
import { BreadcrumbLink } from "@/components/common";
|
||||
import { BreadcrumbLink, SwitcherLabel } from "@/components/common";
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "@/components/issues";
|
||||
import { CreateUpdateWorkspaceViewModal } from "@/components/workspace";
|
||||
import {
|
||||
CreateUpdateWorkspaceViewModal,
|
||||
WorkspaceViewQuickActions,
|
||||
DefaultWorkspaceViewQuickActions,
|
||||
} from "@/components/workspace";
|
||||
// helpers
|
||||
// hooks
|
||||
import { useLabel, useMember, useIssues, useGlobalView } from "@/hooks/store";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { GlobalViewLayoutSelection } from "@/plane-web/components/views/helper";
|
||||
|
||||
export const GlobalIssuesHeader = observer(() => {
|
||||
// states
|
||||
const [createViewModal, setCreateViewModal] = useState(false);
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, globalViewId } = useParams();
|
||||
// store hooks
|
||||
const {
|
||||
issuesFilter: { filters, updateFilters },
|
||||
} = useIssues(EIssuesStoreType.GLOBAL);
|
||||
const { getViewDetailsById } = useGlobalView();
|
||||
const { getViewDetailsById, currentWorkspaceViews } = useGlobalView();
|
||||
const { workspaceLabels } = useLabel();
|
||||
const {
|
||||
workspace: { workspaceMemberIds },
|
||||
|
|
@ -113,6 +130,29 @@ export const GlobalIssuesHeader = observer(() => {
|
|||
|
||||
const isLocked = viewDetails?.is_locked;
|
||||
|
||||
const isDefaultView = DEFAULT_GLOBAL_VIEWS_LIST.find((view) => view.key === globalViewId);
|
||||
|
||||
const defaultViewDetails = DEFAULT_GLOBAL_VIEWS_LIST.find((view) => view.key === globalViewId);
|
||||
|
||||
const defaultOptions = DEFAULT_GLOBAL_VIEWS_LIST.map((view) => ({
|
||||
value: view.key,
|
||||
query: view.key,
|
||||
content: <SwitcherLabel name={t(view.i18n_label)} LabelIcon={Layers} />,
|
||||
}));
|
||||
|
||||
const workspaceOptions = (currentWorkspaceViews || []).map((view) => {
|
||||
const _view = getViewDetailsById(view);
|
||||
if (!_view) return;
|
||||
return {
|
||||
value: _view.id,
|
||||
query: _view.name,
|
||||
content: <SwitcherLabel name={_view.name} LabelIcon={Layers} />,
|
||||
};
|
||||
});
|
||||
|
||||
const switcherOptions = [...defaultOptions, ...workspaceOptions].filter(
|
||||
(option) => option !== undefined
|
||||
) as ICustomSearchSelectOption[];
|
||||
const currentLayoutFilters = useMemo(() => {
|
||||
const layout = activeLayout ?? EIssueLayoutTypes.SPREADSHEET;
|
||||
return ISSUE_DISPLAY_FILTERS_BY_PAGE.my_issues[layout];
|
||||
|
|
@ -124,9 +164,29 @@ export const GlobalIssuesHeader = observer(() => {
|
|||
<Header>
|
||||
<Header.LeftItem>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
type="text"
|
||||
link={<BreadcrumbLink label={t("views")} icon={<Layers className="h-4 w-4 text-custom-text-300" />} />}
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbLink label={t("views")} icon={<Layers className="h-4 w-4 text-custom-text-300" />} />
|
||||
}
|
||||
/>
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbNavigationSearchDropdown
|
||||
selectedItem={globalViewId?.toString() || ""}
|
||||
navigationItems={switcherOptions}
|
||||
onChange={(value: string) => {
|
||||
router.push(`/${workspaceSlug}/workspace-views/${value}`);
|
||||
}}
|
||||
title={viewDetails?.name ?? t(defaultViewDetails?.i18n_label ?? "")}
|
||||
icon={
|
||||
<Breadcrumbs.Icon>
|
||||
<Layers className="size-4 flex-shrink-0 text-custom-text-300" />
|
||||
</Breadcrumbs.Icon>
|
||||
}
|
||||
isLast
|
||||
/>
|
||||
}
|
||||
isLast
|
||||
/>
|
||||
</Breadcrumbs>
|
||||
</Header.LeftItem>
|
||||
|
|
@ -171,6 +231,12 @@ export const GlobalIssuesHeader = observer(() => {
|
|||
<Button variant="primary" size="sm" onClick={() => setCreateViewModal(true)}>
|
||||
{t("workspace_views.add_view")}
|
||||
</Button>
|
||||
<div className="hidden md:block">
|
||||
{viewDetails && <WorkspaceViewQuickActions workspaceSlug={workspaceSlug?.toString()} view={viewDetails} />}
|
||||
{isDefaultView && defaultViewDetails && (
|
||||
<DefaultWorkspaceViewQuickActions workspaceSlug={workspaceSlug?.toString()} view={defaultViewDetails} />
|
||||
)}
|
||||
</div>
|
||||
</Header.RightItem>
|
||||
</Header>
|
||||
</>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue