style: new empty states (#1497)
* fix: custom colors opacity * chore: update text colors for dark mode * fix: dropdown text colors, datepicker bg color * chore: update text colors * chore: updated primary bg color * style: new empty states added * refactor: empty state for issues * style: empty state for estimates * chore: update labels, estimates and integrations empty states * fix: custom analytics sidebar
This commit is contained in:
parent
82ff786666
commit
4a2057c0b3
44 changed files with 757 additions and 792 deletions
|
|
@ -8,6 +8,7 @@ import useSWR from "swr";
|
|||
import { useForm } from "react-hook-form";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import useProjects from "hooks/use-projects";
|
||||
// headless ui
|
||||
import { Tab } from "@headlessui/react";
|
||||
// services
|
||||
|
|
@ -19,6 +20,11 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
|||
import { CustomAnalytics, ScopeAndDemand } from "components/analytics";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
import { EmptyState } from "components/ui";
|
||||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyAnalytics from "public/empty-state/analytics.svg";
|
||||
// types
|
||||
import { IAnalyticsParams } from "types";
|
||||
// fetch-keys
|
||||
|
|
@ -38,6 +44,7 @@ const Analytics = () => {
|
|||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { user } = useUserAuth();
|
||||
const { projects } = useProjects();
|
||||
|
||||
const { control, watch, setValue } = useForm<IAnalyticsParams>({ defaultValues });
|
||||
|
||||
|
|
@ -84,54 +91,60 @@ const Analytics = () => {
|
|||
<BreadcrumbItem title="Workspace Analytics" />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
// right={
|
||||
// <PrimaryButton
|
||||
// className="flex items-center gap-2"
|
||||
// onClick={() => {
|
||||
// const e = new KeyboardEvent("keydown", { key: "p" });
|
||||
// document.dispatchEvent(e);
|
||||
// }}
|
||||
// >
|
||||
// <PlusIcon className="h-4 w-4" />
|
||||
// Save Analytics
|
||||
// </PrimaryButton>
|
||||
// }
|
||||
>
|
||||
<div className="h-full flex flex-col overflow-hidden bg-custom-background-100">
|
||||
<Tab.Group as={Fragment}>
|
||||
<Tab.List as="div" className="space-x-2 border-b border-custom-border-100 px-5 py-3">
|
||||
{tabsList.map((tab) => (
|
||||
<Tab
|
||||
key={tab}
|
||||
className={({ selected }) =>
|
||||
`rounded-3xl border border-custom-border-100 px-4 py-2 text-xs hover:bg-custom-background-80 ${
|
||||
selected ? "bg-custom-background-80" : ""
|
||||
}`
|
||||
}
|
||||
onClick={() => trackAnalyticsEvent(tab)}
|
||||
>
|
||||
{tab}
|
||||
</Tab>
|
||||
))}
|
||||
</Tab.List>
|
||||
<Tab.Panels as={Fragment}>
|
||||
<Tab.Panel as={Fragment}>
|
||||
<ScopeAndDemand fullScreen />
|
||||
</Tab.Panel>
|
||||
<Tab.Panel as={Fragment}>
|
||||
<CustomAnalytics
|
||||
analytics={analytics}
|
||||
analyticsError={analyticsError}
|
||||
params={params}
|
||||
control={control}
|
||||
setValue={setValue}
|
||||
user={user}
|
||||
fullScreen
|
||||
/>
|
||||
</Tab.Panel>
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
</div>
|
||||
{projects ? (
|
||||
projects.length > 0 ? (
|
||||
<div className="h-full flex flex-col overflow-hidden bg-custom-background-100">
|
||||
<Tab.Group as={Fragment}>
|
||||
<Tab.List as="div" className="space-x-2 border-b border-custom-border-100 px-5 py-3">
|
||||
{tabsList.map((tab) => (
|
||||
<Tab
|
||||
key={tab}
|
||||
className={({ selected }) =>
|
||||
`rounded-3xl border border-custom-border-100 px-4 py-2 text-xs hover:bg-custom-background-80 ${
|
||||
selected ? "bg-custom-background-80" : ""
|
||||
}`
|
||||
}
|
||||
onClick={() => trackAnalyticsEvent(tab)}
|
||||
>
|
||||
{tab}
|
||||
</Tab>
|
||||
))}
|
||||
</Tab.List>
|
||||
<Tab.Panels as={Fragment}>
|
||||
<Tab.Panel as={Fragment}>
|
||||
<ScopeAndDemand fullScreen />
|
||||
</Tab.Panel>
|
||||
<Tab.Panel as={Fragment}>
|
||||
<CustomAnalytics
|
||||
analytics={analytics}
|
||||
analyticsError={analyticsError}
|
||||
params={params}
|
||||
control={control}
|
||||
setValue={setValue}
|
||||
user={user}
|
||||
fullScreen
|
||||
/>
|
||||
</Tab.Panel>
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
</div>
|
||||
) : (
|
||||
<EmptyState
|
||||
title="You can see your all projects' analytics here"
|
||||
description="Let's create your first project and analyse the stats with various graphs."
|
||||
image={emptyAnalytics}
|
||||
buttonText="New Project"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "p",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : null}
|
||||
</WorkspaceAuthorizationLayout>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Image from "next/image";
|
||||
|
||||
import useSWR, { mutate } from "swr";
|
||||
|
||||
|
|
@ -8,6 +9,9 @@ import useSWR, { mutate } from "swr";
|
|||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
// services
|
||||
import userService from "services/user.service";
|
||||
// hooks
|
||||
import useUser from "hooks/use-user";
|
||||
import useProjects from "hooks/use-projects";
|
||||
// components
|
||||
import {
|
||||
CompletedIssuesGraph,
|
||||
|
|
@ -15,11 +19,18 @@ import {
|
|||
IssuesPieChart,
|
||||
IssuesStats,
|
||||
} from "components/workspace";
|
||||
import { ProductUpdatesModal } from "components/ui";
|
||||
// ui
|
||||
import { PrimaryButton, ProductUpdatesModal } from "components/ui";
|
||||
// images
|
||||
import emptyDashboard from "public/empty-state/dashboard.svg";
|
||||
// helpers
|
||||
import { render12HourFormatTime, renderShortDate } from "helpers/date-time.helper";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { USER_WORKSPACE_DASHBOARD } from "constants/fetch-keys";
|
||||
// constants
|
||||
import { DAYS } from "constants/project";
|
||||
|
||||
const WorkspacePage: NextPage = () => {
|
||||
const [month, setMonth] = useState(new Date().getMonth() + 1);
|
||||
|
|
@ -28,11 +39,18 @@ const WorkspacePage: NextPage = () => {
|
|||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { user } = useUser();
|
||||
const { projects } = useProjects();
|
||||
|
||||
const { data: workspaceDashboardData } = useSWR(
|
||||
workspaceSlug ? USER_WORKSPACE_DASHBOARD(workspaceSlug as string) : null,
|
||||
workspaceSlug ? () => userService.userWorkspaceDashboard(workspaceSlug as string, month) : null
|
||||
);
|
||||
|
||||
const today = new Date();
|
||||
const greeting =
|
||||
today.getHours() < 12 ? "morning" : today.getHours() < 18 ? "afternoon" : "evening";
|
||||
|
||||
useEffect(() => {
|
||||
if (!workspaceSlug) return;
|
||||
|
||||
|
|
@ -47,42 +65,76 @@ const WorkspacePage: NextPage = () => {
|
|||
setIsOpen={setIsProductUpdatesModalOpen}
|
||||
/>
|
||||
)}
|
||||
<div className="p-8">
|
||||
<div className="flex flex-col gap-8">
|
||||
<div className="text-custom-text-200 flex flex-col justify-between gap-x-2 gap-y-6 rounded-lg border border-custom-border-100 bg-custom-background-100 px-4 py-6 md:flex-row md:items-center md:py-3">
|
||||
<p className="font-semibold">
|
||||
Plane is open source, support us by starring us on GitHub.
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => setIsProductUpdatesModalOpen(true)}
|
||||
className="rounded-md border-2 border-custom-border-100 px-3 py-1.5 text-sm font-medium duration-300"
|
||||
>
|
||||
{`What's New?`}
|
||||
</button>
|
||||
<a
|
||||
href="https://github.com/makeplane/plane"
|
||||
target="_blank"
|
||||
className="rounded-md border-2 border-custom-border-100 px-3 py-1.5 text-sm font-medium duration-300"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Star us on GitHub
|
||||
</a>
|
||||
{projects ? (
|
||||
projects.length > 0 ? (
|
||||
<div className="p-8">
|
||||
<div className="flex flex-col gap-8">
|
||||
<div className="text-custom-text-200 flex flex-col justify-between gap-x-2 gap-y-6 rounded-lg border border-custom-border-100 bg-custom-background-100 px-4 py-6 md:flex-row md:items-center md:py-3">
|
||||
<p className="font-semibold">
|
||||
Plane is open source, support us by starring us on GitHub.
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => setIsProductUpdatesModalOpen(true)}
|
||||
className="rounded-md border-2 border-custom-border-100 px-3 py-1.5 text-sm font-medium duration-300"
|
||||
>
|
||||
{`What's New?`}
|
||||
</button>
|
||||
<a
|
||||
href="https://github.com/makeplane/plane"
|
||||
target="_blank"
|
||||
className="rounded-md border-2 border-custom-border-100 px-3 py-1.5 text-sm font-medium duration-300"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Star us on GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<IssuesStats data={workspaceDashboardData} />
|
||||
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
|
||||
<IssuesList issues={workspaceDashboardData?.overdue_issues} type="overdue" />
|
||||
<IssuesList issues={workspaceDashboardData?.upcoming_issues} type="upcoming" />
|
||||
<IssuesPieChart groupedIssues={workspaceDashboardData?.state_distribution} />
|
||||
<CompletedIssuesGraph
|
||||
issues={workspaceDashboardData?.completed_issues}
|
||||
month={month}
|
||||
setMonth={setMonth}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<IssuesStats data={workspaceDashboardData} />
|
||||
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
|
||||
<IssuesList issues={workspaceDashboardData?.overdue_issues} type="overdue" />
|
||||
<IssuesList issues={workspaceDashboardData?.upcoming_issues} type="upcoming" />
|
||||
<IssuesPieChart groupedIssues={workspaceDashboardData?.state_distribution} />
|
||||
<CompletedIssuesGraph
|
||||
issues={workspaceDashboardData?.completed_issues}
|
||||
month={month}
|
||||
setMonth={setMonth}
|
||||
/>
|
||||
) : (
|
||||
<div className="p-8">
|
||||
<h3 className="text-2xl font-semibold">
|
||||
Good {greeting}, {user?.first_name} {user?.last_name}
|
||||
</h3>
|
||||
<h6 className="text-custom-text-400 font-medium">
|
||||
{DAYS[today.getDay()]}, {renderShortDate(today)} {render12HourFormatTime(today)}
|
||||
</h6>
|
||||
<div className="mt-7 bg-custom-primary-100/5 flex justify-between gap-5 md:gap-8">
|
||||
<div className="p-5 md:p-8 pr-0">
|
||||
<h5 className="text-xl font-semibold">Create a project</h5>
|
||||
<p className="mt-2 mb-5">
|
||||
Manage your projects by creating issues, cycles, modules, views and pages.
|
||||
</p>
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "p",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
>
|
||||
Create Project
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
<div className="hidden md:block self-end overflow-hidden pt-8">
|
||||
<Image src={emptyDashboard} alt="Empty Dashboard" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
</WorkspaceAuthorizationLayout>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@ import { useRouter } from "next/router";
|
|||
// headless ui
|
||||
import { Disclosure, Popover, Transition } from "@headlessui/react";
|
||||
// icons
|
||||
import { ChevronDownIcon, PlusIcon, RectangleStackIcon } from "@heroicons/react/24/outline";
|
||||
import { ChevronDownIcon, PlusIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyMyIssues from "public/empty-state/my-issues.svg";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
// hooks
|
||||
import useIssues from "hooks/use-issues";
|
||||
// ui
|
||||
import { Spinner, EmptySpace, EmptySpaceItem, PrimaryButton } from "components/ui";
|
||||
import { Spinner, PrimaryButton, EmptyState } from "components/ui";
|
||||
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
|
||||
// hooks
|
||||
import useMyIssuesProperties from "hooks/use-my-issues-filter";
|
||||
|
|
@ -23,13 +25,14 @@ import { MyIssuesListItem } from "components/issues";
|
|||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import useProjects from "hooks/use-projects";
|
||||
|
||||
const MyIssuesPage: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
// fetching user issues
|
||||
const { myIssues } = useIssues(workspaceSlug as string);
|
||||
const { projects } = useProjects();
|
||||
|
||||
const [properties, setProperties] = useMyIssuesProperties(workspaceSlug as string);
|
||||
|
||||
|
|
@ -148,30 +151,39 @@ const MyIssuesPage: NextPage = () => {
|
|||
)}
|
||||
</Disclosure>
|
||||
) : (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center px-4">
|
||||
<EmptySpace
|
||||
title="You don't have any issue assigned to you yet."
|
||||
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||
Icon={RectangleStackIcon}
|
||||
>
|
||||
<EmptySpaceItem
|
||||
title="Create a new issue"
|
||||
description={
|
||||
<span>
|
||||
Use <pre className="inline rounded bg-gray-200 px-2 py-1">C</pre> shortcut
|
||||
to create a new issue
|
||||
</span>
|
||||
}
|
||||
Icon={PlusIcon}
|
||||
action={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "c",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
</EmptySpace>
|
||||
</div>
|
||||
<EmptyState
|
||||
title={
|
||||
projects
|
||||
? projects.length > 0
|
||||
? "You don't have any issue assigned to you yet"
|
||||
: "Issues assigned to you will appear here"
|
||||
: ""
|
||||
}
|
||||
description={
|
||||
projects
|
||||
? projects.length > 0
|
||||
? "Keep track of your work in a single place."
|
||||
: "Let's create your first project and add issues that you want to accomplish."
|
||||
: ""
|
||||
}
|
||||
image={emptyMyIssues}
|
||||
buttonText={projects ? (projects.length > 0 ? "New Issue" : "New Project") : ""}
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
let e: KeyboardEvent;
|
||||
|
||||
if (projects && projects.length > 0)
|
||||
e = new KeyboardEvent("keydown", {
|
||||
key: "c",
|
||||
});
|
||||
else
|
||||
e = new KeyboardEvent("keydown", {
|
||||
key: "p",
|
||||
});
|
||||
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { Tab } from "@headlessui/react";
|
|||
import useLocalStorage from "hooks/use-local-storage";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// services
|
||||
import cycleService from "services/cycles.service";
|
||||
import projectService from "services/project.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ import {
|
|||
import { EmptyState, Loader, PrimaryButton } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// icons
|
||||
import { ChartBarIcon, PlusIcon, Squares2X2Icon } from "@heroicons/react/24/outline";
|
||||
import { PlusIcon, Squares2X2Icon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyModule from "public/empty-state/empty-module.svg";
|
||||
import emptyModule from "public/empty-state/module.svg";
|
||||
// types
|
||||
import { IModule, SelectModuleType } from "types/modules";
|
||||
import type { NextPage } from "next";
|
||||
|
|
@ -141,10 +141,17 @@ const ProjectModules: NextPage = () => {
|
|||
</div>
|
||||
) : (
|
||||
<EmptyState
|
||||
type="module"
|
||||
title="Create New Module"
|
||||
description="Modules are smaller, focused projects that help you group and organize issues within a specific time frame."
|
||||
imgURL={emptyModule}
|
||||
title="Manage your project with modules"
|
||||
description="Modules are smaller, focused projects that help you group and organize issues."
|
||||
image={emptyModule}
|
||||
buttonText="New Module"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "m",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import {
|
|||
} from "@heroicons/react/24/outline";
|
||||
import { ColorPalletteIcon, ClipboardIcon } from "components/icons";
|
||||
// helpers
|
||||
import { renderShortTime, renderShortDate } from "helpers/date-time.helper";
|
||||
import { render24HourFormatTime, renderShortDate } from "helpers/date-time.helper";
|
||||
import { copyTextToClipboard } from "helpers/string.helper";
|
||||
import { orderArrayBy } from "helpers/array.helper";
|
||||
// types
|
||||
|
|
@ -397,11 +397,11 @@ const SinglePage: NextPage = () => {
|
|||
<div className="flex items-center">
|
||||
<div className="flex items-center gap-6 text-custom-text-200">
|
||||
<Tooltip
|
||||
tooltipContent={`Last updated at ${renderShortTime(
|
||||
tooltipContent={`Last updated at ${render24HourFormatTime(
|
||||
pageDetails.updated_at
|
||||
)} on ${renderShortDate(pageDetails.updated_at)}`}
|
||||
>
|
||||
<p className="text-sm">{renderShortTime(pageDetails.updated_at)}</p>
|
||||
<p className="text-sm">{render24HourFormatTime(pageDetails.updated_at)}</p>
|
||||
</Tooltip>
|
||||
<button className="flex items-center gap-2" onClick={handleCopyText}>
|
||||
<LinkIcon className="h-4 w-4" />
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
|||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyEstimate from "public/empty-state/empty-estimate.svg";
|
||||
import emptyEstimate from "public/empty-state/estimate.svg";
|
||||
// types
|
||||
import { IEstimate, IProject } from "types";
|
||||
import type { NextPage } from "next";
|
||||
|
|
@ -158,13 +158,14 @@ const EstimatesSettings: NextPage = () => {
|
|||
))}
|
||||
</section>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center">
|
||||
<div className="h-full w-full overflow-y-auto">
|
||||
<EmptyState
|
||||
type="estimate"
|
||||
title="Create New Estimate"
|
||||
description="Estimates help you communicate the complexity of an issue. You can create your own estimate and communicate with your team."
|
||||
imgURL={emptyEstimate}
|
||||
action={() => {
|
||||
title="No estimates yet"
|
||||
description="Estimates help you communicate the complexity of an issue."
|
||||
image={emptyEstimate}
|
||||
buttonText="Add Estimate"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
setEstimateToUpdate(undefined);
|
||||
setEstimateFormOpen(true);
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -12,15 +12,12 @@ import projectService from "services/project.service";
|
|||
// components
|
||||
import { SettingsHeader, SingleIntegration } from "components/project";
|
||||
// ui
|
||||
import {
|
||||
EmptySpace,
|
||||
EmptySpaceItem,
|
||||
IntegrationAndImportExportBanner,
|
||||
Loader,
|
||||
} from "components/ui";
|
||||
import { EmptyState, IntegrationAndImportExportBanner, Loader } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// icons
|
||||
import { PlusIcon, PuzzlePieceIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyIntegration from "public/empty-state/integration.svg";
|
||||
// types
|
||||
import { IProject } from "types";
|
||||
import type { NextPage } from "next";
|
||||
|
|
@ -74,21 +71,13 @@ const ProjectIntegrations: NextPage = () => {
|
|||
</div>
|
||||
</section>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center">
|
||||
<EmptySpace
|
||||
title="You haven't added any integration yet."
|
||||
description="Add GitHub and other integrations to sync your project issues."
|
||||
Icon={PuzzlePieceIcon}
|
||||
>
|
||||
<EmptySpaceItem
|
||||
title="Add new integration"
|
||||
Icon={PlusIcon}
|
||||
action={() => {
|
||||
router.push(`/${workspaceSlug}/settings/integrations`);
|
||||
}}
|
||||
/>
|
||||
</EmptySpace>
|
||||
</div>
|
||||
<EmptyState
|
||||
title="You haven't configured integrations"
|
||||
description="Configure GitHub and other integrations to sync your project issues."
|
||||
image={emptyIntegration}
|
||||
buttonText="Configure now"
|
||||
onClick={() => router.push(`/${workspaceSlug}/settings/integrations`)}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Loader className="space-y-5">
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@ import {
|
|||
} from "components/labels";
|
||||
import { SettingsHeader } from "components/project";
|
||||
// ui
|
||||
import { Loader, PrimaryButton } from "components/ui";
|
||||
import { EmptyState, Loader, PrimaryButton } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyLabel from "public/empty-state/label.svg";
|
||||
// types
|
||||
import { IIssueLabels } from "types";
|
||||
import type { NextPage } from "next";
|
||||
|
|
@ -133,16 +135,33 @@ const LabelsSettings: NextPage = () => {
|
|||
)}
|
||||
<>
|
||||
{issueLabels ? (
|
||||
issueLabels.map((label) => {
|
||||
const children = issueLabels?.filter((l) => l.parent === label.id);
|
||||
issueLabels.length > 0 ? (
|
||||
issueLabels.map((label) => {
|
||||
const children = issueLabels?.filter((l) => l.parent === label.id);
|
||||
|
||||
if (children && children.length === 0) {
|
||||
if (!label.parent)
|
||||
if (children && children.length === 0) {
|
||||
if (!label.parent)
|
||||
return (
|
||||
<SingleLabel
|
||||
key={label.id}
|
||||
label={label}
|
||||
addLabelToGroup={() => addLabelToGroup(label)}
|
||||
editLabel={(label) => {
|
||||
editLabel(label);
|
||||
scrollToRef.current?.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
});
|
||||
}}
|
||||
handleLabelDelete={() => setSelectDeleteLabel(label)}
|
||||
/>
|
||||
);
|
||||
} else
|
||||
return (
|
||||
<SingleLabel
|
||||
<SingleLabelGroup
|
||||
key={label.id}
|
||||
label={label}
|
||||
addLabelToGroup={() => addLabelToGroup(label)}
|
||||
labelChildren={children}
|
||||
addLabelToGroup={addLabelToGroup}
|
||||
editLabel={(label) => {
|
||||
editLabel(label);
|
||||
scrollToRef.current?.scrollIntoView({
|
||||
|
|
@ -150,26 +169,20 @@ const LabelsSettings: NextPage = () => {
|
|||
});
|
||||
}}
|
||||
handleLabelDelete={() => setSelectDeleteLabel(label)}
|
||||
user={user}
|
||||
/>
|
||||
);
|
||||
} else
|
||||
return (
|
||||
<SingleLabelGroup
|
||||
key={label.id}
|
||||
label={label}
|
||||
labelChildren={children}
|
||||
addLabelToGroup={addLabelToGroup}
|
||||
editLabel={(label) => {
|
||||
editLabel(label);
|
||||
scrollToRef.current?.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
});
|
||||
}}
|
||||
handleLabelDelete={() => setSelectDeleteLabel(label)}
|
||||
user={user}
|
||||
/>
|
||||
);
|
||||
})
|
||||
})
|
||||
) : (
|
||||
<EmptyState
|
||||
title="No labels yet"
|
||||
description="Create labels to help organize and filter issues in you project"
|
||||
image={emptyLabel}
|
||||
buttonText="Add label"
|
||||
onClick={newLabel}
|
||||
isFullScreen={false}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Loader className="space-y-5">
|
||||
<Loader.Item height="40px" />
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
|||
//icons
|
||||
import { PlusIcon } from "components/icons";
|
||||
// images
|
||||
import emptyView from "public/empty-state/empty-view.svg";
|
||||
import emptyView from "public/empty-state/view.svg";
|
||||
// fetching keys
|
||||
import { PROJECT_DETAILS, VIEWS_LIST } from "constants/fetch-keys";
|
||||
// components
|
||||
|
|
@ -115,10 +115,17 @@ const ProjectViews: NextPage = () => {
|
|||
</div>
|
||||
) : (
|
||||
<EmptyState
|
||||
type="view"
|
||||
title="Create New View"
|
||||
title="Get focused with views"
|
||||
description="Views aid in saving your issues by applying various filters and grouping options."
|
||||
imgURL={emptyView}
|
||||
image={emptyView}
|
||||
buttonText="New View"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "v",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
|||
import { JoinProjectModal } from "components/project/join-project-modal";
|
||||
import { DeleteProjectModal, SingleProjectCard } from "components/project";
|
||||
// ui
|
||||
import { Loader, EmptyState, PrimaryButton } from "components/ui";
|
||||
import { EmptyState, Loader, PrimaryButton } from "components/ui";
|
||||
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
|
||||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyProject from "public/empty-state/empty-project.svg";
|
||||
import emptyProject from "public/empty-state/project.svg";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
|
|
@ -88,16 +88,7 @@ const ProjectsPage: NextPage = () => {
|
|||
/>
|
||||
{projects ? (
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
{projects.length === 0 ? (
|
||||
<div className="h-full w-full grid place-items-center p-8">
|
||||
<EmptyState
|
||||
type="project"
|
||||
title="Create New Project"
|
||||
description="Projects are a collection of issues. They can be used to represent the development work for a product, project, or service."
|
||||
imgURL={emptyProject}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
{projects.length > 0 ? (
|
||||
<div className="h-full p-8 overflow-y-auto">
|
||||
<div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
|
||||
{projects.map((project) => (
|
||||
|
|
@ -110,6 +101,20 @@ const ProjectsPage: NextPage = () => {
|
|||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<EmptyState
|
||||
image={emptyProject}
|
||||
title="No projects yet"
|
||||
description="Get started by creating your first project"
|
||||
buttonText="New Project"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "p",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue