Skip to content
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
7 changes: 3 additions & 4 deletions web/components/command-palette/command-pallette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { CreateUpdateCycleModal } from "components/cycles";
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
import { CreateUpdateModuleModal } from "components/modules";
import { CreateProjectModal } from "components/project";
import { CreateUpdateViewModal } from "components/views";
import { CreateUpdateProjectViewModal } from "components/views";
import { CreateUpdatePageModal } from "components/pages";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
Expand Down Expand Up @@ -151,10 +151,9 @@ export const CommandPalette: React.FC = observer(() => {
setIsOpen={setIsCreateModuleModalOpen}
user={user}
/>
<CreateUpdateViewModal
handleClose={() => setIsCreateViewModalOpen(false)}
<CreateUpdateProjectViewModal
isOpen={isCreateViewModalOpen}
user={user}
onClose={() => setIsCreateViewModalOpen(false)}
/>
<CreateUpdatePageModal
isOpen={isCreateUpdatePageModalOpen}
Expand Down
4 changes: 3 additions & 1 deletion web/components/core/views/all-views.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export const AllViews: React.FC = observer(() => {

return (
<div className="relative w-full h-full flex flex-col overflow-auto">
<AppliedFiltersRoot />
<div className="p-4">
<AppliedFiltersRoot />
</div>
<div className="w-full h-full">
{activeLayout === "list" ? (
<ListLayout />
Expand Down
9 changes: 3 additions & 6 deletions web/components/headers/global-issues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,37 +38,34 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
const { workspaceSlug, globalViewId } = router.query;

const {
globalViews: globalViewsStore,
globalViewFilters: globalViewFiltersStore,
workspaceFilter: workspaceFilterStore,
workspace: workspaceStore,
project: projectStore,
} = useMobxStore();

const queryData = globalViewId ? globalViewsStore.globalViewDetails[globalViewId.toString()]?.query_data : undefined;

const storedFilters = globalViewId ? globalViewFiltersStore.storedFilters[globalViewId.toString()] : undefined;

const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !globalViewId) return;

const newValues = queryData?.filters?.[key] ?? [];
const newValues = storedFilters?.[key] ?? [];

if (Array.isArray(value)) {
value.forEach((val) => {
if (!newValues.includes(val)) newValues.push(val);
});
} else {
if (queryData?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
if (storedFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
else newValues.push(value);
}

globalViewFiltersStore.updateStoredFilters(globalViewId.toString(), {
[key]: newValues,
});
},
[globalViewId, globalViewFiltersStore, queryData, workspaceSlug]
[globalViewId, globalViewFiltersStore, storedFilters, workspaceSlug]
);

const handleDisplayFiltersUpdate = useCallback(
Expand Down
2 changes: 2 additions & 0 deletions web/components/headers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from "./global-issues";
export * from "./module-issues";
export * from "./project-issues";
export * from "./project-view-issues";
export * from "./project-views";
113 changes: 113 additions & 0 deletions web/components/headers/project-view-issues.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { useCallback } from "react";
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";
// types
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";

export const ProjectViewIssuesHeader: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug, projectId, viewId } = router.query;

const {
issueFilter: issueFilterStore,
projectViewFilters: projectViewFiltersStore,
project: projectStore,
} = useMobxStore();

const storedFilters = viewId ? projectViewFiltersStore.storedFilters[viewId.toString()] : undefined;

const activeLayout = issueFilterStore.userDisplayFilters.layout;

const handleLayoutChange = useCallback(
(layout: TIssueLayouts) => {
if (!workspaceSlug || !projectId) return;

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
display_filters: {
layout,
},
});
},
[issueFilterStore, projectId, workspaceSlug]
);

const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !viewId) return;

const newValues = storedFilters?.[key] ?? [];

if (Array.isArray(value)) {
value.forEach((val) => {
if (!newValues.includes(val)) newValues.push(val);
});
} else {
if (storedFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
else newValues.push(value);
}

projectViewFiltersStore.updateStoredFilters(viewId.toString(), {
[key]: newValues,
});
},
[projectViewFiltersStore, storedFilters, viewId, workspaceSlug]
);

const handleDisplayFiltersUpdate = useCallback(
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
if (!workspaceSlug || !projectId) return;

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
display_filters: {
...updatedDisplayFilter,
},
});
},
[issueFilterStore, projectId, workspaceSlug]
);

const handleDisplayPropertiesUpdate = useCallback(
(property: Partial<IIssueDisplayProperties>) => {
if (!workspaceSlug || !projectId) return;

issueFilterStore.updateDisplayProperties(workspaceSlug.toString(), projectId.toString(), property);
},
[issueFilterStore, projectId, workspaceSlug]
);

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="View">
<DisplayFiltersSelection
displayFilters={issueFilterStore.userDisplayFilters}
displayProperties={issueFilterStore.userDisplayProperties}
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
handleDisplayPropertiesUpdate={handleDisplayPropertiesUpdate}
layoutDisplayFiltersOptions={activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined}
/>
</FiltersDropdown>
</div>
);
});
31 changes: 31 additions & 0 deletions web/components/headers/project-views.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useState } from "react";

// components
import { CreateUpdateProjectViewModal } from "components/views";
// ui
import { PrimaryButton } from "components/ui";
// icons
import { PlusIcon } from "lucide-react";

export const ProjectViewsHeader = () => {
const [createViewModal, setCreateViewModal] = useState(false);

return (
<>
<CreateUpdateProjectViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
<div>
<PrimaryButton
type="button"
className="flex items-center gap-2"
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "v" });
document.dispatchEvent(e);
}}
>
<PlusIcon size={14} strokeWidth={2} />
Create View
</PrimaryButton>
</div>
</>
);
};
1 change: 1 addition & 0 deletions web/components/issues/issue-layouts/calendar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from "./day-tile";
export * from "./header";
export * from "./issue-blocks";
export * from "./module-root";
export * from "./project-view-root";
export * from "./root";
export * from "./week-days";
export * from "./week-header";
39 changes: 39 additions & 0 deletions web/components/issues/issue-layouts/calendar/project-view-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { observer } from "mobx-react-lite";
import { DragDropContext, DropResult } from "@hello-pangea/dnd";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { CalendarChart } from "components/issues";
// types
import { IIssueGroupedStructure } from "store/issue";

export const ProjectViewCalendarLayout: React.FC = observer(() => {
const { projectViewIssues: projectViewIssuesStore, issueFilter: issueFilterStore } = useMobxStore();

// TODO: add drag and drop functionality
const onDragEnd = (result: DropResult) => {
if (!result) return;

// return if not dropped on the correct place
if (!result.destination) return;

// return if dropped on the same date
if (result.destination.droppableId === result.source.droppableId) return;

// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
};

const issues = projectViewIssuesStore.getIssues;

return (
<div className="h-full w-full pt-4 bg-custom-background-100 overflow-hidden">
<DragDropContext onDragEnd={onDragEnd}>
<CalendarChart
issues={issues as IIssueGroupedStructure | null}
layout={issueFilterStore.userDisplayFilters.calendar?.layout}
/>
</DragDropContext>
</div>
);
});
3 changes: 1 addition & 2 deletions web/components/issues/issue-layouts/cycle-layout-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import useSWR from "swr";
// mobx react lite
import { observer } from "mobx-react-lite";
// components
import { CycleListLayout } from "./list/cycle-root";
import { CycleKanBanLayout } from "./kanban/cycle-root";
import { CycleKanBanLayout, CycleListLayout } from "components/issues";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from "./label";
export * from "./members";
export * from "./module-root";
export * from "./priority";
export * from "./project-view-root";
export * from "./project";
export * from "./root";
export * from "./state";
Expand Down
Loading