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

style: filter issues dropdown #466

Merged
merged 1 commit into from
Mar 16, 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
36 changes: 27 additions & 9 deletions apps/app/components/core/issues-view-filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,24 @@ import useIssuesProperties from "hooks/use-issue-properties";
import useIssuesView from "hooks/use-issues-view";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// components
import { PRIORITIES } from "constants/project";
// ui
import { CustomMenu, MultiLevelDropdown } from "components/ui";
import { Avatar, CustomMenu, MultiLevelDropdown } from "components/ui";
// icons
import { ChevronDownIcon, ListBulletIcon } from "@heroicons/react/24/outline";
import { Squares2X2Icon } from "@heroicons/react/20/solid";
import { getStateGroupIcon } from "components/icons";
import { getPriorityIcon } from "components/icons/priority-icon";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
import { getStatesList } from "helpers/state.helper";
// types
import { IIssue, IIssueLabels, Properties } from "types";
import { IIssueLabels, Properties } from "types";
// fetch-keys
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATE_LIST } from "constants/fetch-keys";
// constants
import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue";
import { PRIORITIES } from "constants/project";

export const IssuesFilterView: React.FC = () => {
const router = useRouter();
Expand Down Expand Up @@ -97,7 +100,7 @@ export const IssuesFilterView: React.FC = () => {
</button>
</div>
<MultiLevelDropdown
label="Filter"
label="Filters"
onSelect={(option) => {
setFilters({
...filters,
Expand All @@ -116,7 +119,11 @@ export const IssuesFilterView: React.FC = () => {
children: [
...PRIORITIES.map((priority) => ({
id: priority ?? "none",
label: priority ?? "None",
label: (
<div className="flex items-center gap-2">
{getPriorityIcon(priority)} {priority ?? "None"}
</div>
),
value: {
key: "priority",
value: priority,
Expand All @@ -132,7 +139,11 @@ export const IssuesFilterView: React.FC = () => {
children: [
...statesList.map((state) => ({
id: state.id,
label: state.name,
label: (
<div className="flex items-center gap-2">
{getStateGroupIcon(state.group, "16", "16", state.color)} {state.name}
</div>
),
value: {
key: "state",
value: state.id,
Expand All @@ -148,7 +159,14 @@ export const IssuesFilterView: React.FC = () => {
children: [
...(members?.map((member) => ({
id: member.member.id,
label: member.member.first_name,
label: (
<div className="flex items-center gap-2">
<Avatar user={member.member} />
{member.member.first_name && member.member.first_name !== ""
? member.member.first_name
: member.member.email}
</div>
),
value: {
key: "assignee",
value: member.member.id,
Expand All @@ -163,12 +181,12 @@ export const IssuesFilterView: React.FC = () => {
{({ open }) => (
<>
<Popover.Button
className={`group flex items-center gap-2 rounded-md border bg-transparent p-2 text-xs font-medium hover:bg-gray-100 hover:text-gray-900 focus:outline-none ${
className={`group flex items-center gap-2 rounded-md border bg-transparent px-3 py-1.5 text-xs hover:bg-gray-100 hover:text-gray-900 focus:outline-none ${
open ? "bg-gray-100 text-gray-900" : "text-gray-500"
}`}
>
View
<ChevronDownIcon className="h-4 w-4" aria-hidden="true" />
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</Popover.Button>

<Transition
Expand Down
16 changes: 9 additions & 7 deletions apps/app/components/core/issues-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
STATE_LIST,
} from "constants/fetch-keys";
import { EmptySpace, EmptySpaceItem } from "components/ui";
import { PrimaryButton } from "components/ui/button/primary-button";

type Props = {
type?: "issue" | "cycle" | "module";
Expand Down Expand Up @@ -496,20 +497,21 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
})}
</div>

<div>
<button
{Object.keys(filters).length > 0 && (
<PrimaryButton
type="button"
onClick={() =>
setCreateViewModal({
query: filters,
})
}
className="flex items-center gap-x-0.5 text-sm"
className="flex items-center gap-4 text-sm"
size="sm"
>
<PlusIcon className="h-3 w-3" />
<span>Save view</span>
</button>
</div>
<PlusIcon className="h-4 w-4" />
Save view
</PrimaryButton>
)}
</div>
<DragDropContext onDragEnd={handleOnDragEnd}>
<StrictModeDroppable droppableId="trashBox">
Expand Down
2 changes: 1 addition & 1 deletion apps/app/components/issues/select/priority.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const IssuePrioritySelect: React.FC<Props> = ({ value, onChange }) => (
label={
<div className="flex items-center justify-center gap-2 text-xs">
<span className="flex items-center">
{getPriorityIcon(value, `${value ? "text-xs" : "text-xs text-gray-500"}`)}
{getPriorityIcon(value, `text-xs ${value ? "" : "text-gray-500"}`)}
</span>
<span className={`${value ? "text-gray-600" : "text-gray-500"} capitalize`}>
{value ?? "Priority"}
Expand Down
8 changes: 6 additions & 2 deletions apps/app/components/project/single-sidebar-project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,12 @@ export const SingleSidebarProject: React.FC<Props> = ({
className={`${sidebarCollapse ? "" : "ml-[2.25rem]"} flex flex-col gap-y-1`}
>
{navigation(workspaceSlug as string, project?.id).map((item) => {
if (item.name === "Cycles" && !project.cycle_view) return;
if (item.name === "Modules" && !project.module_view) return;
if (
(item.name === "Cycles" && !project.cycle_view) ||
(item.name === "Modules" && !project.module_view) ||
(item.name === "Views" && !project.issue_views_view)
)
return;

return (
<Link key={item.name} href={item.href}>
Expand Down
76 changes: 39 additions & 37 deletions apps/app/components/ui/multi-level-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Menu, Transition } from "@headlessui/react";
import { Fragment, useState } from "react";
import { ChevronDownIcon, ChevronRightIcon, ChevronLeftIcon } from "@heroicons/react/20/solid";
import { ChevronRightIcon, ChevronLeftIcon } from "@heroicons/react/20/solid";
import { ChevronDownIcon } from "@heroicons/react/24/outline";

type MultiLevelDropdownProps = {
label: string;
Expand All @@ -11,7 +12,7 @@ type MultiLevelDropdownProps = {
selected?: boolean;
children?: {
id: string;
label: string;
label: string | JSX.Element;
value: any;
selected?: boolean;
}[];
Expand All @@ -20,26 +21,27 @@ type MultiLevelDropdownProps = {
direction?: "left" | "right";
};

export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) => {
const { label, options, onSelect, direction = "right" } = props;

export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({
label,
options,
onSelect,
direction = "right",
}) => {
const [openChildFor, setOpenChildFor] = useState<string | null>(null);

return (
<Menu as="div" className="relative inline-block text-left">
<Menu as="div" className="relative z-10 inline-block text-left">
{({ open }) => (
<>
<div>
<Menu.Button
onClick={() => {
setOpenChildFor(null);
}}
className={`group flex items-center gap-2 rounded-md border bg-transparent p-2 text-xs font-medium hover:bg-gray-100 hover:text-gray-900 focus:outline-none ${
onClick={() => setOpenChildFor(null)}
className={`group flex items-center justify-between gap-2 rounded-md border px-3 py-1.5 text-xs shadow-sm duration-300 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 ${
open ? "bg-gray-100 text-gray-900" : "text-gray-500"
}`}
>
{label}
<ChevronDownIcon className="h-4 w-4" aria-hidden="true" />
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</Menu.Button>
</div>
<Transition
Expand All @@ -53,10 +55,10 @@ export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) =>
>
<Menu.Items
static
className="absolute right-0 mt-2 w-36 origin-top-right select-none divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
className="absolute right-0 mt-1 w-36 origin-top-right select-none rounded-md bg-white text-xs shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
>
{options.map((option) => (
<div className="relative px-1 py-1" key={option.id}>
<div className="relative p-1" key={option.id}>
<Menu.Item
as="button"
onClick={(e: any) => {
Expand All @@ -81,7 +83,9 @@ export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) =>
<div
className={`${
active || option.selected ? "bg-gray-100" : "text-gray-900"
} group flex w-full items-center justify-between rounded-md px-2 py-2 text-sm`}
} flex items-center gap-1 rounded px-1 py-1.5 ${
direction === "right" ? "justify-between" : ""
}`}
>
{direction === "left" && option.children && (
<ChevronLeftIcon className="h-4 w-4" aria-hidden="true" />
Expand All @@ -97,33 +101,31 @@ export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) =>
{option.children && option.id === openChildFor && (
<Menu.Items
static
className={`absolute top-0 mt-2 w-36 origin-top-right select-none divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none ${
className={`absolute top-0 w-36 origin-top-right select-none rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none ${
direction === "left"
? "right-full -translate-x-2"
: "left-full translate-x-2"
? "right-full -translate-x-1"
: "left-full translate-x-1"
}`}
>
{option.children.map((child) => (
<div className="relative px-1 py-1" key={child.id}>
<Menu.Item as="div" className="flex items-center justify-between">
{({ active }) => (
<>
<button
type="button"
onClick={() => {
onSelect(child.value);
}}
className={`${
active || option.selected ? "bg-gray-100" : "text-gray-900"
} group flex w-full items-center rounded-md px-2 py-2 text-sm capitalize`}
>
{child.label}
</button>
</>
)}
<div className="p-1">
{option.children.map((child) => (
<Menu.Item
key={child.id}
as="button"
type="button"
onClick={() => {
onSelect(child.value);
}}
className={({ active }) =>
`${
active || option.selected ? "bg-gray-100" : "text-gray-900"
} flex w-full items-center rounded px-1 py-1.5 capitalize`
}
>
{child.label}
</Menu.Item>
</div>
))}
))}
</div>
</Menu.Items>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { IProject, UserAuth } from "types";
import type { NextPage, GetServerSidePropsContext } from "next";
// fetch-keys
import { PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
import { ContrastIcon, PeopleGroupIcon } from "components/icons";
import { ContrastIcon, PeopleGroupIcon, ViewListIcon } from "components/icons";

const FeaturesSettings: NextPage<UserAuth> = (props) => {
const router = useRouter();
Expand Down Expand Up @@ -93,7 +93,7 @@ const FeaturesSettings: NextPage<UserAuth> = (props) => {
<section className="space-y-8">
<h3 className="text-2xl font-semibold">Features</h3>
<div className="space-y-5">
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-6">
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-5">
<div className="flex items-start gap-3">
<ContrastIcon color="#3f76ff" width={28} height={28} className="flex-shrink-0" />
<div>
Expand Down Expand Up @@ -122,7 +122,7 @@ const FeaturesSettings: NextPage<UserAuth> = (props) => {
/>
</button>
</div>
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-6">
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-5">
<div className="flex items-start gap-3">
<PeopleGroupIcon color="#ff6b00" width={28} height={28} className="flex-shrink-0" />
<div>
Expand Down Expand Up @@ -151,6 +151,35 @@ const FeaturesSettings: NextPage<UserAuth> = (props) => {
/>
</button>
</div>
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-5">
<div className="flex items-start gap-3">
<ViewListIcon color="#ff6b00" width={28} height={28} className="flex-shrink-0" />
<div>
<h4 className="-mt-1.5 text-xl font-semibold">Views</h4>
<p className="text-gray-500">
Modules are enabled for all the projects in this workspace. Access it from the
navigation bar.
</p>
</div>
</div>
<button
type="button"
className={`relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${
projectDetails?.issue_views_view ? "bg-green-500" : "bg-gray-200"
}`}
role="switch"
aria-checked={projectDetails?.issue_views_view}
onClick={() => handleSubmit({ issue_views_view: !projectDetails?.issue_views_view })}
>
<span className="sr-only">Use views</span>
<span
aria-hidden="true"
className={`inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out ${
projectDetails?.issue_views_view ? "translate-x-5" : "translate-x-0"
}`}
/>
</button>
</div>
</div>
<div className="flex items-center gap-2">
<a href="https://plane.so/" target="_blank" rel="noreferrer">
Expand Down
1 change: 1 addition & 0 deletions apps/app/types/projects.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface IProject {
id: string;
identifier: string;
is_favorite: boolean;
issue_views_view: boolean;
module_view: boolean;
name: string;
network: number;
Expand Down