chore: dashboard empty states, fetching logic (#3455)
* chore: remove one-time fetching * chore: update empty states * chore: updated icons * chore: empty state content
@ -50,32 +50,36 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetDetails) return;
|
const filterDates = getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week");
|
||||||
|
|
||||||
const filterDates = getCustomDates(widgetDetails.widget_filters.target_date ?? "this_week");
|
|
||||||
|
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
issue_type: widgetDetails.widget_filters.tab ?? "upcoming",
|
issue_type: widgetDetails?.widget_filters.tab ?? "upcoming",
|
||||||
target_date: filterDates,
|
target_date: filterDates,
|
||||||
expand: "issue_relation",
|
expand: "issue_relation",
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetDetails, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const filterParams = getRedirectionFilters(widgetDetails?.widget_filters.tab ?? "upcoming");
|
const filterParams = getRedirectionFilters(widgetDetails?.widget_filters.tab ?? "upcoming");
|
||||||
|
|
||||||
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col">
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col min-h-96">
|
||||||
<div className="flex items-center justify-between gap-2 p-6 pl-7">
|
<div className="flex items-start justify-between gap-2 p-6 pl-7">
|
||||||
|
<div>
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspaceSlug}/workspace-views/assigned/${filterParams}`}
|
href={`/${workspaceSlug}/workspace-views/assigned/${filterParams}`}
|
||||||
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
||||||
>
|
>
|
||||||
All issues assigned
|
Assigned to you
|
||||||
</Link>
|
</Link>
|
||||||
|
<p className="mt-3 text-xs font-medium text-custom-text-300">
|
||||||
|
Filtered by{" "}
|
||||||
|
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<DurationFilterDropdown
|
<DurationFilterDropdown
|
||||||
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
@ -97,11 +101,10 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
<div className="px-6">
|
<div className="px-6">
|
||||||
<TabsList />
|
<TabsList />
|
||||||
</div>
|
</div>
|
||||||
<Tab.Panels as="div" className="mt-7 h-full">
|
<Tab.Panels as="div" className="h-full">
|
||||||
{ISSUES_TABS_LIST.map((tab) => (
|
{ISSUES_TABS_LIST.map((tab) => (
|
||||||
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col">
|
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col">
|
||||||
<WidgetIssuesList
|
<WidgetIssuesList
|
||||||
filter={widgetDetails.widget_filters.target_date}
|
|
||||||
issues={widgetStats.issues}
|
issues={widgetStats.issues}
|
||||||
tab={tab.key}
|
tab={tab.key}
|
||||||
totalIssues={widgetStats.count}
|
totalIssues={widgetStats.count}
|
||||||
|
@ -49,29 +49,33 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetDetails) return;
|
|
||||||
|
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
issue_type: widgetDetails.widget_filters.tab ?? "upcoming",
|
issue_type: widgetDetails?.widget_filters.tab ?? "upcoming",
|
||||||
target_date: getCustomDates(widgetDetails.widget_filters.target_date ?? "this_week"),
|
target_date: getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week"),
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetDetails, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const filterParams = getRedirectionFilters(widgetDetails?.widget_filters.tab ?? "upcoming");
|
const filterParams = getRedirectionFilters(widgetDetails?.widget_filters.tab ?? "upcoming");
|
||||||
|
|
||||||
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col">
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col min-h-96">
|
||||||
<div className="flex items-center justify-between gap-2 p-6 pl-7">
|
<div className="flex items-start justify-between gap-2 p-6 pl-7">
|
||||||
|
<div>
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspaceSlug}/workspace-views/created/${filterParams}`}
|
href={`/${workspaceSlug}/workspace-views/created/${filterParams}`}
|
||||||
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
||||||
>
|
>
|
||||||
All issues created
|
Created by you
|
||||||
</Link>
|
</Link>
|
||||||
|
<p className="mt-3 text-xs font-medium text-custom-text-300">
|
||||||
|
Filtered by{" "}
|
||||||
|
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<DurationFilterDropdown
|
<DurationFilterDropdown
|
||||||
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
@ -93,11 +97,10 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
<div className="px-6">
|
<div className="px-6">
|
||||||
<TabsList />
|
<TabsList />
|
||||||
</div>
|
</div>
|
||||||
<Tab.Panels as="div" className="mt-7 h-full">
|
<Tab.Panels as="div" className="h-full">
|
||||||
{ISSUES_TABS_LIST.map((tab) => (
|
{ISSUES_TABS_LIST.map((tab) => (
|
||||||
<Tab.Panel as="div" className="h-full flex flex-col">
|
<Tab.Panel as="div" className="h-full flex flex-col">
|
||||||
<WidgetIssuesList
|
<WidgetIssuesList
|
||||||
filter={widgetDetails.widget_filters.target_date}
|
|
||||||
issues={widgetStats.issues}
|
issues={widgetStats.issues}
|
||||||
tab={tab.key}
|
tab={tab.key}
|
||||||
totalIssues={widgetStats.count}
|
totalIssues={widgetStats.count}
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// helpers
|
|
||||||
import { cn } from "helpers/common.helper";
|
|
||||||
// types
|
// types
|
||||||
import { TDurationFilterOptions, TIssuesListTypes } from "@plane/types";
|
import { TIssuesListTypes } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
import { ASSIGNED_ISSUES_EMPTY_STATES } from "constants/dashboard";
|
import { ASSIGNED_ISSUES_EMPTY_STATES } from "constants/dashboard";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
filter: TDurationFilterOptions;
|
|
||||||
type: TIssuesListTypes;
|
type: TIssuesListTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AssignedIssuesEmptyState: React.FC<Props> = (props) => {
|
export const AssignedIssuesEmptyState: React.FC<Props> = (props) => {
|
||||||
const { filter, type } = props;
|
const { type } = props;
|
||||||
// next-themes
|
// next-themes
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
@ -21,22 +18,13 @@ export const AssignedIssuesEmptyState: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const image = resolvedTheme === "dark" ? typeDetails.darkImage : typeDetails.lightImage;
|
const image = resolvedTheme === "dark" ? typeDetails.darkImage : typeDetails.lightImage;
|
||||||
|
|
||||||
|
// TODO: update empty state logic to use a general component
|
||||||
return (
|
return (
|
||||||
<div className="text-center space-y-10 mt-16 flex flex-col items-center">
|
<div className="text-center space-y-6 flex flex-col items-center">
|
||||||
<p className="text-sm font-medium text-custom-text-300">{typeDetails.title(filter)}</p>
|
<div className="h-24 w-24">
|
||||||
<div
|
|
||||||
className={cn("w-1/2 h-1/3 p-1.5 pb-0 rounded-t-md", {
|
|
||||||
"border border-custom-border-200": resolvedTheme === "dark",
|
|
||||||
})}
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
resolvedTheme === "light"
|
|
||||||
? "linear-gradient(135deg, rgba(235, 243, 255, 0.45) 3.57%, rgba(99, 161, 255, 0.24) 94.16%)"
|
|
||||||
: "",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image src={image} className="w-full h-full" alt="Assigned issues" />
|
<Image src={image} className="w-full h-full" alt="Assigned issues" />
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm font-medium text-custom-text-300 whitespace-pre-line">{typeDetails.title}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// helpers
|
|
||||||
import { cn } from "helpers/common.helper";
|
|
||||||
// types
|
// types
|
||||||
import { TDurationFilterOptions, TIssuesListTypes } from "@plane/types";
|
import { TIssuesListTypes } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
import { CREATED_ISSUES_EMPTY_STATES } from "constants/dashboard";
|
import { CREATED_ISSUES_EMPTY_STATES } from "constants/dashboard";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
filter: TDurationFilterOptions;
|
|
||||||
type: TIssuesListTypes;
|
type: TIssuesListTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreatedIssuesEmptyState: React.FC<Props> = (props) => {
|
export const CreatedIssuesEmptyState: React.FC<Props> = (props) => {
|
||||||
const { filter, type } = props;
|
const { type } = props;
|
||||||
// next-themes
|
// next-themes
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
@ -22,21 +19,11 @@ export const CreatedIssuesEmptyState: React.FC<Props> = (props) => {
|
|||||||
const image = resolvedTheme === "dark" ? typeDetails.darkImage : typeDetails.lightImage;
|
const image = resolvedTheme === "dark" ? typeDetails.darkImage : typeDetails.lightImage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="text-center space-y-10 mt-16 flex flex-col items-center">
|
<div className="text-center space-y-6 flex flex-col items-center">
|
||||||
<p className="text-sm font-medium text-custom-text-300">{typeDetails.title(filter)}</p>
|
<div className="h-24 w-24">
|
||||||
<div
|
<Image src={image} className="w-full h-full" alt="Assigned issues" />
|
||||||
className={cn("w-1/2 h-1/3 p-1.5 pb-0 rounded-t-md", {
|
|
||||||
"border border-custom-border-200": resolvedTheme === "dark",
|
|
||||||
})}
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
resolvedTheme === "light"
|
|
||||||
? "linear-gradient(135deg, rgba(235, 243, 255, 0.45) 3.57%, rgba(99, 161, 255, 0.24) 94.16%)"
|
|
||||||
: "",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image src={image} className="w-full h-full" alt="Created issues" />
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm font-medium text-custom-text-300 whitespace-pre-line">{typeDetails.title}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,43 +3,23 @@ import { useTheme } from "next-themes";
|
|||||||
// assets
|
// assets
|
||||||
import DarkImage from "public/empty-state/dashboard/dark/issues-by-priority.svg";
|
import DarkImage from "public/empty-state/dashboard/dark/issues-by-priority.svg";
|
||||||
import LightImage from "public/empty-state/dashboard/light/issues-by-priority.svg";
|
import LightImage from "public/empty-state/dashboard/light/issues-by-priority.svg";
|
||||||
// helpers
|
|
||||||
import { cn } from "helpers/common.helper";
|
|
||||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
|
||||||
// types
|
|
||||||
import { TDurationFilterOptions } from "@plane/types";
|
|
||||||
|
|
||||||
type Props = {
|
export const IssuesByPriorityEmptyState = () => {
|
||||||
filter: TDurationFilterOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const IssuesByPriorityEmptyState: React.FC<Props> = (props) => {
|
|
||||||
const { filter } = props;
|
|
||||||
// next-themes
|
// next-themes
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
|
const image = resolvedTheme === "dark" ? DarkImage : LightImage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="text-center space-y-10 mt-16 flex flex-col items-center">
|
<div className="text-center space-y-6 flex flex-col items-center">
|
||||||
<p className="text-sm font-medium text-custom-text-300">
|
<div className="h-24 w-24">
|
||||||
No assigned issues {replaceUnderscoreIfSnakeCase(filter)}.
|
<Image src={image} className="w-full h-full" alt="Issues by state group" />
|
||||||
</p>
|
|
||||||
<div
|
|
||||||
className={cn("w-1/2 h-1/3 p-1.5 pb-0 rounded-t-md", {
|
|
||||||
"border border-custom-border-200": resolvedTheme === "dark",
|
|
||||||
})}
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
resolvedTheme === "light"
|
|
||||||
? "linear-gradient(135deg, rgba(235, 243, 255, 0.45) 3.57%, rgba(99, 161, 255, 0.24) 94.16%)"
|
|
||||||
: "",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={resolvedTheme === "dark" ? DarkImage : LightImage}
|
|
||||||
className="w-full h-full"
|
|
||||||
alt="Issues by priority"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm font-medium text-custom-text-300">
|
||||||
|
Issues assigned to you, broken down by
|
||||||
|
<br />
|
||||||
|
priority will show up here.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,43 +3,23 @@ import { useTheme } from "next-themes";
|
|||||||
// assets
|
// assets
|
||||||
import DarkImage from "public/empty-state/dashboard/dark/issues-by-state-group.svg";
|
import DarkImage from "public/empty-state/dashboard/dark/issues-by-state-group.svg";
|
||||||
import LightImage from "public/empty-state/dashboard/light/issues-by-state-group.svg";
|
import LightImage from "public/empty-state/dashboard/light/issues-by-state-group.svg";
|
||||||
// helpers
|
|
||||||
import { cn } from "helpers/common.helper";
|
|
||||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
|
||||||
// types
|
|
||||||
import { TDurationFilterOptions } from "@plane/types";
|
|
||||||
|
|
||||||
type Props = {
|
export const IssuesByStateGroupEmptyState = () => {
|
||||||
filter: TDurationFilterOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const IssuesByStateGroupEmptyState: React.FC<Props> = (props) => {
|
|
||||||
const { filter } = props;
|
|
||||||
// next-themes
|
// next-themes
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
|
const image = resolvedTheme === "dark" ? DarkImage : LightImage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="text-center space-y-10 mt-16 flex flex-col items-center">
|
<div className="text-center space-y-6 flex flex-col items-center">
|
||||||
<p className="text-sm font-medium text-custom-text-300">
|
<div className="h-24 w-24">
|
||||||
No assigned issues {replaceUnderscoreIfSnakeCase(filter)}.
|
<Image src={image} className="w-full h-full" alt="Issues by state group" />
|
||||||
</p>
|
|
||||||
<div
|
|
||||||
className={cn("w-1/2 h-1/3 p-1.5 pb-0 rounded-t-md", {
|
|
||||||
"border border-custom-border-200": resolvedTheme === "dark",
|
|
||||||
})}
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
resolvedTheme === "light"
|
|
||||||
? "linear-gradient(135deg, rgba(235, 243, 255, 0.45) 3.57%, rgba(99, 161, 255, 0.24) 94.16%)"
|
|
||||||
: "",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={resolvedTheme === "dark" ? DarkImage : LightImage}
|
|
||||||
className="w-full h-full"
|
|
||||||
alt="Issues by state group"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm font-medium text-custom-text-300">
|
||||||
|
Issue assigned to you, broken down by state,
|
||||||
|
<br />
|
||||||
|
will show up here.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,40 +3,23 @@ import { useTheme } from "next-themes";
|
|||||||
// assets
|
// assets
|
||||||
import DarkImage from "public/empty-state/dashboard/dark/recent-activity.svg";
|
import DarkImage from "public/empty-state/dashboard/dark/recent-activity.svg";
|
||||||
import LightImage from "public/empty-state/dashboard/light/recent-activity.svg";
|
import LightImage from "public/empty-state/dashboard/light/recent-activity.svg";
|
||||||
// helpers
|
|
||||||
import { cn } from "helpers/common.helper";
|
|
||||||
|
|
||||||
type Props = {};
|
export const RecentActivityEmptyState = () => {
|
||||||
|
|
||||||
export const RecentActivityEmptyState: React.FC<Props> = (props) => {
|
|
||||||
const {} = props;
|
|
||||||
// next-themes
|
// next-themes
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
|
const image = resolvedTheme === "dark" ? DarkImage : LightImage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="text-center space-y-10 mt-16 flex flex-col items-center">
|
<div className="text-center space-y-6 flex flex-col items-center">
|
||||||
<p className="text-sm font-medium text-custom-text-300">
|
<div className="h-24 w-24">
|
||||||
Feels new, go and explore our tool in depth and come back
|
<Image src={image} className="w-full h-full" alt="Issues by state group" />
|
||||||
<br />
|
|
||||||
to see your activity.
|
|
||||||
</p>
|
|
||||||
<div
|
|
||||||
className={cn("w-3/5 h-1/3 p-1.5 pb-0 rounded-t-md", {
|
|
||||||
"border border-custom-border-200": resolvedTheme === "dark",
|
|
||||||
})}
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
resolvedTheme === "light"
|
|
||||||
? "linear-gradient(135deg, rgba(235, 243, 255, 0.45) 3.57%, rgba(99, 161, 255, 0.24) 94.16%)"
|
|
||||||
: "",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={resolvedTheme === "dark" ? DarkImage : LightImage}
|
|
||||||
className="w-full h-full"
|
|
||||||
alt="Issues by priority"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm font-medium text-custom-text-300">
|
||||||
|
All your issue activities across
|
||||||
|
<br />
|
||||||
|
projects will show up here.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,39 +1,38 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// assets
|
// assets
|
||||||
import DarkImage from "public/empty-state/dashboard/dark/recent-collaborators.svg";
|
import DarkImage1 from "public/empty-state/dashboard/dark/recent-collaborators-1.svg";
|
||||||
import LightImage from "public/empty-state/dashboard/light/recent-collaborators.svg";
|
import DarkImage2 from "public/empty-state/dashboard/dark/recent-collaborators-2.svg";
|
||||||
// helpers
|
import DarkImage3 from "public/empty-state/dashboard/dark/recent-collaborators-3.svg";
|
||||||
import { cn } from "helpers/common.helper";
|
import LightImage1 from "public/empty-state/dashboard/light/recent-collaborators-1.svg";
|
||||||
|
import LightImage2 from "public/empty-state/dashboard/light/recent-collaborators-2.svg";
|
||||||
|
import LightImage3 from "public/empty-state/dashboard/light/recent-collaborators-3.svg";
|
||||||
|
|
||||||
type Props = {};
|
export const RecentCollaboratorsEmptyState = () => {
|
||||||
|
|
||||||
export const RecentCollaboratorsEmptyState: React.FC<Props> = (props) => {
|
|
||||||
const {} = props;
|
|
||||||
// next-themes
|
// next-themes
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
|
const image1 = resolvedTheme === "dark" ? DarkImage1 : LightImage1;
|
||||||
|
const image2 = resolvedTheme === "dark" ? DarkImage2 : LightImage2;
|
||||||
|
const image3 = resolvedTheme === "dark" ? DarkImage3 : LightImage3;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-7 px-7 flex justify-between gap-16">
|
<div className="mt-7 mb-16 px-36 flex flex-col lg:flex-row items-center justify-between gap-x-24 gap-y-16">
|
||||||
<p className="text-sm font-medium text-custom-text-300">
|
<p className="text-sm font-medium text-custom-text-300 lg:w-2/5 flex-shrink-0 text-center lg:text-left">
|
||||||
People are excited to work with you, once they do you will find your frequent collaborators here.
|
Compare your activities with the top
|
||||||
|
<br />
|
||||||
|
seven in your project.
|
||||||
</p>
|
</p>
|
||||||
<div
|
<div className="flex items-center justify-evenly gap-20 lg:w-3/5 flex-shrink-0">
|
||||||
className={cn("w-3/5 h-1/3 p-1.5 pb-0 rounded-t-md flex-shrink-0 self-end", {
|
<div className="h-24 w-24 flex-shrink-0">
|
||||||
"border border-custom-border-200": resolvedTheme === "dark",
|
<Image src={image1} className="w-full h-full" alt="Recent collaborators" />
|
||||||
})}
|
</div>
|
||||||
style={{
|
<div className="h-24 w-24 flex-shrink-0">
|
||||||
background:
|
<Image src={image2} className="w-full h-full" alt="Recent collaborators" />
|
||||||
resolvedTheme === "light"
|
</div>
|
||||||
? "linear-gradient(135deg, rgba(235, 243, 255, 0.45) 3.57%, rgba(99, 161, 255, 0.24) 94.16%)"
|
<div className="h-24 w-24 flex-shrink-0 hidden xl:block">
|
||||||
: "",
|
<Image src={image3} className="w-full h-full" alt="Recent collaborators" />
|
||||||
}}
|
</div>
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={resolvedTheme === "dark" ? DarkImage : LightImage}
|
|
||||||
className="w-full h-full"
|
|
||||||
alt="Recent collaborators"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -19,10 +19,9 @@ import { Loader, getButtonStyling } from "@plane/ui";
|
|||||||
import { cn } from "helpers/common.helper";
|
import { cn } from "helpers/common.helper";
|
||||||
import { getRedirectionFilters } from "helpers/dashboard.helper";
|
import { getRedirectionFilters } from "helpers/dashboard.helper";
|
||||||
// types
|
// types
|
||||||
import { TDurationFilterOptions, TIssue, TIssuesListTypes } from "@plane/types";
|
import { TIssue, TIssuesListTypes } from "@plane/types";
|
||||||
|
|
||||||
export type WidgetIssuesListProps = {
|
export type WidgetIssuesListProps = {
|
||||||
filter: TDurationFilterOptions | undefined;
|
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
issues: TIssue[];
|
issues: TIssue[];
|
||||||
tab: TIssuesListTypes;
|
tab: TIssuesListTypes;
|
||||||
@ -32,7 +31,7 @@ export type WidgetIssuesListProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
||||||
const { filter, isLoading, issues, tab, totalIssues, type, workspaceSlug } = props;
|
const { isLoading, issues, tab, totalIssues, type, workspaceSlug } = props;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { setPeekIssue } = useIssueDetail();
|
const { setPeekIssue } = useIssueDetail();
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
|||||||
<>
|
<>
|
||||||
<div className="h-full">
|
<div className="h-full">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Loader className="mx-6 mt-2 space-y-4">
|
<Loader className="mt-7 mx-6 space-y-4">
|
||||||
<Loader.Item height="25px" />
|
<Loader.Item height="25px" />
|
||||||
<Loader.Item height="25px" />
|
<Loader.Item height="25px" />
|
||||||
<Loader.Item height="25px" />
|
<Loader.Item height="25px" />
|
||||||
@ -70,7 +69,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
|||||||
</Loader>
|
</Loader>
|
||||||
) : issues.length > 0 ? (
|
) : issues.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<div className="mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-6 gap-1 text-xs text-custom-text-300 pb-1">
|
<div className="mt-7 mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-6 gap-1 text-xs text-custom-text-300 pb-1">
|
||||||
<h6
|
<h6
|
||||||
className={cn("pl-1 flex items-center gap-1 col-span-4", {
|
className={cn("pl-1 flex items-center gap-1 col-span-4", {
|
||||||
"col-span-6": type === "assigned" && tab === "completed",
|
"col-span-6": type === "assigned" && tab === "completed",
|
||||||
@ -105,9 +104,9 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-full grid items-end">
|
<div className="h-full grid place-items-center">
|
||||||
{type === "assigned" && <AssignedIssuesEmptyState filter={filter ?? "this_week"} type={tab} />}
|
{type === "assigned" && <AssignedIssuesEmptyState type={tab} />}
|
||||||
{type === "created" && <CreatedIssuesEmptyState filter={filter ?? "this_week"} type={tab} />}
|
{type === "created" && <CreatedIssuesEmptyState type={tab} />}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,14 +91,12 @@ export const IssuesByPriorityWidget: React.FC<WidgetProps> = observer((props) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetDetails) return;
|
|
||||||
|
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
target_date: getCustomDates(widgetDetails.widget_filters.target_date ?? "this_week"),
|
target_date: getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week"),
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetDetails, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||||
|
|
||||||
@ -130,14 +128,20 @@ export const IssuesByPriorityWidget: React.FC<WidgetProps> = observer((props) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 overflow-hidden">
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 overflow-hidden min-h-96">
|
||||||
<div className="flex items-center justify-between gap-2 pl-7 pr-6">
|
<div className="flex items-start justify-between gap-2 pl-7 pr-6">
|
||||||
|
<div>
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspaceSlug}/workspace-views/assigned`}
|
href={`/${workspaceSlug}/workspace-views/assigned`}
|
||||||
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
||||||
>
|
>
|
||||||
Priority of assigned issues
|
Assigned by priority
|
||||||
</Link>
|
</Link>
|
||||||
|
<p className="mt-3 text-xs font-medium text-custom-text-300">
|
||||||
|
Filtered by{" "}
|
||||||
|
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<DurationFilterDropdown
|
<DurationFilterDropdown
|
||||||
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
@ -196,8 +200,8 @@ export const IssuesByPriorityWidget: React.FC<WidgetProps> = observer((props) =>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-full grid items-end">
|
<div className="h-full grid place-items-center">
|
||||||
<IssuesByPriorityEmptyState filter={widgetDetails.widget_filters.target_date ?? "this_week"} />
|
<IssuesByPriorityEmptyState />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,14 +51,12 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
|
|||||||
|
|
||||||
// fetch widget stats
|
// fetch widget stats
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetDetails) return;
|
|
||||||
|
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
target_date: getCustomDates(widgetDetails.widget_filters.target_date ?? "this_week"),
|
target_date: getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week"),
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetDetails, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
// set active group for center metric
|
// set active group for center metric
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -129,14 +127,20 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 overflow-hidden">
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 overflow-hidden min-h-96">
|
||||||
<div className="flex items-center justify-between gap-2 pl-7 pr-6">
|
<div className="flex items-start justify-between gap-2 pl-7 pr-6">
|
||||||
|
<div>
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspaceSlug}/workspace-views/assigned`}
|
href={`/${workspaceSlug}/workspace-views/assigned`}
|
||||||
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
className="text-lg font-semibold text-custom-text-300 hover:underline"
|
||||||
>
|
>
|
||||||
State of assigned issues
|
Assigned by state
|
||||||
</Link>
|
</Link>
|
||||||
|
<p className="mt-3 text-xs font-medium text-custom-text-300">
|
||||||
|
Filtered by{" "}
|
||||||
|
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<DurationFilterDropdown
|
<DurationFilterDropdown
|
||||||
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
value={widgetDetails.widget_filters.target_date ?? "this_week"}
|
||||||
onChange={(val) =>
|
onChange={(val) =>
|
||||||
@ -204,8 +208,8 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-full grid items-end">
|
<div className="h-full grid place-items-center">
|
||||||
<IssuesByStateGroupEmptyState filter={widgetDetails.widget_filters.target_date ?? "this_week"} />
|
<IssuesByStateGroupEmptyState />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,11 +54,11 @@ export const OverviewStatsWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||||
|
|
||||||
|
@ -25,18 +25,18 @@ export const RecentActivityWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
const widgetStats = getWidgetStats<TRecentActivityWidgetResponse[]>(workspaceSlug, dashboardId, WIDGET_KEY);
|
const widgetStats = getWidgetStats<TRecentActivityWidgetResponse[]>(workspaceSlug, dashboardId, WIDGET_KEY);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300">
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 min-h-96">
|
||||||
<Link href="/profile/activity" className="text-lg font-semibold text-custom-text-300 mx-7 hover:underline">
|
<Link href="/profile/activity" className="text-lg font-semibold text-custom-text-300 mx-7 hover:underline">
|
||||||
My activity
|
Your issue activities
|
||||||
</Link>
|
</Link>
|
||||||
{widgetStats.length > 0 ? (
|
{widgetStats.length > 0 ? (
|
||||||
<div className="space-y-6 mt-4 mx-7">
|
<div className="space-y-6 mt-4 mx-7">
|
||||||
@ -85,7 +85,7 @@ export const RecentActivityWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-full grid items-end">
|
<div className="h-full grid place-items-center">
|
||||||
<RecentActivityEmptyState />
|
<RecentActivityEmptyState />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -57,18 +57,21 @@ export const RecentCollaboratorsWidget: React.FC<WidgetProps> = observer((props)
|
|||||||
const widgetStats = getWidgetStats<TRecentCollaboratorsWidgetResponse[]>(workspaceSlug, dashboardId, WIDGET_KEY);
|
const widgetStats = getWidgetStats<TRecentCollaboratorsWidgetResponse[]>(workspaceSlug, dashboardId, WIDGET_KEY);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300">
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300">
|
||||||
<div className="flex items-center justify-between gap-2 px-7 pt-6">
|
<div className="px-7 pt-6">
|
||||||
<h4 className="text-lg font-semibold text-custom-text-300">Collaborators</h4>
|
<h4 className="text-lg font-semibold text-custom-text-300">Most active members</h4>
|
||||||
|
<p className="mt-2 text-xs font-medium text-custom-text-300">
|
||||||
|
Top eight active members in your project by last activity
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{widgetStats.length > 1 ? (
|
{widgetStats.length > 1 ? (
|
||||||
<div className="mt-7 mb-6 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 xl:grid-cols-8 gap-2 gap-y-8">
|
<div className="mt-7 mb-6 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 xl:grid-cols-8 gap-2 gap-y-8">
|
||||||
@ -82,7 +85,7 @@ export const RecentCollaboratorsWidget: React.FC<WidgetProps> = observer((props)
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-full grid items-end">
|
<div className="h-full grid place-items-center">
|
||||||
<RecentCollaboratorsEmptyState />
|
<RecentCollaboratorsEmptyState />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -81,21 +81,21 @@ export const RecentProjectsWidget: React.FC<WidgetProps> = observer((props) => {
|
|||||||
const canCreateProject = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
|
const canCreateProject = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetStats)
|
|
||||||
fetchWidgetStats(workspaceSlug, dashboardId, {
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
||||||
widget_key: WIDGET_KEY,
|
widget_key: WIDGET_KEY,
|
||||||
});
|
});
|
||||||
}, [dashboardId, fetchWidgetStats, widgetStats, workspaceSlug]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300">
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 min-h-96">
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspaceSlug}/projects`}
|
href={`/${workspaceSlug}/projects`}
|
||||||
className="text-lg font-semibold text-custom-text-300 mx-7 hover:underline"
|
className="text-lg font-semibold text-custom-text-300 mx-7 hover:underline"
|
||||||
>
|
>
|
||||||
My projects
|
Your projects
|
||||||
</Link>
|
</Link>
|
||||||
<div className="space-y-8 mt-4 mx-7">
|
<div className="space-y-8 mt-4 mx-7">
|
||||||
{canCreateProject && (
|
{canCreateProject && (
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
import { linearGradientDef } from "@nivo/core";
|
import { linearGradientDef } from "@nivo/core";
|
||||||
// assets
|
// assets
|
||||||
import UpcomingAssignedIssuesDark from "public/empty-state/dashboard/dark/upcoming-assigned-issues.svg";
|
import UpcomingIssuesDark from "public/empty-state/dashboard/dark/upcoming-issues.svg";
|
||||||
import UpcomingAssignedIssuesLight from "public/empty-state/dashboard/light/upcoming-assigned-issues.svg";
|
import UpcomingIssuesLight from "public/empty-state/dashboard/light/upcoming-issues.svg";
|
||||||
import OverdueAssignedIssuesDark from "public/empty-state/dashboard/dark/overdue-assigned-issues.svg";
|
import OverdueIssuesDark from "public/empty-state/dashboard/dark/overdue-issues.svg";
|
||||||
import OverdueAssignedIssuesLight from "public/empty-state/dashboard/light/overdue-assigned-issues.svg";
|
import OverdueIssuesLight from "public/empty-state/dashboard/light/overdue-issues.svg";
|
||||||
import CompletedAssignedIssuesDark from "public/empty-state/dashboard/dark/completed-assigned-issues.svg";
|
import CompletedIssuesDark from "public/empty-state/dashboard/dark/completed-issues.svg";
|
||||||
import CompletedAssignedIssuesLight from "public/empty-state/dashboard/light/completed-assigned-issues.svg";
|
import CompletedIssuesLight from "public/empty-state/dashboard/light/completed-issues.svg";
|
||||||
import UpcomingCreatedIssuesDark from "public/empty-state/dashboard/dark/upcoming-created-issues.svg";
|
|
||||||
import UpcomingCreatedIssuesLight from "public/empty-state/dashboard/light/upcoming-created-issues.svg";
|
|
||||||
import OverdueCreatedIssuesDark from "public/empty-state/dashboard/dark/overdue-created-issues.svg";
|
|
||||||
import OverdueCreatedIssuesLight from "public/empty-state/dashboard/light/overdue-created-issues.svg";
|
|
||||||
import CompletedCreatedIssuesDark from "public/empty-state/dashboard/dark/completed-created-issues.svg";
|
|
||||||
import CompletedCreatedIssuesLight from "public/empty-state/dashboard/light/completed-created-issues.svg";
|
|
||||||
// types
|
// types
|
||||||
import { TDurationFilterOptions, TIssuesListTypes, TStateGroups } from "@plane/types";
|
import { TDurationFilterOptions, TIssuesListTypes, TStateGroups } from "@plane/types";
|
||||||
import { Props } from "components/icons/types";
|
import { Props } from "components/icons/types";
|
||||||
@ -172,84 +166,43 @@ export const ISSUES_TABS_LIST: {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "completed",
|
key: "completed",
|
||||||
label: "Completed",
|
label: "Marked completed",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// empty state constants
|
|
||||||
const ASSIGNED_ISSUES_DURATION_TITLES: {
|
|
||||||
[type in TIssuesListTypes]: {
|
|
||||||
[duration in TDurationFilterOptions]: string;
|
|
||||||
};
|
|
||||||
} = {
|
|
||||||
upcoming: {
|
|
||||||
today: "today",
|
|
||||||
this_week: "yet in this week",
|
|
||||||
this_month: "yet in this month",
|
|
||||||
this_year: "yet in this year",
|
|
||||||
},
|
|
||||||
overdue: {
|
|
||||||
today: "today",
|
|
||||||
this_week: "in this week",
|
|
||||||
this_month: "in this month",
|
|
||||||
this_year: "in this year",
|
|
||||||
},
|
|
||||||
completed: {
|
|
||||||
today: "today",
|
|
||||||
this_week: "this week",
|
|
||||||
this_month: "this month",
|
|
||||||
this_year: "this year",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const CREATED_ISSUES_DURATION_TITLES: {
|
|
||||||
[duration in TDurationFilterOptions]: string;
|
|
||||||
} = {
|
|
||||||
today: "today",
|
|
||||||
this_week: "in this week",
|
|
||||||
this_month: "in this month",
|
|
||||||
this_year: "in this year",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ASSIGNED_ISSUES_EMPTY_STATES = {
|
export const ASSIGNED_ISSUES_EMPTY_STATES = {
|
||||||
upcoming: {
|
upcoming: {
|
||||||
title: (duration: TDurationFilterOptions) =>
|
title: "Upcoming issues assigned to\nyou will show up here.",
|
||||||
`No issues assigned to you ${ASSIGNED_ISSUES_DURATION_TITLES.upcoming[duration]}.`,
|
darkImage: UpcomingIssuesDark,
|
||||||
darkImage: UpcomingAssignedIssuesDark,
|
lightImage: UpcomingIssuesLight,
|
||||||
lightImage: UpcomingAssignedIssuesLight,
|
|
||||||
},
|
},
|
||||||
overdue: {
|
overdue: {
|
||||||
title: (duration: TDurationFilterOptions) =>
|
title: "Issues assigned to you that are past\ntheir due date will show up here.",
|
||||||
`No issues with due dates ${ASSIGNED_ISSUES_DURATION_TITLES.overdue[duration]} are open.`,
|
darkImage: OverdueIssuesDark,
|
||||||
darkImage: OverdueAssignedIssuesDark,
|
lightImage: OverdueIssuesLight,
|
||||||
lightImage: OverdueAssignedIssuesLight,
|
|
||||||
},
|
},
|
||||||
completed: {
|
completed: {
|
||||||
title: (duration: TDurationFilterOptions) =>
|
title: "Issues assigned to you that you have\nmarked Completed will show up here.",
|
||||||
`No issues completed by you ${ASSIGNED_ISSUES_DURATION_TITLES.completed[duration]}.`,
|
darkImage: CompletedIssuesDark,
|
||||||
darkImage: CompletedAssignedIssuesDark,
|
lightImage: CompletedIssuesLight,
|
||||||
lightImage: CompletedAssignedIssuesLight,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CREATED_ISSUES_EMPTY_STATES = {
|
export const CREATED_ISSUES_EMPTY_STATES = {
|
||||||
upcoming: {
|
upcoming: {
|
||||||
title: (duration: TDurationFilterOptions) =>
|
title: "Upcoming issues you created\nwill show up here.",
|
||||||
`No created issues have deadlines coming up ${CREATED_ISSUES_DURATION_TITLES[duration]}.`,
|
darkImage: UpcomingIssuesDark,
|
||||||
darkImage: UpcomingCreatedIssuesDark,
|
lightImage: UpcomingIssuesLight,
|
||||||
lightImage: UpcomingCreatedIssuesLight,
|
|
||||||
},
|
},
|
||||||
overdue: {
|
overdue: {
|
||||||
title: (duration: TDurationFilterOptions) =>
|
title: "Issues created by you that are past their\ndue date will show up here.",
|
||||||
`No created issues with due dates ${CREATED_ISSUES_DURATION_TITLES[duration]} are open.`,
|
darkImage: OverdueIssuesDark,
|
||||||
darkImage: OverdueCreatedIssuesDark,
|
lightImage: OverdueIssuesLight,
|
||||||
lightImage: OverdueCreatedIssuesLight,
|
|
||||||
},
|
},
|
||||||
completed: {
|
completed: {
|
||||||
title: (duration: TDurationFilterOptions) =>
|
title: "Issues created by you that you have\nmarked completed will show up here.",
|
||||||
`No created issues are completed ${CREATED_ISSUES_DURATION_TITLES[duration]}.`,
|
darkImage: CompletedIssuesDark,
|
||||||
darkImage: CompletedCreatedIssuesDark,
|
lightImage: CompletedIssuesLight,
|
||||||
lightImage: CompletedCreatedIssuesLight,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 144 KiB |
Before Width: | Height: | Size: 249 KiB |
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="46.7188" cy="46.7188" r="46.7188" fill="#171717"/>
|
||||||
|
<path d="M47.0013 72.8346C61.2687 72.8346 72.8346 61.2687 72.8346 47.0013C72.8346 32.7339 61.2687 21.168 47.0013 21.168C32.7339 21.168 21.168 32.7339 21.168 47.0013C21.168 61.2687 32.7339 72.8346 47.0013 72.8346Z" stroke="#4C4C4F" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M34.082 47L41.832 54.75L57.332 39.25" stroke="#696B74" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 593 B |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 666 B |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 202 KiB |
Before Width: | Height: | Size: 275 KiB |
9
web/public/empty-state/dashboard/dark/overdue-issues.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="46.7188" cy="46.7188" r="46.7188" fill="#171717"/>
|
||||||
|
<path d="M69.625 35.4362V31.7487C69.625 30.4447 69.107 29.1941 68.1849 28.2721C67.2629 27.35 66.0123 26.832 64.7083 26.832H30.2917C28.9877 26.832 27.7371 27.35 26.8151 28.2721C25.893 29.1941 25.375 30.4447 25.375 31.7487V66.1654C25.375 67.4693 25.893 68.7199 26.8151 69.642C27.7371 70.564 28.9877 71.082 30.2917 71.082H38.8958" stroke="#4C4C4F" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M57.332 21.918V31.7513" stroke="#696B74" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M37.668 21.918V31.7513" stroke="#696B74" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M25.375 41.582H37.6667" stroke="#4C4C4F" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M61.0195 60.0221L57.332 57.0721V51.418" stroke="#696B74" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M57.332 71.082C65.4782 71.082 72.082 64.4782 72.082 56.332C72.082 48.1858 65.4782 41.582 57.332 41.582C49.1858 41.582 42.582 48.1858 42.582 56.332C42.582 64.4782 49.1858 71.082 57.332 71.082Z" stroke="#696B74" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 363 KiB After Width: | Height: | Size: 941 B |
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="100" cy="100" r="100" fill="#171717"/>
|
||||||
|
<path d="M99.6846 98.4238C113.579 98.4238 124.842 87.1606 124.842 73.2666C124.842 59.3726 113.579 48.1094 99.6846 48.1094C85.7906 48.1094 74.5273 59.3726 74.5273 73.2666C74.5273 87.1606 85.7906 98.4238 99.6846 98.4238Z" fill="#696B74"/>
|
||||||
|
<path d="M145.28 139.701C145.28 129.228 139.926 119.183 132.014 111.777C124.101 104.372 113.37 100.211 102.18 100.211C90.9898 100.211 80.2583 104.372 72.3459 111.777C64.4334 119.183 59.9883 129.228 59.9883 139.701" fill="#363638" stroke="#363638" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M144.723 135.61C146.059 140.899 140.278 147.705 132.365 152.07C124.453 156.436 115.016 158.204 103.826 158.204C92.636 158.204 81.9044 155.751 73.992 151.386C65.8129 148.307 57.5454 140.561 61.6344 134.926L103.826 134.926L144.723 135.61Z" fill="#363638"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 972 B |
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="100" cy="100" r="100" fill="#171717"/>
|
||||||
|
<path d="M99.6846 98.4238C113.579 98.4238 124.842 87.1606 124.842 73.2666C124.842 59.3727 113.579 48.1094 99.6846 48.1094C85.7906 48.1094 74.5273 59.3727 74.5273 73.2666C74.5273 87.1606 85.7906 98.4238 99.6846 98.4238Z" fill="#323232"/>
|
||||||
|
<path d="M145.28 139.701C145.28 129.228 139.926 119.183 132.014 111.777C124.101 104.372 113.37 100.211 102.18 100.211C90.9898 100.211 80.2583 104.372 72.3459 111.777C64.4334 119.183 59.9883 129.228 59.9883 139.701" fill="#505050" stroke="#505050" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M144.723 135.61C146.059 140.899 140.278 147.705 132.365 152.07C124.453 156.436 115.016 158.204 103.826 158.204C92.636 158.204 81.9044 155.751 73.992 151.386C65.8129 148.307 57.5454 140.561 61.6344 134.926L103.826 134.926L144.723 135.61Z" fill="#505050"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 972 B |
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="100" cy="100" r="100" fill="#171717"/>
|
||||||
|
<path d="M99.6846 98.4238C113.579 98.4238 124.842 87.1606 124.842 73.2666C124.842 59.3726 113.579 48.1094 99.6846 48.1094C85.7906 48.1094 74.5273 59.3726 74.5273 73.2666C74.5273 87.1606 85.7906 98.4238 99.6846 98.4238Z" fill="#3B3D40"/>
|
||||||
|
<path d="M145.28 139.701C145.28 129.228 139.926 119.183 132.014 111.777C124.101 104.372 113.37 100.211 102.18 100.211C90.9898 100.211 80.2583 104.372 72.3459 111.777C64.4334 119.183 59.9883 129.228 59.9883 139.701" fill="#4E4E54" stroke="#4E4E54" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M144.723 135.61C146.059 140.899 140.278 147.705 132.365 152.07C124.453 156.436 115.016 158.204 103.826 158.204C92.636 158.204 81.9044 155.751 73.992 151.386C65.8129 148.307 57.5454 140.561 61.6344 134.926L103.826 134.926L144.723 135.61Z" fill="#4E4E54"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 972 B |
Before Width: | Height: | Size: 306 KiB |
Before Width: | Height: | Size: 215 KiB |
Before Width: | Height: | Size: 285 KiB |
13
web/public/empty-state/dashboard/dark/upcoming-issues.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="46.7188" cy="46.7188" r="46.7188" fill="#171717"/>
|
||||||
|
<g clip-path="url(#clip0_6556_126714)">
|
||||||
|
<path d="M22.3683 30.8508L46.374 21.6169C47.6902 21.1106 49.1029 22.0889 49.0919 23.4991L49.0807 24.9392L48.5304 51.0826C48.5125 51.9323 47.9595 52.6779 47.1516 52.9418L27.2534 59.4394L23.7288 60.635C22.4318 61.075 21.0863 60.1106 21.0863 58.741L21.0863 32.7175C21.0863 31.89 21.5959 31.1479 22.3683 30.8508Z" fill="#5D5D63"/>
|
||||||
|
<path d="M32.9995 38.1587L57.0052 28.9248C58.3214 28.4185 59.7342 29.3968 59.7232 30.807L59.712 32.2471L59.7119 57.5857C59.7119 58.4323 59.1789 59.1872 58.3811 59.4704L37.8846 66.7473L34.36 67.9429C33.0631 68.3829 31.7175 67.4185 31.7175 66.0489L31.7175 40.0254C31.7175 39.1979 32.2272 38.4558 32.9995 38.1587Z" fill="#4E4E54"/>
|
||||||
|
<path d="M68.8117 65.0919C69.5835 64.795 70.0929 64.0537 70.0935 63.2267L70.1116 37.3209C70.1126 35.9167 68.7041 34.9487 67.3936 35.4528L43.3671 44.6948C42.5947 44.9919 42.0851 45.7339 42.0851 46.5615L42.0851 72.4629C42.0851 73.8666 43.4932 74.8336 44.8033 74.3295L68.8117 65.0919Z" fill="#323333"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_6556_126714">
|
||||||
|
<rect width="69" height="69" fill="white" transform="translate(81 13) rotate(90)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 249 KiB |
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="46.7188" cy="46.7188" r="46.7188" fill="#F9F9FB"/>
|
||||||
|
<path d="M47.0013 72.8346C61.2687 72.8346 72.8346 61.2687 72.8346 47.0013C72.8346 32.7339 61.2687 21.168 47.0013 21.168C32.7339 21.168 21.168 32.7339 21.168 47.0013C21.168 61.2687 32.7339 72.8346 47.0013 72.8346Z" stroke="#CDCED6" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M34.082 47L41.832 54.75L57.332 39.25" stroke="#B9BBC6" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 593 B |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 666 B |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 204 KiB |
Before Width: | Height: | Size: 275 KiB |
@ -0,0 +1,9 @@
|
|||||||
|
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="46.7188" cy="46.7188" r="46.7188" fill="#F9F9FB"/>
|
||||||
|
<path d="M74.5 34.2487V29.9987C74.5 28.4958 73.903 27.0545 72.8403 25.9918C71.7776 24.9291 70.3362 24.332 68.8333 24.332H29.1667C27.6638 24.332 26.2224 24.9291 25.1597 25.9918C24.097 27.0545 23.5 28.4958 23.5 29.9987V69.6654C23.5 71.1683 24.097 72.6096 25.1597 73.6723C26.2224 74.735 27.6638 75.332 29.1667 75.332H39.0833" stroke="#D9D9E0" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M60.332 18.668V30.0013" stroke="#CDCED6" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M37.668 18.668V30.0013" stroke="#CDCED6" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M23.5 41.332H37.6667" stroke="#D9D9E0" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M64.582 62.5846L60.332 59.1846V52.668" stroke="#B9BBC6" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M60.332 75.332C69.7209 75.332 77.332 67.7209 77.332 58.332C77.332 48.9432 69.7209 41.332 60.332 41.332C50.9432 41.332 43.332 48.9432 43.332 58.332C43.332 67.7209 50.9432 75.332 60.332 75.332Z" stroke="#B9BBC6" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 363 KiB After Width: | Height: | Size: 941 B |
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="98" height="98" viewBox="0 0 98 98" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="49" cy="49" r="49" fill="#F8F9FA"/>
|
||||||
|
<path d="M48.8466 48.2283C55.6546 48.2283 61.1736 42.7093 61.1736 35.9013C61.1736 29.0932 55.6546 23.5742 48.8466 23.5742C42.0385 23.5742 36.5195 29.0932 36.5195 35.9013C36.5195 42.7093 42.0385 48.2283 48.8466 48.2283Z" fill="#F0F0F3"/>
|
||||||
|
<path d="M71.1877 68.4519C71.1877 63.3199 68.564 58.398 64.6869 54.7691C60.8098 51.1402 55.5514 49.1016 50.0683 49.1016C44.5853 49.1016 39.3268 51.1402 35.4497 54.7691C31.5727 58.398 29.3945 63.3199 29.3945 68.4519" fill="#CED4DA"/>
|
||||||
|
<path d="M71.1877 68.4519C71.1877 63.3199 68.564 58.398 64.6869 54.7691C60.8098 51.1402 55.5514 49.1016 50.0683 49.1016C44.5853 49.1016 39.3268 51.1402 35.4497 54.7691C31.5727 58.398 29.3945 63.3199 29.3945 68.4519C32.1264 78.8118 67.0106 81.1231 71.1877 68.4519Z" stroke="#CED4DA" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M70.9144 66.4486C71.5691 69.0402 68.7363 72.3749 64.8592 74.514C60.9821 76.6531 56.3578 77.5195 50.8747 77.5195C45.3917 77.5195 40.1332 76.3178 36.2562 74.1787C32.2484 72.6698 28.1973 68.8746 30.2009 66.1133L50.8747 66.1133L70.9144 66.4486Z" fill="#CED4DA"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="98" height="98" viewBox="0 0 98 98" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="49" cy="49" r="49" fill="#F8F9FA"/>
|
||||||
|
<path d="M48.8466 48.2283C55.6546 48.2283 61.1736 42.7093 61.1736 35.9013C61.1736 29.0932 55.6546 23.5742 48.8466 23.5742C42.0385 23.5742 36.5195 29.0932 36.5195 35.9013C36.5195 42.7093 42.0385 48.2283 48.8466 48.2283Z" fill="#E0E0E0"/>
|
||||||
|
<path d="M71.1877 68.4519C71.1877 63.3199 68.564 58.398 64.6869 54.7691C60.8098 51.1402 55.5514 49.1016 50.0683 49.1016C44.5853 49.1016 39.3268 51.1402 35.4497 54.7691C31.5727 58.398 29.3945 63.3199 29.3945 68.4519" fill="#B9BBC6"/>
|
||||||
|
<path d="M71.1877 68.4519C71.1877 63.3199 68.564 58.398 64.6869 54.7691C60.8098 51.1402 55.5514 49.1016 50.0683 49.1016C44.5853 49.1016 39.3268 51.1402 35.4497 54.7691C31.5727 58.398 29.3945 63.3199 29.3945 68.4519C32.1264 78.8118 67.0106 81.1231 71.1877 68.4519Z" stroke="#B9BBC6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M70.9144 66.4486C71.5691 69.0402 68.7363 72.3749 64.8592 74.514C60.9821 76.6531 56.3578 77.5195 50.8747 77.5195C45.3917 77.5195 40.1332 76.3178 36.2562 74.1787C32.2484 72.6698 28.1973 68.8746 30.2009 66.1133L50.8747 66.1133L70.9144 66.4486Z" fill="#B9BBC6"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="98" height="98" viewBox="0 0 98 98" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="49" cy="49" r="49" fill="#F8F9FA"/>
|
||||||
|
<path d="M48.8466 48.2283C55.6546 48.2283 61.1736 42.7093 61.1736 35.9013C61.1736 29.0932 55.6546 23.5742 48.8466 23.5742C42.0385 23.5742 36.5195 29.0932 36.5195 35.9013C36.5195 42.7093 42.0385 48.2283 48.8466 48.2283Z" fill="#CDCED6"/>
|
||||||
|
<path d="M71.1877 68.4519C71.1877 63.3199 68.564 58.398 64.6869 54.7691C60.8098 51.1402 55.5514 49.1016 50.0683 49.1016C44.5853 49.1016 39.3268 51.1402 35.4497 54.7691C31.5727 58.398 29.3945 63.3199 29.3945 68.4519" fill="#E0E1E6"/>
|
||||||
|
<path d="M71.1877 68.4519C71.1877 63.3199 68.564 58.398 64.6869 54.7691C60.8098 51.1402 55.5514 49.1016 50.0683 49.1016C44.5853 49.1016 39.3268 51.1402 35.4497 54.7691C31.5727 58.398 29.3945 63.3199 29.3945 68.4519C32.1264 78.8118 67.0106 81.1231 71.1877 68.4519Z" stroke="#E0E1E6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M70.9144 66.4486C71.5691 69.0402 68.7363 72.3749 64.8592 74.514C60.9821 76.6531 56.3578 77.5195 50.8747 77.5195C45.3917 77.5195 40.1332 76.3178 36.2562 74.1787C32.2484 72.6698 28.1973 68.8746 30.2009 66.1133L50.8747 66.1133L70.9144 66.4486Z" fill="#E0E1E6"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 305 KiB |
Before Width: | Height: | Size: 218 KiB |
Before Width: | Height: | Size: 285 KiB |
13
web/public/empty-state/dashboard/light/upcoming-issues.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg width="94" height="94" viewBox="0 0 94 94" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="46.7188" cy="46.7188" r="46.7188" fill="#F9F9FB"/>
|
||||||
|
<g clip-path="url(#clip0_6465_168324)">
|
||||||
|
<path d="M22.3683 30.8508L46.374 21.6169C47.6902 21.1106 49.1029 22.0889 49.0919 23.4991L49.0807 24.9392L48.5304 51.0826C48.5125 51.9323 47.9595 52.6779 47.1516 52.9418L27.2534 59.4394L23.7288 60.635C22.4318 61.075 21.0863 60.1106 21.0863 58.741L21.0863 32.7175C21.0863 31.89 21.5959 31.1479 22.3683 30.8508Z" fill="#E8E8EC"/>
|
||||||
|
<path d="M32.9995 38.1587L57.0052 28.9248C58.3214 28.4185 59.7342 29.3968 59.7232 30.807L59.712 32.2471L59.7119 57.5857C59.7119 58.4323 59.1789 59.1872 58.3811 59.4704L37.8846 66.7473L34.36 67.9429C33.0631 68.3829 31.7175 67.4185 31.7175 66.0489L31.7175 40.0254C31.7175 39.1979 32.2272 38.4558 32.9995 38.1587Z" fill="#D9D9E0"/>
|
||||||
|
<path d="M68.8117 65.0919C69.5835 64.795 70.0929 64.0537 70.0935 63.2267L70.1116 37.3209C70.1126 35.9167 68.7041 34.9487 67.3936 35.4528L43.3671 44.6948C42.5947 44.9919 42.0851 45.7339 42.0851 46.5615L42.0851 72.4629C42.0851 73.8666 43.4932 74.8336 44.8033 74.3295L68.8117 65.0919Z" fill="#B9BBC6"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_6465_168324">
|
||||||
|
<rect width="69" height="69" fill="white" transform="translate(81 13) rotate(90)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |