Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: cycle, module and view layout roots #2517

Merged
merged 1 commit into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 76 additions & 25 deletions web/components/headers/project-view-issues.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useCallback } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";

// mobx store
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";
// helpers
import { truncateText } from "helpers/string.helper";
// types
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
Expand All @@ -19,6 +23,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
issueFilter: issueFilterStore,
projectViewFilters: projectViewFiltersStore,
project: projectStore,
projectViews: projectViewsStore,
} = useMobxStore();

const storedFilters = viewId ? projectViewFiltersStore.storedFilters[viewId.toString()] : undefined;
Expand Down Expand Up @@ -82,32 +87,78 @@ 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 (
<div className="flex items-center gap-2">
<LayoutSelection
layouts={["list", "kanban", "calendar", "spreadsheet", "gantt_chart"]}
onChange={(layout) => handleLayoutChange(layout)}
selectedLayout={activeLayout}
/>
<FiltersDropdown title="Filters">
<FilterSelection
filters={storedFilters ?? {}}
handleFiltersUpdate={handleFiltersUpdate}
layoutDisplayFiltersOptions={activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined}
labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined}
members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)}
states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined}
/>
</FiltersDropdown>
<FiltersDropdown title="Display">
<DisplayFiltersSelection
displayFilters={issueFilterStore.userDisplayFilters}
displayProperties={issueFilterStore.userDisplayProperties}
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
handleDisplayPropertiesUpdate={handleDisplayPropertiesUpdate}
layoutDisplayFiltersOptions={activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined}
<div className="relative w-full flex items-center z-10 justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
<div className="flex items-center gap-2">
<Breadcrumbs onBack={() => router.back()}>
<BreadcrumbItem
link={
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/cycles`}>
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
<p className="truncate">{`${projectDetails?.name ?? "Project"} Views`}</p>
</a>
</Link>
}
/>
</Breadcrumbs>
<CustomMenu
label={
<>
<PhotoFilterIcon height={12} width={12} />
{viewDetails?.name && truncateText(viewDetails.name, 40)}
</>
}
className="ml-1.5"
placement="bottom-start"
>
{viewsList?.map((view) => (
<CustomMenu.MenuItem
key={view.id}
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/views/${view.id}`)}
>
{truncateText(view.name, 40)}
</CustomMenu.MenuItem>
))}
</CustomMenu>
</div>
<div className="flex items-center gap-2">
<LayoutSelection
layouts={["list", "kanban", "calendar", "spreadsheet", "gantt_chart"]}
onChange={(layout) => handleLayoutChange(layout)}
selectedLayout={activeLayout}
/>
</FiltersDropdown>
<FiltersDropdown title="Filters">
<FilterSelection
filters={storedFilters ?? {}}
handleFiltersUpdate={handleFiltersUpdate}
layoutDisplayFiltersOptions={
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
}
labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? undefined}
members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)}
states={projectStore.states?.[projectId?.toString() ?? ""] ?? undefined}
/>
</FiltersDropdown>
<FiltersDropdown title="Display">
<DisplayFiltersSelection
displayFilters={issueFilterStore.userDisplayFilters}
displayProperties={issueFilterStore.userDisplayProperties}
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
handleDisplayPropertiesUpdate={handleDisplayPropertiesUpdate}
layoutDisplayFiltersOptions={
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
}
/>
</FiltersDropdown>
</div>
</div>
);
});
40 changes: 19 additions & 21 deletions web/components/headers/project-views.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { FC, useState } from "react";
import { useState } from "react";
import { useRouter } from "next/router";
// icons
import { ArrowLeft, Link, Plus } from "lucide-react";
import Link from "next/link";
import { observer } from "mobx-react-lite";
import { ArrowLeft, Plus } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { CreateUpdateProjectViewModal } from "components/views";
// components
Expand All @@ -11,18 +14,20 @@ import { PrimaryButton } from "components/ui";
// helpers
import { truncateText } from "helpers/string.helper";

interface IProjectViewsHeader {
title: string | undefined;
}

export const ProjectViewsHeader: FC<IProjectViewsHeader> = (props) => {
const { title } = props;
export const ProjectViewsHeader: React.FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
// states
const [createViewModal, setCreateViewModal] = useState(false);

const { project: projectStore } = useMobxStore();

const projectDetails =
workspaceSlug && projectId
? projectStore.getProjectById(workspaceSlug.toString(), projectId.toString())
: undefined;

return (
<>
{workspaceSlug && projectId && (
Expand All @@ -43,7 +48,7 @@ export const ProjectViewsHeader: FC<IProjectViewsHeader> = (props) => {
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
onClick={() => router.back()}
>
<ArrowLeft fontSize={14} strokeWidth={2} />
<ArrowLeft className="h-3 w-3" strokeWidth={2} />
</button>
</div>
<div>
Expand All @@ -57,20 +62,13 @@ export const ProjectViewsHeader: FC<IProjectViewsHeader> = (props) => {
</Link>
}
/>
<BreadcrumbItem title={`${truncateText(title ?? "Project", 32)} Cycles`} />
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Views`} />
</Breadcrumbs>
</div>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 flex-shrink-0">
<div>
<PrimaryButton
type="button"
className="flex items-center gap-2"
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "v" });
document.dispatchEvent(e);
}}
>
<PrimaryButton type="button" className="flex items-center gap-2" onClick={() => setCreateViewModal(true)}>
<Plus size={14} strokeWidth={2} />
Create View
</PrimaryButton>
Expand All @@ -79,4 +77,4 @@ export const ProjectViewsHeader: FC<IProjectViewsHeader> = (props) => {
</div>
</>
);
};
});
77 changes: 40 additions & 37 deletions web/components/issues/issue-layouts/roots/cycle-layout-root.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from "react";
// next imports
import React, { useState } from "react";
import { useRouter } from "next/router";
// swr
import useSWR from "swr";
// mobx react lite
import { observer } from "mobx-react-lite";
import useSWR from "swr";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import {
CycleAppliedFiltersRoot,
Expand All @@ -14,59 +13,63 @@ import {
CycleListLayout,
CycleSpreadsheetLayout,
} from "components/issues";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { TransferIssues, TransferIssuesModal } from "components/cycles";
// helpers
import { getDateRangeStatus } from "helpers/date-time.helper";

export const CycleLayoutRoot: React.FC = observer(() => {
const [transferIssuesModal, setTransferIssuesModal] = useState(false);

const router = useRouter();
const { workspaceSlug, projectId, cycleId } = router.query as {
workspaceSlug: string;
projectId: string;
cycleId: string;
};
const { workspaceSlug, projectId, cycleId } = router.query;

const {
project: projectStore,
issueFilter: issueFilterStore,
cycle: cycleStore,
cycleIssue: cycleIssueStore,
cycleIssueFilter: cycleIssueFilterStore,
} = useMobxStore();

useSWR(workspaceSlug && projectId && cycleId ? `CYCLE_ISSUES` : null, async () => {
useSWR(workspaceSlug && projectId && cycleId ? `CYCLE_FILTERS_AND_ISSUES_${cycleId.toString()}` : null, async () => {
if (workspaceSlug && projectId && cycleId) {
// fetching the project display filters and display properties
await issueFilterStore.fetchUserProjectFilters(workspaceSlug, projectId);
await issueFilterStore.fetchUserProjectFilters(workspaceSlug.toString(), projectId.toString());
// fetching the cycle filters
await cycleIssueFilterStore.fetchCycleFilters(workspaceSlug, projectId, cycleId);

// fetching the project state, labels and members
await projectStore.fetchProjectStates(workspaceSlug, projectId);
await projectStore.fetchProjectLabels(workspaceSlug, projectId);
await projectStore.fetchProjectMembers(workspaceSlug, projectId);
await cycleIssueFilterStore.fetchCycleFilters(workspaceSlug.toString(), projectId.toString(), cycleId.toString());

// fetching the cycle issues
await cycleIssueStore.fetchIssues(workspaceSlug, projectId, cycleId);
await cycleIssueStore.fetchIssues(workspaceSlug.toString(), projectId.toString(), cycleId.toString());
}
});

const activeLayout = issueFilterStore.userDisplayFilters.layout;

const cycleDetails = cycleId ? cycleStore.cycle_details[cycleId.toString()] : undefined;
const cycleStatus =
cycleDetails?.start_date && cycleDetails?.end_date
? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date)
: "draft";

return (
<div className="relative w-full h-full flex flex-col overflow-hidden">
<CycleAppliedFiltersRoot />
<div className="w-full h-full overflow-auto">
{activeLayout === "list" ? (
<CycleListLayout />
) : activeLayout === "kanban" ? (
<CycleKanBanLayout />
) : activeLayout === "calendar" ? (
<CycleCalendarLayout />
) : activeLayout === "gantt_chart" ? (
<CycleGanttLayout />
) : activeLayout === "spreadsheet" ? (
<CycleSpreadsheetLayout />
) : null}
<>
<TransferIssuesModal handleClose={() => setTransferIssuesModal(false)} isOpen={transferIssuesModal} />
<div className="relative w-full h-full flex flex-col overflow-hidden">
{cycleStatus === "completed" && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
<CycleAppliedFiltersRoot />
<div className="w-full h-full overflow-auto">
{activeLayout === "list" ? (
<CycleListLayout />
) : activeLayout === "kanban" ? (
<CycleKanBanLayout />
) : activeLayout === "calendar" ? (
<CycleCalendarLayout />
) : activeLayout === "gantt_chart" ? (
<CycleGanttLayout />
) : activeLayout === "spreadsheet" ? (
<CycleSpreadsheetLayout />
) : null}
</div>
</div>
</div>
</>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import React, { useCallback } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR from "swr";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { GlobalViewsAppliedFiltersRoot, SpreadsheetView } from "components/issues";
// types
import { IIssue, IIssueDisplayFilterOptions, TStaticViewTypes } from "types";
// fetch-keys
import { GLOBAL_VIEW_ISSUES } from "constants/fetch-keys";

type Props = {
type?: TStaticViewTypes;
Expand All @@ -35,7 +32,7 @@ export const GlobalViewLayoutRoot: React.FC<Props> = observer((props) => {
const storedFilters = globalViewId ? globalViewFiltersStore.storedFilters[globalViewId.toString()] : undefined;

useSWR(
workspaceSlug && globalViewId && viewDetails ? GLOBAL_VIEW_ISSUES(globalViewId.toString()) : null,
workspaceSlug && globalViewId && viewDetails ? `GLOBAL_VIEW_ISSUES_${globalViewId.toString()}` : null,
workspaceSlug && globalViewId && viewDetails
? () => {
globalViewIssuesStore.fetchViewIssues(workspaceSlug.toString(), globalViewId.toString(), storedFilters ?? {});
Expand All @@ -44,7 +41,7 @@ export const GlobalViewLayoutRoot: React.FC<Props> = observer((props) => {
);

useSWR(
workspaceSlug && type ? GLOBAL_VIEW_ISSUES(type) : null,
workspaceSlug && type ? `GLOBAL_VIEW_ISSUES_${type.toString()}` : null,
workspaceSlug && type
? () => {
globalViewIssuesStore.fetchStaticIssues(workspaceSlug.toString(), type);
Expand Down
27 changes: 12 additions & 15 deletions web/components/issues/issue-layouts/roots/module-layout-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,25 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
};

const {
project: projectStore,
issueFilter: issueFilterStore,
moduleIssue: moduleIssueStore,
moduleFilter: moduleIssueFilterStore,
} = useMobxStore();

useSWR(workspaceSlug && projectId && moduleId ? `MODULE_INFORMATION_${moduleId.toString()}` : null, async () => {
if (workspaceSlug && projectId && moduleId) {
// fetching the project display filters and display properties
await issueFilterStore.fetchUserProjectFilters(workspaceSlug, projectId);
// fetching the module filters
await moduleIssueFilterStore.fetchModuleFilters(workspaceSlug, projectId, moduleId);
useSWR(
workspaceSlug && projectId && moduleId ? `MODULE_FILTERS_AND_ISSUES_${moduleId.toString()}` : null,
async () => {
if (workspaceSlug && projectId && moduleId) {
// fetching the project display filters and display properties
await issueFilterStore.fetchUserProjectFilters(workspaceSlug, projectId);
// fetching the module filters
await moduleIssueFilterStore.fetchModuleFilters(workspaceSlug, projectId, moduleId);

// fetching the project state, labels and members
await projectStore.fetchProjectStates(workspaceSlug, projectId);
await projectStore.fetchProjectLabels(workspaceSlug, projectId);
await projectStore.fetchProjectMembers(workspaceSlug, projectId);

// fetching the module issues
await moduleIssueStore.fetchIssues(workspaceSlug, projectId, moduleId);
// fetching the module issues
await moduleIssueStore.fetchIssues(workspaceSlug, projectId, moduleId);
}
}
});
);

const activeLayout = issueFilterStore.userDisplayFilters.layout;

Expand Down
Loading
Loading