Skip to content

Commit

Permalink
Merge pull request #2195 from makeplane/fix/list-sorting
Browse files Browse the repository at this point in the history
Implementing list view
  • Loading branch information
sriramveeraghanta authored Sep 15, 2023
2 parents 7b04adf + cf34d4a commit cc9ebc5
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 10 deletions.
2 changes: 2 additions & 0 deletions web/components/core/views/list-view/single-issue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ export const SingleListIssue: React.FC<Props> = ({
const isNotAllowed =
userAuth.isGuest || userAuth.isViewer || disableUserActions || isArchivedIssues;

console.log("properties", properties);

return (
<>
<ContextMenu
Expand Down
41 changes: 41 additions & 0 deletions web/components/issue-layouts/list/group-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { FC } from "react";
// lib
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";

export interface IIssueListGroupHeader {
groupId: string;
groupBy: string;
}

export const IssueListGroupHeader: FC<IIssueListGroupHeader> = (props) => {
const { groupId, groupBy } = props;

const { issueView: issueViewStore, issueFilters: issueFilterStore }: RootStore = useMobxStore();

return (
<div>
{groupBy === "state" && <>{issueFilterStore.getProjectStateById(groupId)?.name}</>}
{groupBy === "state_detail.group" && <>{groupId}</>}
{groupBy === "priority" && <>{groupId}</>}
{groupBy === "project" && (
<>{issueFilterStore.workspaceProjects?.find((p) => (p.id = groupId))}</>
)}
{groupBy === "labels" && (
<>{issueFilterStore.projectLabels?.find((p) => p.id === groupId)?.name || " None"}</>
)}
{groupBy === "assignees" && (
<>
{issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member
?.display_name || " None"}
</>
)}
{groupBy === "created_by" && (
<>
{issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member
?.display_name || " None"}
</>
)}
</div>
);
};
4 changes: 4 additions & 0 deletions web/components/issue-layouts/list/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./root";
export * from "./list";
export * from "./item";
export * from "./group-header";
6 changes: 0 additions & 6 deletions web/components/issue-layouts/list/index.tsx

This file was deleted.

234 changes: 234 additions & 0 deletions web/components/issue-layouts/list/item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import React, { FC, useState } from "react";
import { Tooltip, CustomMenu, ContextMenu } from "components/ui";
// lib
import { useMobxStore } from "lib/mobx/store-provider";
import { IIssue } from "types";
import useUserAuth from "hooks/use-user-auth";
// icons
import {
ClipboardDocumentCheckIcon,
LinkIcon,
PencilIcon,
TrashIcon,
XMarkIcon,
ArrowTopRightOnSquareIcon,
PaperClipIcon,
} from "@heroicons/react/24/outline";
// components
import { LayerDiagonalIcon } from "components/icons";
import {
ViewAssigneeSelect,
ViewDueDateSelect,
ViewEstimateSelect,
ViewIssueLabel,
ViewPrioritySelect,
ViewStartDateSelect,
ViewStateSelect,
} from "components/issues";

export interface IIssueListItem {
issue: IIssue;
}

export const IssueListItem: FC<IIssueListItem> = (props) => {
const { issue } = props;
// store
const { user: userStore, issueFilters: issueFilterStore } = useMobxStore();
const displayProperties = issueFilterStore.userFilters?.display_properties;
console.log("userStore", userStore);
// context menu
const [contextMenu, setContextMenu] = useState(false);
const [contextMenuPosition, setContextMenuPosition] = useState<React.MouseEvent | null>(null);
const { user: userAuth } = useUserAuth();

// const isNotAllowed =
// userAuth?.isGuest || userAuth?.isViewer || disableUserActions || isArchivedIssues;

return (
<div>
<>
<ContextMenu
clickEvent={contextMenuPosition}
title="Quick actions"
isOpen={contextMenu}
setIsOpen={setContextMenu}
>
{/* {!isNotAllowed && (
<>
<ContextMenu.Item Icon={PencilIcon} onClick={editIssue}>
Edit issue
</ContextMenu.Item>
<ContextMenu.Item Icon={ClipboardDocumentCheckIcon} onClick={makeIssueCopy}>
Make a copy...
</ContextMenu.Item>
<ContextMenu.Item Icon={TrashIcon} onClick={() => handleDeleteIssue(issue)}>
Delete issue
</ContextMenu.Item>
</>
)}
<ContextMenu.Item Icon={LinkIcon} onClick={handleCopyText}>
Copy issue link
</ContextMenu.Item>
<a href={issuePath} target="_blank" rel="noreferrer noopener">
<ContextMenu.Item Icon={ArrowTopRightOnSquareIcon}>
Open issue in new tab
</ContextMenu.Item>
</a> */}
</ContextMenu>
<div
className="flex items-center justify-between px-4 py-2.5 gap-10 border-b border-custom-border-200 bg-custom-background-100 last:border-b-0"
onContextMenu={(e) => {
e.preventDefault();
setContextMenu(true);
setContextMenuPosition(e);
}}
>
<div className="flex-grow cursor-pointer min-w-[200px] whitespace-nowrap overflow-hidden overflow-ellipsis">
<div className="group relative flex items-center gap-2">
{/* {properties.key && (
<Tooltip
tooltipHeading="Issue ID"
tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`}
>
<span className="flex-shrink-0 text-xs text-custom-text-200">
{issue.project_detail?.identifier}-{issue.sequence_id}
</span>
</Tooltip>
)} */}
<Tooltip position="top-left" tooltipHeading="Title" tooltipContent={issue.name}>
<button
type="button"
className="truncate text-[0.825rem] text-custom-text-100"
onClick={() => {
// if (!isDraftIssues) openPeekOverview(issue);
// if (handleDraftIssueSelect) handleDraftIssueSelect(issue);
}}
>
{issue.name}
</button>
</Tooltip>
</div>
</div>

<div className={`flex flex-shrink-0 items-center gap-2 text-xs `}>
{displayProperties?.priority && (
<ViewPrioritySelect
issue={issue}
partialUpdateIssue={partialUpdateIssue}
position="right"
user={user}
isNotAllowed={isNotAllowed}
/>
)}
{displayProperties?.state && (
<ViewStateSelect
issue={issue}
partialUpdateIssue={partialUpdateIssue}
position="right"
user={user}
isNotAllowed={isNotAllowed}
/>
)}
{displayProperties?.start_date && issue.start_date && (
<ViewStartDateSelect
issue={issue}
partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed}
/>
)}
{displayProperties?.due_date && issue.target_date && (
<ViewDueDateSelect
issue={issue}
partialUpdateIssue={partialUpdateIssue}
user={user}
isNotAllowed={isNotAllowed}
/>
)}
{displayProperties?.labels && (
<ViewIssueLabel labelDetails={issue.label_details} maxRender={3} />
)}
{displayProperties?.assignee && (
<ViewAssigneeSelect
issue={issue}
partialUpdateIssue={partialUpdateIssue}
position="right"
user={user}
isNotAllowed={isNotAllowed}
/>
)}
{displayProperties?.estimate && issue.estimate_point !== null && (
<ViewEstimateSelect
issue={issue}
partialUpdateIssue={partialUpdateIssue}
position="right"
user={user}
isNotAllowed={isNotAllowed}
/>
)}
{displayProperties?.sub_issue_count && issue.sub_issues_count > 0 && (
<div className="flex cursor-default items-center rounded-md border border-custom-border-200 px-2.5 py-1 text-xs shadow-sm">
<Tooltip tooltipHeading="Sub-issue" tooltipContent={`${issue.sub_issues_count}`}>
<div className="flex items-center gap-1 text-custom-text-200">
<LayerDiagonalIcon className="h-3.5 w-3.5" />
{issue.sub_issues_count}
</div>
</Tooltip>
</div>
)}
{displayProperties?.link && issue.link_count > 0 && (
<div className="flex cursor-default items-center rounded-md border border-custom-border-200 px-2.5 py-1 text-xs shadow-sm">
<Tooltip tooltipHeading="Links" tooltipContent={`${issue.link_count}`}>
<div className="flex items-center gap-1 text-custom-text-200">
<LinkIcon className="h-3.5 w-3.5" />
{issue.link_count}
</div>
</Tooltip>
</div>
)}
{displayProperties?.attachment_count && issue.attachment_count > 0 && (
<div className="flex cursor-default items-center rounded-md border border-custom-border-200 px-2.5 py-1 text-xs shadow-sm">
<Tooltip tooltipHeading="Attachments" tooltipContent={`${issue.attachment_count}`}>
<div className="flex items-center gap-1 text-custom-text-200">
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45" />
{issue.attachment_count}
</div>
</Tooltip>
</div>
)}
{/* {type && !isNotAllowed && (
<CustomMenu width="auto" ellipsis>
<CustomMenu.MenuItem onClick={editIssue}>
<div className="flex items-center justify-start gap-2">
<PencilIcon className="h-4 w-4" />
<span>Edit issue</span>
</div>
</CustomMenu.MenuItem>
{type !== "issue" && removeIssue && (
<CustomMenu.MenuItem onClick={removeIssue}>
<div className="flex items-center justify-start gap-2">
<XMarkIcon className="h-4 w-4" />
<span>Remove from {type}</span>
</div>
</CustomMenu.MenuItem>
)}
<CustomMenu.MenuItem onClick={() => handleDeleteIssue(issue)}>
<div className="flex items-center justify-start gap-2">
<TrashIcon className="h-4 w-4" />
<span>Delete issue</span>
</div>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={handleCopyText}>
<div className="flex items-center justify-start gap-2">
<LinkIcon className="h-4 w-4" />
<span>Copy issue link</span>
</div>
</CustomMenu.MenuItem>
</CustomMenu>
)} */}
</div>
</div>
</>
</div>
);
};
18 changes: 18 additions & 0 deletions web/components/issue-layouts/list/list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { FC } from "react";
import { IIssue } from "types";
import { IssueListItem } from "./item";

export interface IIssueListView {
issues: IIssue[];
}

export const IssueListView: FC<IIssueListView> = (props) => {
const { issues = [] } = props;
return (
<div>
{issues.map((issue) => (
<IssueListItem issue={issue} />
))}
</div>
);
};
44 changes: 44 additions & 0 deletions web/components/issue-layouts/list/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import { Disclosure } from "@headlessui/react";
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
// components
import { IssueListView } from "./list";
import { IssueListGroupHeader } from "./group-header";

export const IssueListViewRoot = observer(() => {
const { issueView: issueViewStore, issueFilters: issueFilterStore }: RootStore = useMobxStore();
console.log("issueViewStore", issueViewStore);
console.log("userFilters", issueFilterStore.userFilters);
console.log("issueFilterStore", issueFilterStore);

return (
<div className="relative w-full h-full">
{issueViewStore.loader || issueViewStore?.getIssues === null ? (
<div>Loading...</div>
) : (
<>
{Object.keys(issueViewStore?.getIssues).map((groupId) => (
<Disclosure key={groupId}>
{({ open }) => (
<>
<Disclosure.Button className="flex w-full justify-between rounded-lg bg-purple-100 px-4 py-2 text-left text-sm font-medium text-purple-900 hover:bg-purple-200 focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75">
<IssueListGroupHeader
groupId={groupId}
groupBy={issueFilterStore.userFilters?.display_filters["group_by"] || ""}
/>
</Disclosure.Button>
<Disclosure.Panel className="px-4 pt-4 pb-2">
<IssueListView issues={issueViewStore?.getIssues?.[groupId]}></IssueListView>
</Disclosure.Panel>
</>
)}
</Disclosure>
))}
</>
)}
</div>
);
});
5 changes: 2 additions & 3 deletions web/components/issue-layouts/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DisplayFiltersSelection } from "./display-filters";

import { FilterPreview } from "./filters-preview";

import { IssueListViewRoot } from "./list";
import { IssueListViewRoot } from "./list/root";
import { IssueKanBanViewRoot } from "./kanban";
import { IssueCalendarViewRoot } from "./calendar";
import { IssueSpreadsheetViewRoot } from "./spreadsheet";
Expand All @@ -19,8 +19,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";

export const IssuesRoot = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilters: issueFilterStore }: RootStore = useMobxStore();

return (
<div className="w-full h-full relative flex flex-col overflow-hidden">
Expand Down
Loading

0 comments on commit cc9ebc5

Please sign in to comment.