From 7eeac188d755ea085914af756370117bbbb3dab2 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:01:34 +0530 Subject: [PATCH 1/2] chore: peek overview improvement and bug fixes (#2627) * chore: peekoverview issue properties text size fix * chore: peekoverview icon updated and active view indicator added * chore: peekoverview and issue sidebar improvement --- ...-center-icon.tsx => center-panel-icon.tsx} | 16 ++- ...ek-icon.tsx => full-screen-panel-icon.tsx} | 2 +- packages/ui/src/icons/index.ts | 6 +- ...side-peek-icon.tsx => side-panel-icon.tsx} | 2 +- .../issues/issue-peek-overview/properties.tsx | 44 ++++--- .../issues/issue-peek-overview/view.tsx | 16 ++- .../issues/peek-overview/header.tsx | 12 +- web/components/issues/select/label.tsx | 7 +- .../issues/sidebar-select/cycle.tsx | 68 +++++------ .../issues/sidebar-select/label.tsx | 114 +++--------------- .../issues/sidebar-select/module.tsx | 68 +++++------ .../issues/sidebar-select/state.tsx | 50 ++++---- web/components/issues/sidebar.tsx | 10 +- 13 files changed, 172 insertions(+), 243 deletions(-) rename packages/ui/src/icons/{panel-center-icon.tsx => center-panel-icon.tsx} (50%) rename packages/ui/src/icons/{modal-peek-icon.tsx => full-screen-panel-icon.tsx} (93%) rename packages/ui/src/icons/{side-peek-icon.tsx => side-panel-icon.tsx} (92%) diff --git a/packages/ui/src/icons/panel-center-icon.tsx b/packages/ui/src/icons/center-panel-icon.tsx similarity index 50% rename from packages/ui/src/icons/panel-center-icon.tsx rename to packages/ui/src/icons/center-panel-icon.tsx index 4546474e4..321b61b88 100644 --- a/packages/ui/src/icons/panel-center-icon.tsx +++ b/packages/ui/src/icons/center-panel-icon.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { ISvgIcons } from "./type"; -export const FullScreenPeekIcon: React.FC = ({ +export const CenterPanelIcon: React.FC = ({ className = "text-current", ...rest }) => ( @@ -16,14 +16,18 @@ export const FullScreenPeekIcon: React.FC = ({ > ); diff --git a/packages/ui/src/icons/modal-peek-icon.tsx b/packages/ui/src/icons/full-screen-panel-icon.tsx similarity index 93% rename from packages/ui/src/icons/modal-peek-icon.tsx rename to packages/ui/src/icons/full-screen-panel-icon.tsx index 9df00f54a..da21aca1f 100644 --- a/packages/ui/src/icons/modal-peek-icon.tsx +++ b/packages/ui/src/icons/full-screen-panel-icon.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { ISvgIcons } from "./type"; -export const ModalPeekIcon: React.FC = ({ +export const FullScreenPanelIcon: React.FC = ({ className = "text-current", ...rest }) => ( diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts index 518a4bfad..4cb4e30f7 100644 --- a/packages/ui/src/icons/index.ts +++ b/packages/ui/src/icons/index.ts @@ -9,9 +9,9 @@ export * from "./subscribe-icon"; export * from "./external-link-icon"; export * from "./copy-icon"; export * from "./layer-stack"; -export * from "./side-peek-icon"; -export * from "./modal-peek-icon"; -export * from "./panel-center-icon"; +export * from "./side-panel-icon"; +export * from "./center-panel-icon"; +export * from "./full-screen-panel-icon"; export * from "./priority-icon"; export * from "./state"; export * from "./blocked-icon"; diff --git a/packages/ui/src/icons/side-peek-icon.tsx b/packages/ui/src/icons/side-panel-icon.tsx similarity index 92% rename from packages/ui/src/icons/side-peek-icon.tsx rename to packages/ui/src/icons/side-panel-icon.tsx index de4103a1a..8185da768 100644 --- a/packages/ui/src/icons/side-peek-icon.tsx +++ b/packages/ui/src/icons/side-panel-icon.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { ISvgIcons } from "./type"; -export const SidePeekIcon: React.FC = ({ +export const SidePanelIcon: React.FC = ({ className = "text-current", ...rest }) => ( diff --git a/web/components/issues/issue-peek-overview/properties.tsx b/web/components/issues/issue-peek-overview/properties.tsx index d1d609f7b..8de442aa0 100644 --- a/web/components/issues/issue-peek-overview/properties.tsx +++ b/web/components/issues/issue-peek-overview/properties.tsx @@ -24,7 +24,7 @@ import useToast from "hooks/use-toast"; import { CustomDatePicker } from "components/ui"; import { LinkModal, LinksList } from "components/core"; // types -import { ICycle, IIssue, IIssueLink, IModule, TIssuePriorities, linkDetails } from "types"; +import { IIssue, IIssueLink, TIssuePriorities, linkDetails } from "types"; import { ISSUE_DETAILS } from "constants/fetch-keys"; // services import { IssueService } from "services/issue"; @@ -42,7 +42,7 @@ export const PeekOverviewProperties: FC = observer((pro const [linkModal, setLinkModal] = useState(false); const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState(null); - const { user: userStore } = useMobxStore(); + const { user: userStore, cycleIssue: cycleIssueStore, moduleIssue: moduleIssueStore } = useMobxStore(); const userRole = userStore.currentProjectRole; const router = useRouter(); @@ -71,11 +71,15 @@ export const PeekOverviewProperties: FC = observer((pro const handleParent = (_parent: string) => { issueUpdate({ ...issue, parent: _parent }); }; - const handleCycle = (_cycle: ICycle) => { - issueUpdate({ ...issue, cycle: _cycle.id }); + const addIssueToCycle = async (cycleId: string) => { + if (!workspaceSlug || !issue || !cycleId) return; + cycleIssueStore.addIssueToCycle(workspaceSlug.toString(), issue.project_detail.id, cycleId, issue.id); }; - const handleModule = (_module: IModule) => { - issueUpdate({ ...issue, module: _module.id }); + + const addIssueToModule = async (moduleId: string) => { + if (!workspaceSlug || !issue || !moduleId) return; + + moduleIssueStore.addIssueToModule(workspaceSlug.toString(), issue.project_detail.id, moduleId, issue.id); }; const handleLabels = (formData: Partial) => { issueUpdate({ ...issue, ...formData }); @@ -187,7 +191,7 @@ export const PeekOverviewProperties: FC = observer((pro
{/* state */}
-
+

State

@@ -198,7 +202,7 @@ export const PeekOverviewProperties: FC = observer((pro {/* assignee */}
-
+

Assignees

@@ -209,7 +213,7 @@ export const PeekOverviewProperties: FC = observer((pro {/* priority */}
-
+

Priority

@@ -220,7 +224,7 @@ export const PeekOverviewProperties: FC = observer((pro {/* estimate */}
-
+

Estimate

@@ -231,7 +235,7 @@ export const PeekOverviewProperties: FC = observer((pro {/* start date */}
-
+

Start date

@@ -249,7 +253,7 @@ export const PeekOverviewProperties: FC = observer((pro {/* due date */}
-
+

Due date

@@ -267,7 +271,7 @@ export const PeekOverviewProperties: FC = observer((pro {/* parent */}
-
+

Parent

@@ -281,26 +285,26 @@ export const PeekOverviewProperties: FC = observer((pro
-
+

Cycle

- +
-
+

Module

- +
-
+

Label

@@ -321,8 +325,8 @@ export const PeekOverviewProperties: FC = observer((pro
-
- +
+

Links

diff --git a/web/components/issues/issue-peek-overview/view.tsx b/web/components/issues/issue-peek-overview/view.tsx index 83eb7737a..95ab28f2a 100644 --- a/web/components/issues/issue-peek-overview/view.tsx +++ b/web/components/issues/issue-peek-overview/view.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; import { PeekOverviewIssueDetails } from "./issue-detail"; import { PeekOverviewProperties } from "./properties"; import { IssueComment } from "./activity"; -import { Button, CustomSelect, FullScreenPeekIcon, ModalPeekIcon, SidePeekIcon } from "@plane/ui"; +import { Button, CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon } from "@plane/ui"; import { DeleteIssueModal } from "../delete-issue-modal"; // types import { IIssue } from "types"; @@ -41,17 +41,17 @@ type TPeekModes = "side-peek" | "modal" | "full-screen"; const peekOptions: { key: TPeekModes; icon: any; title: string }[] = [ { key: "side-peek", - icon: SidePeekIcon, + icon: SidePanelIcon, title: "Side Peek", }, { key: "modal", - icon: ModalPeekIcon, + icon: CenterPanelIcon, title: "Modal", }, { key: "full-screen", - icon: FullScreenPeekIcon, + icon: FullScreenPanelIcon, title: "Full Screen", }, ]; @@ -206,7 +206,13 @@ export const IssueView: FC = observer((props) => { > {peekOptions.map((mode) => ( -
+
{mode.title}
diff --git a/web/components/issues/peek-overview/header.tsx b/web/components/issues/peek-overview/header.tsx index d271533af..55586ddf8 100644 --- a/web/components/issues/peek-overview/header.tsx +++ b/web/components/issues/peek-overview/header.tsx @@ -3,9 +3,9 @@ import Link from "next/link"; // hooks import useToast from "hooks/use-toast"; // ui -import { CustomSelect, FullScreenPeekIcon, ModalPeekIcon, SidePeekIcon } from "@plane/ui"; +import { CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon } from "@plane/ui"; // icons -import { LinkIcon, MoveRight, Trash2 } from "lucide-react"; +import { LinkIcon, MoveDiagonal, MoveRight, Trash2 } from "lucide-react"; // helpers import { copyTextToClipboard } from "helpers/string.helper"; // types @@ -26,15 +26,15 @@ const peekModes: { icon: any; label: string; }[] = [ - { key: "side", icon: SidePeekIcon, label: "Side Peek" }, + { key: "side", icon: SidePanelIcon, label: "Side Peek" }, { key: "modal", - icon: ModalPeekIcon, + icon: CenterPanelIcon, label: "Modal Peek", }, { key: "full", - icon: FullScreenPeekIcon, + icon: FullScreenPanelIcon, label: "Full Screen Peek", }, ]; @@ -73,7 +73,7 @@ export const PeekOverviewHeader: React.FC = ({ )} - + void; projectId: string; + label?: JSX.Element; }; const issueLabelService = new IssueLabelService(); -export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, projectId }) => { +export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, projectId, label }) => { // states const [query, setQuery] = useState(""); @@ -56,7 +57,9 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, ref={setReferenceElement} className="flex items-center gap-2 cursor-pointer text-xs text-custom-text-200" > - {value && value.length > 0 ? ( + {label ? ( + label + ) : value && value.length > 0 ? ( issueLabels?.find((l) => l.id === v)) ?? []} diff --git a/web/components/issues/sidebar-select/cycle.tsx b/web/components/issues/sidebar-select/cycle.tsx index 5f4ef6e13..ff37cc68f 100644 --- a/web/components/issues/sidebar-select/cycle.tsx +++ b/web/components/issues/sidebar-select/cycle.tsx @@ -8,17 +8,15 @@ import useSWR, { mutate } from "swr"; import { IssueService } from "services/issue"; import { CycleService } from "services/cycle.service"; // ui -import { CustomSelect, Spinner, Tooltip } from "@plane/ui"; -// helper -import { truncateText } from "helpers/string.helper"; +import { ContrastIcon, CustomSearchSelect, Tooltip } from "@plane/ui"; // types -import { ICycle, IIssue } from "types"; +import { IIssue } from "types"; // fetch-keys import { CYCLE_ISSUES, INCOMPLETE_CYCLES_LIST, ISSUE_DETAILS } from "constants/fetch-keys"; type Props = { issueDetail: IIssue | undefined; - handleCycleChange: (cycle: ICycle) => void; + handleCycleChange: (cycleId: string) => void; disabled?: boolean; }; @@ -52,10 +50,30 @@ export const SidebarCycleSelect: React.FC = ({ issueDetail, handleCycleCh }); }; + const options = incompleteCycles?.map((cycle) => ({ + value: cycle.id, + query: cycle.name, + content: ( +
+ + + + {cycle.name} +
+ ), + })); + const issueCycle = issueDetail?.issue_cycle; return ( - { + value === issueCycle?.cycle_detail.id + ? removeIssueFromCycle(issueCycle?.id ?? "", issueCycle?.cycle ?? "") + : handleCycleChange(value); + }} + options={options} customButton={
@@ -65,41 +83,21 @@ export const SidebarCycleSelect: React.FC = ({ issueDetail, handleCycleCh disabled ? "cursor-not-allowed" : "" }`} > - + + {issueCycle && } {issueCycle ? issueCycle.cycle_detail.name : "No cycle"}
} - value={issueCycle ? issueCycle.cycle_detail.id : null} - onChange={(value: any) => { - !value - ? removeIssueFromCycle(issueCycle?.id ?? "", issueCycle?.cycle ?? "") - : handleCycleChange(incompleteCycles?.find((c) => c.id === value) as ICycle); - }} - width="w-full" - maxHeight="rg" + width="max-w-[10rem]" + noChevron disabled={disabled} - > - {incompleteCycles ? ( - incompleteCycles.length > 0 ? ( - <> - {incompleteCycles.map((option) => ( - - - {truncateText(option.name, 25)} - - - ))} - None - - ) : ( -
No cycles found
- ) - ) : ( - - )} -
+ /> ); }; diff --git a/web/components/issues/sidebar-select/label.tsx b/web/components/issues/sidebar-select/label.tsx index 6cd0cff2a..464554aec 100644 --- a/web/components/issues/sidebar-select/label.tsx +++ b/web/components/issues/sidebar-select/label.tsx @@ -4,15 +4,16 @@ import useSWR from "swr"; import { Controller, useForm } from "react-hook-form"; import { TwitterPicker } from "react-color"; // headless ui -import { Listbox, Popover, Transition } from "@headlessui/react"; +import { Popover, Transition } from "@headlessui/react"; // services import { IssueLabelService } from "services/issue"; // hooks import useUser from "hooks/use-user"; // ui -import { Input, Spinner } from "@plane/ui"; +import { Input } from "@plane/ui"; +import { IssueLabelSelect } from "../select"; // icons -import { Component, Plus, X } from "lucide-react"; +import { Plus, X } from "lucide-react"; // types import { IIssue, IIssueLabels } from "types"; // fetch-keys @@ -117,102 +118,21 @@ export const SidebarLabelSelect: React.FC = ({
); })} - submitChanges({ labels: val })} - className="flex-shrink-0" - multiple - disabled={isNotAllowed || uneditable} - > - {({ open }) => ( -
- - Select Label - - - - -
- {issueLabels ? ( - issueLabels.length > 0 ? ( - issueLabels.map((label: IIssueLabels) => { - const children = issueLabels?.filter((l) => l.parent === label.id); - - if (children.length === 0) { - if (!label.parent) - return ( - - `${active || selected ? "bg-custom-background-90" : ""} ${ - selected ? "" : "text-custom-text-200" - } flex cursor-pointer select-none items-center gap-2 truncate p-2` - } - value={label.id} - > - - {label.name} - - ); - } else - return ( -
-
- - {label.name} -
-
- {children.map((child) => ( - - `${active || selected ? "bg-custom-background-100" : ""} ${ - selected ? "" : "text-custom-text-200" - } flex cursor-pointer select-none items-center gap-2 truncate p-2` - } - value={child.id} - > - - {child.name} - - ))} -
-
- ); - }) - ) : ( -
No labels found
- ) - ) : ( - - )} -
-
-
-
- )} -
+ projectId={issueDetails?.project_detail.id ?? ""} + label={ + + Select Label + + } + /> {!isNotAllowed && (
} - value={issueModule ? issueModule.module_detail?.id : null} - onChange={(value: any) => { - !value - ? removeIssueFromModule(issueModule?.id ?? "", issueModule?.module ?? "") - : handleModuleChange(modules?.find((m) => m.id === value) as IModule); - }} - width="w-full" - maxHeight="rg" + width="max-w-[10rem]" + noChevron disabled={disabled} - > - {modules ? ( - modules.length > 0 ? ( - <> - {modules.map((option) => ( - - - {truncateText(option.name, 25)} - - - ))} - None - - ) : ( -
No modules found
- ) - ) : ( - - )} - + /> ); }; diff --git a/web/components/issues/sidebar-select/state.tsx b/web/components/issues/sidebar-select/state.tsx index 730da4b5b..a109ddab9 100644 --- a/web/components/issues/sidebar-select/state.tsx +++ b/web/components/issues/sidebar-select/state.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; // services import { ProjectStateService } from "services/project"; // ui -import { CustomSelect, Spinner, StateGroupIcon } from "@plane/ui"; +import { CustomSearchSelect, StateGroupIcon } from "@plane/ui"; // helpers import { getStatesList } from "helpers/state.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper"; @@ -33,16 +33,30 @@ export const SidebarStateSelect: React.FC = ({ value, onChange, disabled ); const states = getStatesList(stateGroups); - const selectedState = states?.find((s) => s.id === value); + const selectedOption = states?.find((s) => s.id === value); + + const options = states?.map((state) => ({ + value: state.id, + query: state.name, + content: ( +
+ + {state.name} +
+ ), + })); return ( - - {selectedState ? ( + {selectedOption ? (
- - {addSpaceIfCamelCase(selectedState?.name ?? "")} + + {addSpaceIfCamelCase(selectedOption?.name ?? "")}
) : inboxIssueId ? (
@@ -54,27 +68,9 @@ export const SidebarStateSelect: React.FC = ({ value, onChange, disabled )}
} - value={value} - onChange={onChange} - optionsClassName="w-min" + width="min-w-[10rem]" + noChevron disabled={disabled} - > - {states ? ( - states.length > 0 ? ( - states.map((state) => ( - - <> - - {state.name} - - - )) - ) : ( -
No states found
- ) - ) : ( - - )} -
+ /> ); }; diff --git a/web/components/issues/sidebar.tsx b/web/components/issues/sidebar.tsx index 5ce7ff59a..3ef335309 100644 --- a/web/components/issues/sidebar.tsx +++ b/web/components/issues/sidebar.tsx @@ -37,7 +37,7 @@ import { ContrastIcon, DiceIcon, DoubleCircleIcon, UserGroupIcon } from "@plane/ // helpers import { copyTextToClipboard } from "helpers/string.helper"; // types -import type { ICycle, IIssue, IIssueLink, linkDetails, IModule } from "types"; +import type { IIssue, IIssueLink, linkDetails } from "types"; // fetch-keys import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; @@ -97,14 +97,14 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { const { setToastAlert } = useToast(); const handleCycleChange = useCallback( - (cycleDetails: ICycle) => { + (cycleId: string) => { if (!workspaceSlug || !projectId || !issueDetail || !user) return; issueService .addIssueToCycle( workspaceSlug as string, projectId as string, - cycleDetails.id, + cycleId, { issues: [issueDetail.id], }, @@ -118,14 +118,14 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { ); const handleModuleChange = useCallback( - (moduleDetail: IModule) => { + (moduleId: string) => { if (!workspaceSlug || !projectId || !issueDetail || !user) return; moduleService .addIssuesToModule( workspaceSlug as string, projectId as string, - moduleDetail.id, + moduleId, { issues: [issueDetail.id], }, From 8919b724c5bdf5eb33792b60e4eeaa018d1cac15 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:01:49 +0530 Subject: [PATCH 2/2] chore: breadcrumbs ui revamp and refactor (#2634) --- packages/ui/src/breadcrumbs/breadcrumbs.tsx | 112 +++++++++++------- web/components/headers/cycle-issues.tsx | 79 +++++++----- web/components/headers/cycles.tsx | 35 ++++-- web/components/headers/global-issues.tsx | 21 +++- web/components/headers/module-issues.tsx | 78 +++++++----- web/components/headers/modules-list.tsx | 35 ++++-- web/components/headers/page-details.tsx | 92 ++++++++++++++ web/components/headers/pages.tsx | 44 ++++--- .../headers/profile-preferences.tsx | 29 ++--- .../project-archived-issue-details.tsx | 50 +++++--- .../headers/project-archived-issues.tsx | 41 ++++--- .../headers/project-draft-issues.tsx | 42 ++++--- web/components/headers/project-inbox.tsx | 42 ++++--- .../headers/project-issue-details.tsx | 48 +++++--- web/components/headers/project-issues.tsx | 50 +++++--- web/components/headers/project-settings.tsx | 30 +++-- .../headers/project-view-issues.tsx | 87 ++++++++------ web/components/headers/project-views.tsx | 44 ++++--- web/components/headers/projects.tsx | 18 ++- web/components/headers/user-profile.tsx | 23 +++- .../headers/workspace-analytics.tsx | 12 +- web/components/headers/workspace-settings.tsx | 35 ++---- .../profile/[userId]/assigned.tsx | 2 +- .../profile/[userId]/created.tsx | 2 +- .../profile/[userId]/index.tsx | 2 +- .../profile/[userId]/subscribed.tsx | 2 +- .../projects/[projectId]/pages/[pageId].tsx | 4 +- 27 files changed, 672 insertions(+), 387 deletions(-) create mode 100644 web/components/headers/page-details.tsx diff --git a/packages/ui/src/breadcrumbs/breadcrumbs.tsx b/packages/ui/src/breadcrumbs/breadcrumbs.tsx index 41fe14739..94f317825 100644 --- a/packages/ui/src/breadcrumbs/breadcrumbs.tsx +++ b/packages/ui/src/breadcrumbs/breadcrumbs.tsx @@ -1,59 +1,81 @@ import * as React from "react"; // icons -import { MoveLeft } from "lucide-react"; +import { ChevronRight } from "lucide-react"; +// components +import { Tooltip } from "../tooltip"; type BreadcrumbsProps = { - onBack: () => void; children: any; }; -const Breadcrumbs = ({ onBack, children }: BreadcrumbsProps) => ( - <> -
- - {children} -
- -); - -type BreadcrumbItemProps = { - title?: string; - link?: JSX.Element; - icon?: any; - unshrinkTitle?: boolean; -}; - -const BreadcrumbItem: React.FC = ({ - title, - link, - icon, - unshrinkTitle = false, -}) => ( - <> - {link ? ( - link - ) : ( -
-

- {icon} - {title} -

+const Breadcrumbs = ({ children }: BreadcrumbsProps) => ( +
+ {React.Children.map(children, (child, index) => ( +
+ {child} + {index !== React.Children.count(children) - 1 && ( +
- )} - + ))} +
); +type Props = { + type?: "text" | "component"; + component?: React.ReactNode; + label?: string; + icon?: React.ReactNode; + link?: string; +}; +const BreadcrumbItem: React.FC = (props) => { + const { type = "text", component, label, icon, link } = props; + return ( + <> + {type != "text" ? ( +
{component}
+ ) : ( + +
  • +
    + {link ? ( + + {icon && ( +
    + {icon} +
    + )} +
    + {label} +
    +
    + ) : ( +
    + {icon && ( +
    + {icon} +
    + )} +
    + {label} +
    +
    + )} +
    +
  • +
    + )} + + ); +}; + Breadcrumbs.BreadcrumbItem = BreadcrumbItem; export { Breadcrumbs, BreadcrumbItem }; diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx index cfadc80aa..4106f443b 100644 --- a/web/components/headers/cycle-issues.tsx +++ b/web/components/headers/cycle-issues.tsx @@ -1,6 +1,5 @@ import { useCallback, useState } from "react"; import { useRouter } from "next/router"; -import Link from "next/link"; import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; @@ -10,11 +9,12 @@ import useLocalStorage from "hooks/use-local-storage"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; import { ProjectAnalyticsModal } from "components/analytics"; // ui -import { Breadcrumbs, Button, CustomMenu } from "@plane/ui"; +import { Breadcrumbs, Button, ContrastIcon, CustomMenu } from "@plane/ui"; // icons -import { ArrowRight, ContrastIcon, Plus } from "lucide-react"; +import { ArrowRight, Plus } from "lucide-react"; // helpers import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types"; // constants @@ -32,6 +32,8 @@ export const CycleIssuesHeader: React.FC = observer(() => { cycleIssueFilter: cycleIssueFilterStore, project: projectStore, } = useMobxStore(); + const { currentProjectDetails } = projectStore; + const activeLayout = issueFilterStore.userDisplayFilters.layout; const { setValue, storedValue } = useLocalStorage("cycle_sidebar_collapsed", "false"); @@ -110,36 +112,55 @@ export const CycleIssuesHeader: React.FC = observer(() => { />
    - router.back()}> + - -

    {`${truncateText(cycleDetails?.project_detail.name ?? "", 32)} Cycles`}

    -
    - + type="text" + icon={ + currentProjectDetails?.emoji ? ( + renderEmoji(currentProjectDetails.emoji) + ) : currentProjectDetails?.icon_prop ? ( + renderEmoji(currentProjectDetails.icon_prop) + ) : ( + + {currentProjectDetails?.name.charAt(0)} + + ) + } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Cycles" + link={`/${workspaceSlug}/projects/${projectId}/cycles`} + /> + + + {cycleDetails?.name && truncateText(cycleDetails.name, 40)} + + } + className="ml-1.5 flex-shrink-0" + width="auto" + > + {cyclesList?.map((cycle) => ( + router.push(`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`)} + > + {truncateText(cycle.name, 40)} + + ))} + } />
    - - - {cycleDetails?.name && truncateText(cycleDetails.name, 40)} - - } - className="ml-1.5 flex-shrink-0" - width="auto" - > - {cyclesList?.map((cycle) => ( - router.push(`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`)} - > - {truncateText(cycle.name, 40)} - - ))} -
    = (props) => { @@ -25,17 +25,28 @@ export const CyclesHeader: FC = (props) => { >
    - router.back()}> - - -

    Projects

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) } + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Cycles" /> -
    diff --git a/web/components/headers/global-issues.tsx b/web/components/headers/global-issues.tsx index 43d615d84..7c41ba327 100644 --- a/web/components/headers/global-issues.tsx +++ b/web/components/headers/global-issues.tsx @@ -10,9 +10,9 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "components/issues"; import { CreateUpdateWorkspaceViewModal } from "components/workspace"; // ui -import { Button, Tooltip } from "@plane/ui"; +import { Breadcrumbs, Button, LayersIcon, PhotoFilterIcon, Tooltip } from "@plane/ui"; // icons -import { CheckCircle, List, PlusIcon, Sheet } from "lucide-react"; +import { List, PlusIcon, Sheet } from "lucide-react"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TStaticViewTypes } from "types"; // constants @@ -99,9 +99,20 @@ export const GlobalIssuesHeader: React.FC = observer((props) => { <> setCreateViewModal(false)} />
    -
    - {activeLayout === "spreadsheet" && } - Workspace {activeLayout === "spreadsheet" ? "Issues" : "Views"} +
    + + + ) : ( + + ) + } + label={`Workspace ${activeLayout === "spreadsheet" ? "Issues" : "Views"}`} + /> +
    diff --git a/web/components/headers/module-issues.tsx b/web/components/headers/module-issues.tsx index 0fd143e61..42c01d531 100644 --- a/web/components/headers/module-issues.tsx +++ b/web/components/headers/module-issues.tsx @@ -1,6 +1,5 @@ import { useCallback, useState } from "react"; import { useRouter } from "next/router"; -import Link from "next/link"; import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; @@ -10,11 +9,12 @@ import useLocalStorage from "hooks/use-local-storage"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; import { ProjectAnalyticsModal } from "components/analytics"; // ui -import { Breadcrumbs, Button, CustomMenu } from "@plane/ui"; +import { Breadcrumbs, Button, CustomMenu, DiceIcon } from "@plane/ui"; // icons import { ArrowRight, ContrastIcon, Plus } from "lucide-react"; // helpers import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types"; // constants @@ -33,6 +33,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => { project: projectStore, } = useMobxStore(); const activeLayout = issueFilterStore.userDisplayFilters.layout; + const { currentProjectDetails } = projectStore; const { setValue, storedValue } = useLocalStorage("module_sidebar_collapsed", "false"); @@ -110,39 +111,54 @@ export const ModuleIssuesHeader: React.FC = observer(() => { />
    - router.back()}> + - -

    {`${truncateText( - moduleDetails?.project_detail.name ?? "", - 32 - )} Modules`}

    -
    - + type="text" + icon={ + currentProjectDetails?.emoji ? ( + renderEmoji(currentProjectDetails.emoji) + ) : currentProjectDetails?.icon_prop ? ( + renderEmoji(currentProjectDetails.icon_prop) + ) : ( + + {currentProjectDetails?.name.charAt(0)} + + ) + } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Modules" + link={`/${workspaceSlug}/projects/${projectId}/modules`} + /> + + + {moduleDetails?.name && truncateText(moduleDetails.name, 40)} + + } + className="ml-1.5 flex-shrink-0" + width="auto" + > + {modulesList?.map((module) => ( + router.push(`/${workspaceSlug}/projects/${projectId}/modules/${module.id}`)} + > + {truncateText(module.name, 40)} + + ))} + } />
    - - - {moduleDetails?.name && truncateText(moduleDetails.name, 40)} - - } - className="ml-1.5 flex-shrink-0" - width="auto" - > - {modulesList?.map((module) => ( - router.push(`/${workspaceSlug}/projects/${projectId}/modules/${module.id}`)} - > - {truncateText(module.name, 40)} - - ))} -
    { >
    - router.back()}> - - -

    Projects

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) } + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Modules" /> -
    diff --git a/web/components/headers/page-details.tsx b/web/components/headers/page-details.tsx new file mode 100644 index 000000000..8b9fa433d --- /dev/null +++ b/web/components/headers/page-details.tsx @@ -0,0 +1,92 @@ +import { FC } from "react"; +import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; +import { FileText, Plus } from "lucide-react"; +// services +import { PageService } from "services/page.service"; + +// constants +import { PAGE_DETAILS } from "constants/fetch-keys"; + +// hooks +import { useMobxStore } from "lib/mobx/store-provider"; +// ui +import { Breadcrumbs, Button } from "@plane/ui"; +// helper +import { renderEmoji } from "helpers/emoji.helper"; + +import useSWR from "swr"; + +export interface IPagesHeaderProps { + showButton?: boolean; +} +const pageService = new PageService(); + +export const PageDetailsHeader: FC = observer((props) => { + const { showButton = false } = props; + const router = useRouter(); + const { workspaceSlug, pageId } = router.query; + + const { project: projectStore } = useMobxStore(); + const { currentProjectDetails } = projectStore; + + const { data: pageDetails } = useSWR( + workspaceSlug && currentProjectDetails?.id && pageId ? PAGE_DETAILS(pageId as string) : null, + workspaceSlug && currentProjectDetails?.id + ? () => pageService.getPageDetails(workspaceSlug as string, currentProjectDetails.id, pageId as string) + : null + ); + + return ( +
    +
    +
    + + + {currentProjectDetails?.name.charAt(0)} + + ) + } + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Pages" + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages`} + /> + } + label={pageDetails?.name ?? "Page"} + /> + +
    +
    + {showButton && ( +
    + +
    + )} +
    + ); +}); diff --git a/web/components/headers/pages.tsx b/web/components/headers/pages.tsx index f30c03fbb..634dd0c38 100644 --- a/web/components/headers/pages.tsx +++ b/web/components/headers/pages.tsx @@ -1,14 +1,13 @@ import { FC } from "react"; -import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; -import { Plus } from "lucide-react"; +import { FileText, Plus } from "lucide-react"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; // ui -import { Breadcrumbs, BreadcrumbItem, Button } from "@plane/ui"; +import { Breadcrumbs, Button } from "@plane/ui"; // helper -import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; export interface IPagesHeaderProps { showButton?: boolean; @@ -17,30 +16,37 @@ export interface IPagesHeaderProps { export const PagesHeader: FC = observer((props) => { const { showButton = false } = props; const router = useRouter(); - const { workspaceSlug, projectId } = router.query; + const { workspaceSlug } = router.query; const { project: projectStore } = useMobxStore(); - - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; + const { currentProjectDetails } = projectStore; return (
    - router.back()}> - - -

    Projects

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) } + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Pages" /> -
    diff --git a/web/components/headers/profile-preferences.tsx b/web/components/headers/profile-preferences.tsx index ae5ad8811..cde226fd7 100644 --- a/web/components/headers/profile-preferences.tsx +++ b/web/components/headers/profile-preferences.tsx @@ -1,21 +1,16 @@ -import { useRouter } from "next/router"; // components -import { BreadcrumbItem, Breadcrumbs } from "@plane/ui"; +import { Breadcrumbs } from "@plane/ui"; -export const ProfilePreferencesHeader = () => { - const router = useRouter(); - - return ( -
    -
    -
    - router.back()}> - - -
    +export const ProfilePreferencesHeader = () => ( +
    +
    +
    + + +
    - ); -}; +
    +); diff --git a/web/components/headers/project-archived-issue-details.tsx b/web/components/headers/project-archived-issue-details.tsx index 8c659431e..be8b5cebe 100644 --- a/web/components/headers/project-archived-issue-details.tsx +++ b/web/components/headers/project-archived-issue-details.tsx @@ -1,20 +1,19 @@ import { FC } from "react"; import useSWR from "swr"; -import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; // ui -import { Breadcrumbs, BreadcrumbItem } from "@plane/ui"; -// helper -import { truncateText } from "helpers/string.helper"; +import { Breadcrumbs, LayersIcon } from "@plane/ui"; // types import { IIssue } from "types"; // constants import { ISSUE_DETAILS } from "constants/fetch-keys"; // services import { IssueArchiveService } from "services/issue"; +// helpers +import { renderEmoji } from "helpers/emoji.helper"; const issueArchiveService = new IssueArchiveService(); @@ -24,10 +23,7 @@ export const ProjectArchivedIssueDetailsHeader: FC = observer(() => { const { project: projectStore } = useMobxStore(); - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; + const { currentProjectDetails } = projectStore; const { data: issueDetails } = useSWR( workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId as string) : null, @@ -45,17 +41,35 @@ export const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
    - router.back()}> - - -

    {`${truncateText( - issueDetails?.project_detail.name ?? "Project", - 32 - )} Issues`}

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) + } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects`} + /> - + } + label="Archived Issues" + link={`/${workspaceSlug}/projects/${projectId}/archived-issues`} + /> + +
    diff --git a/web/components/headers/project-archived-issues.tsx b/web/components/headers/project-archived-issues.tsx index a40ab9e60..82dffa2c3 100644 --- a/web/components/headers/project-archived-issues.tsx +++ b/web/components/headers/project-archived-issues.tsx @@ -1,37 +1,48 @@ import { FC } from "react"; -import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; // ui -import { Breadcrumbs, BreadcrumbItem } from "@plane/ui"; +import { Breadcrumbs, LayersIcon } from "@plane/ui"; // helper -import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; export const ProjectArchivedIssuesHeader: FC = observer(() => { const router = useRouter(); - const { workspaceSlug, projectId } = router.query; + const { workspaceSlug } = router.query; const { project: projectStore } = useMobxStore(); - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; + const { currentProjectDetails } = projectStore; return (
    - router.back()}> - - -

    Projects

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) + } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects`} + /> - + } + label="Archived Issues" + />
    diff --git a/web/components/headers/project-draft-issues.tsx b/web/components/headers/project-draft-issues.tsx index 125dccadd..0ab1603be 100644 --- a/web/components/headers/project-draft-issues.tsx +++ b/web/components/headers/project-draft-issues.tsx @@ -1,41 +1,47 @@ import { FC } from "react"; -import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; // ui -import { Breadcrumbs, BreadcrumbItem } from "@plane/ui"; +import { Breadcrumbs, LayersIcon } from "@plane/ui"; // helper -import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; export const ProjectDraftIssueHeader: FC = observer(() => { const router = useRouter(); - const { workspaceSlug, projectId } = router.query; + const { workspaceSlug } = router.query; const { project: projectStore } = useMobxStore(); - - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; + const { currentProjectDetails } = projectStore; return (
    - router.back()}> - - -

    Projects

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects`} /> - + } + label="Draft Issues" + />
    diff --git a/web/components/headers/project-inbox.tsx b/web/components/headers/project-inbox.tsx index 20eb67211..5098c69b9 100644 --- a/web/components/headers/project-inbox.tsx +++ b/web/components/headers/project-inbox.tsx @@ -1,44 +1,52 @@ import { FC, useState } from "react"; -import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { Plus } from "lucide-react"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; // ui -import { Breadcrumbs, BreadcrumbItem, Button } from "@plane/ui"; +import { Breadcrumbs, Button, LayersIcon } from "@plane/ui"; // components import { CreateInboxIssueModal } from "components/inbox"; // helper -import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; export const ProjectInboxHeader: FC = observer(() => { const router = useRouter(); - const { workspaceSlug, projectId } = router.query; + const { workspaceSlug } = router.query; const [createIssueModal, setCreateIssueModal] = useState(false); const { project: projectStore } = useMobxStore(); - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; + const { currentProjectDetails } = projectStore; return (
    - router.back()}> - - -

    Projects

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects`} + /> + + } + label="Inbox Issues" /> -
    diff --git a/web/components/headers/project-issue-details.tsx b/web/components/headers/project-issue-details.tsx index 2728919b2..9fce63575 100644 --- a/web/components/headers/project-issue-details.tsx +++ b/web/components/headers/project-issue-details.tsx @@ -1,17 +1,17 @@ import { FC } from "react"; import useSWR from "swr"; -import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; // ui -import { Breadcrumbs } from "@plane/ui"; +import { Breadcrumbs, LayersIcon } from "@plane/ui"; // helper -import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; // services import { IssueService } from "services/issue"; // constants import { ISSUE_DETAILS } from "constants/fetch-keys"; +import { useMobxStore } from "lib/mobx/store-provider"; // services const issueService = new IssueService(); @@ -20,6 +20,10 @@ export const ProjectIssueDetailsHeader: FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; + const { project: projectStore } = useMobxStore(); + + const { currentProjectDetails } = projectStore; + const { data: issueDetails } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null, workspaceSlug && projectId && issueId @@ -31,24 +35,34 @@ export const ProjectIssueDetailsHeader: FC = observer(() => {
    - router.back()}> + - -

    {`${truncateText( - issueDetails?.project_detail.name ?? "Project", - 32 - )} Issues`}

    -
    - + type="text" + icon={ + currentProjectDetails?.emoji ? ( + renderEmoji(currentProjectDetails.emoji) + ) : currentProjectDetails?.icon_prop ? ( + renderEmoji(currentProjectDetails.icon_prop) + ) : ( + + {currentProjectDetails?.name.charAt(0)} + + ) } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects`} /> + } + label="Issues" + link={`/${workspaceSlug}/projects/${projectId}/issues`} + /> + +
    diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index 55e44173a..f9bf6ec58 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -9,13 +9,13 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; import { ProjectAnalyticsModal } from "components/analytics"; // ui -import { Breadcrumbs, BreadcrumbItem, Button } from "@plane/ui"; +import { Breadcrumbs, Button, LayersIcon } from "@plane/ui"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types"; // constants import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; // helper -import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; export const ProjectIssuesHeader: React.FC = observer(() => { const [analyticsModal, setAnalyticsModal] = useState(false); @@ -85,11 +85,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => { }, [issueFilterStore, projectId, workspaceSlug] ); - - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; + const { currentProjectDetails } = projectStore; const inboxDetails = projectId ? inboxStore.inboxesList?.[projectId.toString()]?.[0] : undefined; @@ -100,7 +96,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => { setAnalyticsModal(false)} - projectDetails={projectDetails ?? undefined} + projectDetails={currentProjectDetails ?? undefined} />
    @@ -114,22 +110,38 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
    - router.back()}> - - -

    Projects

    -
    - + + + {renderEmoji(currentProjectDetails.emoji)} + + ) : currentProjectDetails?.icon_prop ? ( +
    + {renderEmoji(currentProjectDetails.icon_prop)} +
    + ) : ( + + {currentProjectDetails?.name.charAt(0)} + + ) } + label={currentProjectDetails?.name ?? "Project"} + link={`/${workspaceSlug}/projects`} + /> + + } + label="Issues" /> -
    - {projectDetails?.is_deployed && deployUrl && ( + {currentProjectDetails?.is_deployed && deployUrl && ( = observer((props) >
    - router.back()}> - - -

    {`${truncateText(currentProjectDetails?.name ?? "Project", 32)}`}

    -
    - + + + {currentProjectDetails?.name.charAt(0)} + + ) } + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} /> - +
    diff --git a/web/components/headers/project-view-issues.tsx b/web/components/headers/project-view-issues.tsx index 862b3b869..50d97505c 100644 --- a/web/components/headers/project-view-issues.tsx +++ b/web/components/headers/project-view-issues.tsx @@ -1,5 +1,4 @@ import { useCallback } from "react"; -import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; // mobx store @@ -7,9 +6,10 @@ import { useMobxStore } from "lib/mobx/store-provider"; // components import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; // ui -import { BreadcrumbItem, Breadcrumbs, CustomMenu, PhotoFilterIcon } from "@plane/ui"; +import { Breadcrumbs, CustomMenu, PhotoFilterIcon } from "@plane/ui"; // helpers import { truncateText } from "helpers/string.helper"; +import { renderEmoji } from "helpers/emoji.helper"; // types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types"; // constants @@ -26,6 +26,8 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { projectViews: projectViewsStore, } = useMobxStore(); + const { currentProjectDetails } = projectStore; + const storedFilters = viewId ? projectViewFiltersStore.storedFilters[viewId.toString()] : undefined; const activeLayout = issueFilterStore.userDisplayFilters.layout; @@ -87,47 +89,64 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { [issueFilterStore, projectId, workspaceSlug] ); - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; - const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined; const viewDetails = viewId ? projectViewsStore.viewDetails[viewId.toString()] : undefined; return (
    - router.back()}> - - -

    {`${projectDetails?.name ?? "Project"} Views`}

    -
    - + + + {renderEmoji(currentProjectDetails.emoji)} + + ) : currentProjectDetails?.icon_prop ? ( +
    + {renderEmoji(currentProjectDetails.icon_prop)} +
    + ) : ( + + {currentProjectDetails?.name.charAt(0)} + + ) + } + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Views" + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/views`} + /> + + + {viewDetails?.name && truncateText(viewDetails.name, 40)} + + } + className="ml-1.5" + placement="bottom-start" + > + {viewsList?.map((view) => ( + router.push(`/${workspaceSlug}/projects/${projectId}/views/${view.id}`)} + > + {truncateText(view.name, 40)} + + ))} + } />
    - - - {viewDetails?.name && truncateText(viewDetails.name, 40)} - - } - className="ml-1.5" - placement="bottom-start" - > - {viewsList?.map((view) => ( - router.push(`/${workspaceSlug}/projects/${projectId}/views/${view.id}`)} - > - {truncateText(view.name, 40)} - - ))} -
    { // router @@ -20,11 +19,7 @@ export const ProjectViewsHeader: React.FC = observer(() => { const [createViewModal, setCreateViewModal] = useState(false); const { project: projectStore } = useMobxStore(); - - const projectDetails = - workspaceSlug && projectId - ? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString()) - : undefined; + const { currentProjectDetails } = projectStore; return ( <> @@ -41,17 +36,32 @@ export const ProjectViewsHeader: React.FC = observer(() => { >
    - router.back()}> - - -

    Projects

    -
    - + + + {renderEmoji(currentProjectDetails.emoji)} + + ) : currentProjectDetails?.icon_prop ? ( +
    + {renderEmoji(currentProjectDetails.icon_prop)} +
    + ) : ( + + {currentProjectDetails?.name.charAt(0)} + + ) } + link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`} + /> + } + label="Views" /> -
    diff --git a/web/components/headers/projects.tsx b/web/components/headers/projects.tsx index 453eb38c8..3c56f239e 100644 --- a/web/components/headers/projects.tsx +++ b/web/components/headers/projects.tsx @@ -1,9 +1,7 @@ import { useRouter } from "next/router"; -import { Search, Plus } from "lucide-react"; +import { Search, Plus, Briefcase } from "lucide-react"; // ui -import { BreadcrumbItem, Breadcrumbs, Button } from "@plane/ui"; -// helper -import { truncateText } from "helpers/string.helper"; +import { Breadcrumbs, Button } from "@plane/ui"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; import { observer } from "mobx-react-lite"; @@ -13,8 +11,7 @@ export const ProjectsHeader = observer(() => { const { workspaceSlug } = router.query; // store - const { project: projectStore, workspace: workspaceStore } = useMobxStore(); - const currentWorkspace = workspaceStore.currentWorkspace; + const { project: projectStore } = useMobxStore(); const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : []; @@ -24,10 +21,11 @@ export const ProjectsHeader = observer(() => { >
    - router.back()}> - + } + label="Projects" />
    diff --git a/web/components/headers/user-profile.tsx b/web/components/headers/user-profile.tsx index 870aa1b54..70a3f40f5 100644 --- a/web/components/headers/user-profile.tsx +++ b/web/components/headers/user-profile.tsx @@ -1,22 +1,35 @@ import { FC } from "react"; - import { useRouter } from "next/router"; // ui -import { BreadcrumbItem, Breadcrumbs } from "@plane/ui"; +import { Breadcrumbs } from "@plane/ui"; +import { UserCircle2 } from "lucide-react"; // hooks import { observer } from "mobx-react-lite"; -export const UserProfileHeader: FC = observer(() => { +export interface IUserProfileHeader { + title: string; +} + +export const UserProfileHeader: FC = observer((props) => { + const { title } = props; const router = useRouter(); + const { workspaceSlug } = router.query; + return (
    - router.back()}> - + + } + link={`/${workspaceSlug}/me/profile`} + /> +
    diff --git a/web/components/headers/workspace-analytics.tsx b/web/components/headers/workspace-analytics.tsx index 5a9cf5d9a..ea1cde066 100644 --- a/web/components/headers/workspace-analytics.tsx +++ b/web/components/headers/workspace-analytics.tsx @@ -1,7 +1,7 @@ import { useRouter } from "next/router"; -import { ArrowLeft } from "lucide-react"; +import { ArrowLeft, BarChart2 } from "lucide-react"; // ui -import { BreadcrumbItem, Breadcrumbs } from "@plane/ui"; +import { Breadcrumbs } from "@plane/ui"; export const WorkspaceAnalyticsHeader = () => { const router = useRouter(); @@ -22,8 +22,12 @@ export const WorkspaceAnalyticsHeader = () => {
    - router.back()}> - + + } + label="Analytics" + />
    diff --git a/web/components/headers/workspace-settings.tsx b/web/components/headers/workspace-settings.tsx index 87d06e252..5dc156552 100644 --- a/web/components/headers/workspace-settings.tsx +++ b/web/components/headers/workspace-settings.tsx @@ -1,21 +1,13 @@ import { FC } from "react"; -import useSWR from "swr"; import { useRouter } from "next/router"; -import Link from "next/link"; // ui -import { BreadcrumbItem, Breadcrumbs } from "@plane/ui"; +import { Breadcrumbs } from "@plane/ui"; +import { Settings } from "lucide-react"; + // hooks import { observer } from "mobx-react-lite"; -// services -import { WorkspaceService } from "services/workspace.service"; -// helpers -import { truncateText } from "helpers/string.helper"; -// constant -import { WORKSPACE_DETAILS } from "constants/fetch-keys"; - -const workspaceService = new WorkspaceService(); export interface IWorkspaceSettingHeader { title: string; @@ -27,27 +19,20 @@ export const WorkspaceSettingHeader: FC = observer((pro const { workspaceSlug } = router.query; - const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () => - workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null - ); - return (
    - router.back()}> - - -

    {`${truncateText(activeWorkspace?.name ?? "Workspace", 32)}`}

    -
    - - } + + } + link={`/${workspaceSlug}/settings`} /> - +
    diff --git a/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx b/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx index 738aaecf0..6d0c6e0d6 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/assigned.tsx @@ -65,7 +65,7 @@ const ProfileAssignedIssuesPage: NextPageWithLayout = observer(() => { ProfileAssignedIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - }> + }> {page} ); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/created.tsx b/web/pages/[workspaceSlug]/profile/[userId]/created.tsx index c8418043e..7bf21edd9 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/created.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/created.tsx @@ -61,7 +61,7 @@ const ProfileCreatedIssuesPage: NextPageWithLayout = () => { ProfileCreatedIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - }> + }> {page} ); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/index.tsx b/web/pages/[workspaceSlug]/profile/[userId]/index.tsx index 9f55f1cd9..e5b70b1db 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/index.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/index.tsx @@ -56,7 +56,7 @@ const ProfileOverviewPage: NextPageWithLayout = () => { ProfileOverviewPage.getLayout = function getLayout(page: ReactElement) { return ( - }> + }> {page} ); diff --git a/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx b/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx index 6862b00b4..8900fb3fd 100644 --- a/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx +++ b/web/pages/[workspaceSlug]/profile/[userId]/subscribed.tsx @@ -61,7 +61,7 @@ const ProfileSubscribedIssuesPage: NextPageWithLayout = () => { ProfileSubscribedIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - }> + }> {page} ); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index d8bd19275..e267e7d05 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -19,7 +19,7 @@ import StrictModeDroppable from "components/dnd/StrictModeDroppable"; import { CreateUpdateBlockInline, SinglePageBlock } from "components/pages"; import { CreateLabelModal } from "components/labels"; import { CreateBlock } from "components/pages/create-block"; -import { PagesHeader } from "components/headers"; +import { PageDetailsHeader } from "components/headers/page-details"; // ui import { EmptyState } from "components/common"; import { CustomSearchSelect, TextArea, Loader, ToggleSwitch, Tooltip } from "@plane/ui"; @@ -626,7 +626,7 @@ const PageDetailsPage: NextPageWithLayout = () => { PageDetailsPage.getLayout = function getLayout(page: ReactElement) { return ( - } withProjectWrapper> + } withProjectWrapper> {page} );