Skip to content
Snippets Groups Projects
Commit f54d2b3e authored by Christophe's avatar Christophe
Browse files

fix: github issue report confirmation prompt

parent e8269d38
No related branches found
No related tags found
1 merge request!14fix(frontend): improve error legibility and reporting
import { type ComponentProps, forwardRef } from 'react';
import clsx from 'clsx';
type Variant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning';
const styling = (variant: Variant) => {
let color = 'bg-blue-600 hover:bg-blue-800 text-white';
switch (variant) {
case 'secondary':
color = 'bg-gray-400 hover:bg-gray-600 text-white';
break;
case 'success':
color = 'bg-green-400 hover:bg-green-600 text-white';
break;
case 'danger':
color = 'bg-red-400 hover:bg-red-600 text-white';
break;
case 'warning':
color = 'bg-yellow-400 hover:bg-yellow-600 text-black';
break;
}
return [color, 'rounded px-4 py-2 font-bold'];
};
type ButtonProps = {
variant?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning';
variant?: Variant;
className?: string;
};
const Button = forwardRef<HTMLButtonElement, ComponentProps<'button'> & ButtonProps>(
({ children, variant = 'primary', className, ...props }, ref) => {
let color = 'bg-blue-400 hover:bg-blue-600 text-white';
switch (variant) {
case 'secondary':
color = 'bg-gray-400 hover:bg-gray-600 text-white';
break;
case 'success':
color = 'bg-green-400 hover:bg-green-600 text-white';
break;
case 'danger':
color = 'bg-red-400 hover:bg-red-600 text-white';
break;
case 'warning':
color = 'bg-yellow-400 hover:bg-yellow-600 text-black';
break;
}
return (
<button
className={clsx(
color,
'rounded bg-blue-600 px-4 py-2 font-bold hover:bg-blue-800',
className
)}
{...props}
ref={ref}
>
{children}
</button>
);
}
({ children, variant = 'primary', className, ...props }, ref) => (
<button className={clsx(...styling(variant), className)} {...props} ref={ref}>
{children}
</button>
)
);
Button.displayName = 'Button';
// seperate classes because typing for generic 'as' with forwardRef is difficult
type ButtonLinkProps = {
variant?: Variant;
className?: string;
href: string;
};
export const ButtonLink = forwardRef<HTMLAnchorElement, ComponentProps<'a'> & ButtonLinkProps>(
({ children, variant = 'primary', className, href, ...props }, ref) => (
<a href={href} className={clsx(...styling(variant), className)} {...props} ref={ref}>
{children}
</a>
)
);
ButtonLink.displayName = 'ButtonLink';
export default Button;
......@@ -15,7 +15,7 @@
width: 7px;
height: 7px;
border-radius: 50%;
background: #fff;
background: black;
margin: -4px 0 0 -4px;
}
div:nth-child(1) {
......
......@@ -159,7 +159,7 @@ const TemplateForm: FC<TemplateFormProps> = ({ template }) => {
</TemplateGenerationError>
)}
{(fields.isLoading || generate.isLoading) && (
<div className="mb-4 flex w-full justify-center">
<div className="my-2 flex w-full justify-center">
<LoadingSpinner />
</div>
)}
......@@ -178,11 +178,11 @@ const TemplateForm: FC<TemplateFormProps> = ({ template }) => {
)}
</form>
<dialog id="missing-fields" ref={missingFieldsModal} className="modal p-3">
<h2>Missing fields</h2>
<p>
It looks like you haven&apos;t filled out all the fields. Are you sure you want
to submit the form?{' '}
</p>
<p>Missing fields:</p>
<ul>
{emptyFields.map((f) => (
<li key={f} style={{ marginBlock: '.1rem', listStyle: 'disc inside' }}>
......@@ -190,7 +190,7 @@ const TemplateForm: FC<TemplateFormProps> = ({ template }) => {
</li>
))}
</ul>
<div className="flex-gap flex justify-end">
<div className="buttons">
<Button
variant="secondary"
onClick={() => {
......
import { type FC, type PropsWithChildren, useEffect, useState } from 'react';
import { type FC, type PropsWithChildren, useEffect, useRef, useState } from 'react';
import Center from 'components/Center';
import { type AxiosResponse, isAxiosError } from 'axios';
import LoadingSpinner from './LoadingSpinner';
......@@ -6,6 +6,7 @@ import { ISSUES_URL } from '../lib/links';
import { type Template as TemplateDto } from '../lib/client';
import mustache from 'mustache';
import { useIssueTemplate } from './IssueTemplateContext';
import Button, { ButtonLink } from './Button';
type ErrorMetadata = {
template?: TemplateDto;
......@@ -85,20 +86,32 @@ const ResponseDisplay: FC<ResponseDisplayProps> = ({ response, metadata }) => {
const { issueTemplate } = useIssueTemplate();
const reportErrorModal = useRef<HTMLDialogElement>(null);
if (report === undefined) {
return <LoadingSpinner />;
}
return (
<>
<pre className="max-w-[80ch] overflow-x-scroll rounded-md bg-amber-200 p-2">
<ResponseDisplayError report={report} />
</pre>
{metadata?.template && (
<p className="mt-3">
If you believe this is a problem with the template, please report it under{' '}
{ISSUES_URL.startsWith('https://github.com') ? (
<a
<dialog id="report" ref={reportErrorModal} className="modal p-3">
<h2>Submit report</h2>
<p>
You will be brought to a Github issue creation page. For reproducibility
reasons, your form input is included. If it contains personally identifiable
information, or you&apos;d wish to remove it, please redact it in the next
page.
</p>
<div className="buttons">
<Button
variant="secondary"
onClick={() => reportErrorModal.current?.close()}
>
Cancel
</Button>
<ButtonLink
variant="primary"
href={`${ISSUES_URL}/new?${new URLSearchParams({
title: `[${metadata?.template.title}] Generation issue`,
body: mustache.render(issueTemplate, {
......@@ -131,13 +144,31 @@ const ResponseDisplay: FC<ResponseDisplayProps> = ({ response, metadata }) => {
labels: 'template issue',
})}`}
>
the issues page.
</a>
) : (
<a href={ISSUES_URL}>the issues page and include the template name.</a>
)}
</p>
Continue
</ButtonLink>
</div>
</dialog>
)}
<pre className="max-w-[80ch] overflow-x-scroll rounded-md bg-amber-200 p-2">
<ResponseDisplayError report={report} />
</pre>
<p className="mt-3">
If you believe this is a problem with the template, please report it under{' '}
{metadata?.template && ISSUES_URL.startsWith('https://github.com') ? (
<a
href={ISSUES_URL}
onClick={(e) => {
e.preventDefault();
reportErrorModal.current?.showModal();
}}
>
the issues page.
</a>
) : (
<a href={ISSUES_URL}>the issues page and include the template name.</a>
)}
</p>
</>
);
};
......
......@@ -21,12 +21,21 @@
.modal {
border: 0;
box-shadow: 0 0 1em black;
max-width: 60ch;
}
.modal::backdrop {
background: rgb(0 0 0 / .3);
}
.modal > .buttons {
gap: 1rem;
display: flex;
justify-content: flex-end;
margin-top: 1rem;
}
.button-warning {
background-color: #ffcc33;
color: #000000;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment