Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors UI: Acknowledge functionality #901

Merged
merged 4 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions ui/app/api/mirrors/alerts/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,22 @@ export async function POST(request: Request) {
}
return new Response(JSON.stringify(mirrorStatus));
}

// We accept a list here in preparation for a Select All feature in UI
export async function PUT(request: Request) {
const { mirrorIDStringList } = await request.json();
const mirrorIDList: bigint[] = mirrorIDStringList.map((id: string) =>
BigInt(id)
);
const success = await prisma.flow_errors.updateMany({
where: {
id: {
in: mirrorIDList,
},
},
data: {
ack: true,
},
});
return new Response(JSON.stringify(success.count));
}
7 changes: 3 additions & 4 deletions ui/app/mirrors/edit/[mirrorId]/cdcDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ function CdcDetails({ syncs, createdAt, mirrorConfig }: props) {
</Label>
</div>
<div>
<MirrorError
detailed
flowName={mirrorConfig?.flowJobName || ''}
/>
<Label>
<MirrorError flowName={mirrorConfig?.flowJobName || ''} />
</Label>
</div>
</div>
<div className='basis-1/4 md:basis-1/3'>
Expand Down
57 changes: 57 additions & 0 deletions ui/app/mirrors/errors/[mirrorName]/ackbutton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use client';
import { Button } from '@/lib/Button';
import { Label } from '@/lib/Label';
import { ProgressCircle } from '@/lib/ProgressCircle';
import { useState } from 'react';
import { toast } from 'react-toastify';

const notifyErr = (errMsg: string) => {
toast.error(errMsg, {
position: toast.POSITION.BOTTOM_CENTER,
});
};

const AckButton = ({ ack, id }: { ack: boolean; id: number | bigint }) => {
const [loading, setLoading] = useState(false);
const [updated, setUpdated] = useState(false);
// handleAck updates ack to true for the given mirrorID
const handleAck = async (mirrorID: bigint | number) => {
setLoading(true);
const updateResResult = await fetch('/api/mirrors/alerts', {
method: 'PUT',
body: JSON.stringify({
mirrorIDStringList: [mirrorID.toString()],
}),
});
const updateRes = await updateResResult.json();
setLoading(false);
if (!updateRes) {
notifyErr('Something went wrong when trying to acknowledge');
return;
}
setUpdated(true);
};
return (
<>
{ack !== true && updated !== true ? (
<Button variant='normalSolid' onClick={() => handleAck(id)}>
<Label as='label' style={{ fontSize: 13 }}>
{loading ? (
<ProgressCircle variant='intermediate_progress_circle' />
) : (
'Acknowledge'
)}
</Label>
</Button>
) : (
<Button variant='normal' disabled={true}>
<Label as='label' style={{ fontSize: 13 }}>
Acknowledged
</Label>
</Button>
)}
</>
);
};

export default AckButton;
119 changes: 72 additions & 47 deletions ui/app/mirrors/errors/[mirrorName]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import prisma from '@/app/utils/prisma';
import TimeLabel from '@/components/TimeComponent';
import { Label } from '@/lib/Label';
import { Table, TableCell, TableRow } from '@/lib/Table';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import AckButton from './ackbutton';

type MirrorErrorProps = {
params: { mirrorName: string };
Expand All @@ -14,62 +17,84 @@ const MirrorError = async ({ params: { mirrorName } }: MirrorErrorProps) => {
flow_name: mirrorName,
error_type: 'error',
},
distinct: ['error_message'],
orderBy: {
error_timestamp: 'desc',
},
});

return (
<div style={{ padding: '2rem' }}>
<Label variant='title2'>Error Log</Label>
<hr></hr>
<div style={{ marginTop: '1rem' }}>
<Label variant='body'>
<b>Mirror name</b>:
</Label>
<Label variant='body'>{mirrorName}</Label>
<div
style={{
fontSize: 15,
marginTop: '1rem',
width: '100%',
border: '1px solid rgba(0,0,0,0.1)',
padding: '1rem',
borderRadius: '1rem',
}}
>
<Table
header={
<TableRow style={{ textAlign: 'left' }}>
<TableCell>Type</TableCell>
<Label as='label' style={{ fontSize: 15 }}>
Time
</Label>
<TableCell>Message</TableCell>
</TableRow>
}
<>
<div style={{ padding: '2rem' }}>
<Label variant='title2'>Error Log</Label>
<hr></hr>
<div style={{ marginTop: '1rem' }}>
<Label variant='body'>
<b>Mirror name</b>:
</Label>
<Label variant='body'>{mirrorName}</Label>

<div>
<Label as='label' style={{ fontSize: 14, marginTop: '1rem' }}>
Here you can view error logs for your mirror and mark them as
acknowledged. Once all errors are acknowledged, we will show the
status for this mirror as Active.
<br></br>
This is purely for displaying mirror status and has{' '}
<b>no effect on the mirror</b>.
</Label>
</div>

<div
style={{
fontSize: 15,
marginTop: '1rem',
maxHeight: '50em',
overflow: 'scroll',
width: '100%',
border: '1px solid rgba(0,0,0,0.1)',
padding: '1rem',
borderRadius: '1rem',
}}
>
{mirrorErrors.map((mirrorError) => (
<TableRow key={mirrorError.error_message}>
<TableCell style={{ color: '#F45156', width: '10%' }}>
{mirrorError.error_type.toUpperCase()}
</TableCell>
<TableCell style={{ width: '20%' }}>
<TimeLabel
fontSize={14}
timeVal={mirrorError.error_timestamp.toLocaleString()}
/>
</TableCell>
<TableCell style={{ width: '70%', fontSize: 13 }}>
{mirrorError.error_message}
</TableCell>
</TableRow>
))}
</Table>
<Table
header={
<TableRow style={{ textAlign: 'left' }}>
<TableCell>Type</TableCell>
<TableCell>
<Label as='label' style={{ fontSize: 15 }}>
Time
</Label>
</TableCell>
<TableCell>Message</TableCell>
<TableCell></TableCell>
</TableRow>
}
>
{mirrorErrors.map((mirrorError) => (
<TableRow key={mirrorError.id}>
<TableCell style={{ color: '#F45156', width: '10%' }}>
{mirrorError.error_type.toUpperCase()}
</TableCell>
<TableCell style={{ width: '20%' }}>
<TimeLabel
fontSize={14}
timeVal={mirrorError.error_timestamp}
/>
</TableCell>
<TableCell style={{ width: '50%', fontSize: 13 }}>
{mirrorError.error_message}
</TableCell>
<TableCell style={{ width: '20%', fontSize: 13 }}>
<AckButton ack={mirrorError.ack} id={mirrorError.id} />
</TableCell>
</TableRow>
))}
</Table>
</div>
</div>
</div>
</div>
<ToastContainer />
</>
);
};

Expand Down
41 changes: 22 additions & 19 deletions ui/app/mirrors/mirror-status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,21 @@ export const ErrorModal = ({ flowName }: { flowName: string }) => {
<Link href={`/mirrors/errors/${flowName}`}>
<Button
style={{
backgroundColor: 'rgba(240, 128, 128, 0.5)',
backgroundColor: 'rgba(240, 128, 128, 0.2)',
height: '2rem',
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
border: '1px solid rgba(0, 0, 0, 0.2)',
}}
>
<Label as='label' style={{ fontSize: 13, color: 'darkred' }}>
Show errors
<Icon name='error' />
<Label as='label' style={{ fontSize: 13 }}>
Errors
</Label>
</Button>
</Link>
);
};

export const MirrorError = ({
flowName,
detailed,
}: {
flowName: string;
detailed: boolean;
}) => {
export const MirrorError = ({ flowName }: { flowName: string }) => {
const [flowStatus, setFlowStatus] = useState<string>();
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
Expand Down Expand Up @@ -81,15 +76,23 @@ export const MirrorError = ({
);
}

if (flowStatus == 'healthy') {
if (detailed)
return (
<div style={{ display: 'flex', alignItems: 'center' }}>
if (flowStatus === 'healthy') {
return (
<Link href={`/mirrors/errors/${flowName}`}>
<Button
style={{
backgroundColor: 'white',
height: '2rem',
border: '1px solid rgba(0, 0, 0, 0.1)',
}}
>
<Icon name='check_circle' fill={true} />
<Label>Healthy</Label>
</div>
);
return <Icon name='check_circle' fill={true} />;
<Label as='label' style={{ fontSize: 13 }}>
Active
</Label>
</Button>
</Link>
);
}

return <ErrorModal flowName={flowName} />;
Expand Down
2 changes: 1 addition & 1 deletion ui/app/mirrors/tables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function CDCFlows({ cdcFlows }: { cdcFlows: any }) {
<TimeLabel timeVal={flow.created_at} />
</TableCell>
<TableCell>
<MirrorError flowName={flow.name} detailed={false} />
<MirrorError flowName={flow.name} />
</TableCell>
<TableCell>
<DropDialog
Expand Down
Loading