Skip to content

feat(dashboard): Nv 4985 dashboard error state if get workflows fail we have not #7494

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

Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion apps/dashboard/src/components/auth/auth-side-banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function AuthSideBanner() {
</div>
<div className="flex flex-col items-start justify-start gap-8 self-stretch">
<AuthFeatureRow
icon={<Plug className="h-6 w-6" />}
icon={<Plug className="h-6 w-6 text-[#DD2450]" />}
title="Powerful notifications, easy integrations"
description="Unlimited workflows, unlimited providers, unlimited subscribers with 99.9% uptime SLA"
/>
Expand Down
1 change: 0 additions & 1 deletion apps/dashboard/src/components/error-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useRouteError } from 'react-router-dom';

export default function ErrorPage() {
const error = useRouteError() as { statusText?: string; message: string };
console.error(error);

return (
<div id="error-page">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,186 +1,14 @@
import { PLAIN_SUPPORT_CHAT_APP_ID } from '@/config';
import { useAuth } from '@/context/auth/hooks';
import { useBootIntercom } from '@/hooks/use-boot-intercom';
import * as Sentry from '@sentry/react';
import { useEffect, useState } from 'react';
import { RiQuestionFill } from 'react-icons/ri';
import { HeaderButton } from './header-button';

// Add type declaration for Plain chat widget
declare global {
interface Window {
Plain?: {
init: (config: any) => void;
open: () => void;
};
}
}
import { usePlainChat } from '@/hooks/use-plain-chat';

export const CustomerSupportButton = () => {
const [isFirstRender, setIsFirstRender] = useState(true);
const { currentUser } = useAuth();

const isLiveChatVisible = currentUser?.servicesHashes?.plain && PLAIN_SUPPORT_CHAT_APP_ID !== undefined;

useBootIntercom();

useEffect(() => {
if (isFirstRender && isLiveChatVisible) {
try {
window?.Plain?.init({
appId: PLAIN_SUPPORT_CHAT_APP_ID,
hideLauncher: true,
hideBranding: true,
title: 'Chat with us',
customerDetails: {
email: currentUser?.email,
emailHash: currentUser?.servicesHashes?.plain,
externalId: currentUser?._id,
},
links: [
{
icon: 'book',
text: 'Documentation',
url: 'https://docs.novu.co?utm_campaign=in_app_live_chat',
},
{
icon: 'integration',
text: 'Roadmap',
url: 'https://roadmap.novu.co/roadmap?utm_campaign=in_app_live_chat',
},
{
icon: 'link',
text: 'Changelog',
url: 'https://roadmap.novu.co/changelog?utm_campaign=in_app_live_chat',
},
{
icon: 'email',
text: 'Contact Sales',
url: 'https://notify.novu.co/meetings/novuhq/novu-discovery-session-rr?utm_campaign=in_app_live_chat',
},
],
theme: 'light',

style: {
brandColor: '#DD2450',
launcherBackgroundColor: '#FFFFFF',
launcherIconColor: '#FFFFFF',
},

logo: {
url: 'https://dashboard.novu.co/static/images/novu.png',
alt: 'Novu Logo',
},
chatButtons: [
{
icon: 'chat',
text: 'Ask a question',
threadDetails: {
// "Question"
labelTypeIds: ['lt_01JCJ36RM5P6QSYWXPB3FNC3QF'],
},
},
{
icon: 'bulb',
text: 'Share Feedback',
threadDetails: {
// "Insight"
labelTypeIds: ['lt_01JCKS50M6D1568DSJ1Q9CHFF2'],
},
form: {
fields: [
{
type: 'dropdown',
placeholder: 'How important is this to you?',
options: [
{
icon: 'error',
text: 'Critical - Blocking my work',
threadDetails: {
labelTypeIds: ['lt_01JFYNG7N05VF956CABF23N3N8'],
},
},
{
icon: 'bulb',
text: 'Important - Should be addressed soon',
threadDetails: {
labelTypeIds: ['lt_01JFYNGRPEJ4CNA3GMYSRCRCYB'],
},
},
{
icon: 'chat',
text: 'Nice to have - Suggestion for improvement',
threadDetails: {
labelTypeIds: ['lt_01JFYNGE0EYWSE1GKAM3MTBDMC'],
},
},
],
},
],
},
},
{
icon: 'bug',
text: 'Report a bug',
form: {
fields: [
{
type: 'dropdown',
placeholder: 'Severity of the bug..',
options: [
{
icon: 'integration',
text: 'Unable to access the application',
threadDetails: {
// "Critical Severity, Bug"
labelTypeIds: ['lt_01JA88XK1N11JBBV55ZMYMEH85', 'lt_01JA88XK1N11JBBV55ZMYMEH85'],
},
},
{
icon: 'error',
text: 'Significant functionality impacted',
threadDetails: {
// "High Severity, Bug"
labelTypeIds: ['lt_01JE5V8FK3SHPR6N7XMDW8N005', 'lt_01JA88XK1N11JBBV55ZMYMEH85'],
},
},
{
icon: 'bug',
text: 'Minor inconvenience or issue',
threadDetails: {
// "Low Severity, Bug"
labelTypeIds: ['lt_01JE5V7R152BN3A9Z1R2251F1A', 'lt_01JA88XK1N11JBBV55ZMYMEH85'],
},
},
],
},
],
},
},
],
});
} catch (error) {
console.error('Error initializing plain chat: ', error);
Sentry.captureException(error);
}
}
setIsFirstRender(false);
}, [isLiveChatVisible, currentUser, isFirstRender]);
const { showPlainLiveChat } = usePlainChat();

const showPlainLiveChat = () => {
if (isLiveChatVisible) {
try {
window?.Plain?.open();
} catch (error) {
console.error('Error opening plain chat: ', error);
Sentry.captureException(error);
}
}
};
return (
<button tabIndex={-1} className="flex items-center justify-center" onClick={showPlainLiveChat}>
<HeaderButton label="Help">
<RiQuestionFill className="text-foreground-600 size-4" />{' '}
<RiQuestionFill className="text-foreground-600 size-4" />
</HeaderButton>
</button>
);
Expand Down
12 changes: 6 additions & 6 deletions apps/dashboard/src/components/icons/plug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,47 @@ export function Plug(props: React.ComponentPropsWithoutRef<'svg'>) {
<path
id="Vector"
d="M1 24.9906L3.95687 22.0337"
stroke="#DD2450"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
id="Vector_2"
d="M5.7569 11.7485L3.95685 13.5486C2.83146 14.674 2.19922 16.2003 2.19922 17.7919C2.19922 19.3834 2.83146 20.9098 3.95685 22.0352C5.08225 23.1606 6.60861 23.7928 8.20016 23.7928C9.7917 23.7928 11.3181 23.1606 12.4435 22.0352L14.2435 20.2351L5.7569 11.7485Z"
stroke="#DD2450"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
id="Vector_3"
d="M24.9998 0.990234L22.043 3.94711"
stroke="#DD2450"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
id="Vector_4"
d="M20.2434 14.2357L22.0435 12.4356C23.1689 11.3103 23.8011 9.78389 23.8011 8.19234C23.8011 6.6008 23.1689 5.07443 22.0435 3.94904C20.9181 2.82365 19.3917 2.19141 17.8002 2.19141C16.2086 2.19141 14.6823 2.82365 13.5569 3.94904L11.7568 5.74908L20.2434 14.2357Z"
stroke="#DD2450"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
id="Vector_5"
d="M10.6003 11.7905L8.2002 14.1906"
stroke="#DD2450"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
id="Vector_6"
d="M14.1999 15.3906L11.7998 17.7907"
stroke="#DD2450"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
Expand Down
44 changes: 44 additions & 0 deletions apps/dashboard/src/components/shared/server-error-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { RiQuestionAnswerLine } from 'react-icons/ri';
import { Button } from '../primitives/button';
import { Plug } from '../icons/plug';
import { usePlainChat } from '@/hooks/use-plain-chat';

export function ServerErrorPage() {
const { showPlainLiveChat } = usePlainChat();

return (
<div className="peer flex h-full w-full flex-col items-center justify-center" data-error="true">
<div className="relative flex w-3/4 flex-col items-center justify-center gap-3">
<div className="absolute inset-0 -z-50 h-full w-full rounded-[866px] border border-dashed border-[#E7E7E7] bg-[#E7E7E7] blur-[220px]" />
<div className="flex w-40 items-center gap-3 rounded-md border border-[#e6e6e6] bg-white px-3 py-4 shadow-[0px_4.233px_4.233px_0px_rgba(31,40,55,0.02),0px_1.693px_1.693px_0px_rgba(31,40,55,0.02),0px_-3px_0px_0px_#F7F7F7_inset]">
<span className="size-3 rounded-full bg-[#e6e6e6]" />
<span className="h-3 flex-1 rounded-md bg-[#e6e6e6]" />
</div>
<Plug className="size-4 text-[#E6E6E6]" />
<div className="w-40 rounded-md border border-[#e6e6e6] bg-white px-3 py-1 text-center shadow-[0px_4.233px_4.233px_0px_rgba(31,40,55,0.02),0px_1.693px_1.693px_0px_rgba(31,40,55,0.02),0px_-3px_0px_0px_#F7F7F7_inset]">
<p className="text-2xl font-extrabold text-[#ebecef]">500</p>
</div>
<div className="mt-6 flex flex-col items-center gap-3">
<p className="font-medium text-gray-900">Uh-oh, this is on us, not you.</p>
<div>
<p className="text-text-soft text-center text-xs font-medium">
Whoops, we missed a beat. This 500 is a reminder
</p>
<p className="text-text-soft text-center text-xs font-medium">we're still human… mostly.</p>
</div>

<Button
leadingIcon={RiQuestionAnswerLine}
size="sm"
variant="secondary"
mode="outline"
className="mt-3"
onClick={showPlainLiveChat}
>
Get in Touch
</Button>
</div>
</div>
</div>
);
}
3 changes: 2 additions & 1 deletion apps/dashboard/src/components/workflow-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { WorkflowRow } from '@/components/workflow-row';
import { useFetchWorkflows } from '@/hooks/use-fetch-workflows';
import { RiMore2Fill } from 'react-icons/ri';
import { createSearchParams, useLocation, useSearchParams } from 'react-router-dom';
import { ServerErrorPage } from './shared/server-error-page';

export function WorkflowList() {
const [searchParams] = useSearchParams();
Expand All @@ -34,7 +35,7 @@ export function WorkflowList() {
offset,
});

if (isError) return null;
if (isError) return <ServerErrorPage />;

if (!isPending && data.totalCount === 0) {
return <WorkflowListEmpty />;
Expand Down
Loading
Loading