import * as React from 'react';
import { Issue } from './reportManagerSchema';
import { getLabelColors } from './reportManagerUtils';
import ReactMarkdown from 'react-markdown';
import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
// Mini components to render issues
interface IssueCardProps {
issue: Issue;
onSelect: () => void;
}
export const IssueCard = ({ issue, onSelect }: IssueCardProps) => {
return (
{issue.labels.map(label => {
const labelString = typeof label === 'string' ? label : label.name ?? '';
const colors = getLabelColors(labelString);
return ;
})}
{issue.title}
);
};
interface IssueViewProps {
issue: Issue;
}
export const IssueView = ({ issue }: IssueViewProps) => {
const [issueBody, setIssueBody] = React.useState('');
const isVideoValid = (src: string) => {
const videoElement = document.createElement('video');
const validPromise: Promise = new Promise(resolve => {
videoElement.addEventListener('loadeddata', () => resolve(true));
videoElement.addEventListener('error', () => resolve(false));
});
videoElement.src = src;
return validPromise;
};
const getLinkFromTag = async (tag: string) => {
const regex = /src="([^"]+)"/;
let url = '';
const match = tag.match(regex);
if (match) {
url = match[1];
}
if (url.startsWith('https://github.com/brown-dash/Dash-Web/assets')) {
return `\n${url} (Not authorized to display image here)`;
}
return await getTagFromUrl(url);
};
const getTagFromUrl = async (url: string) => {
const imgRegex = /https:\/\/browndash\.com\/files[/\\]images/;
const videoRegex = /https:\/\/browndash\.com\/files[/\\]videos/;
const audioRegex = /https:\/\/browndash\.com\/files[/\\]audio/;
if (imgRegex.test(url) || url.includes('user-images.githubusercontent.com')) {
return `\n${url}\n
\n`;
} else if (videoRegex.test(url)) {
const videoValid = await isVideoValid(url);
if (!videoValid) return `\n${url} (This video could not be loaded)\n`;
return `\n${url}\n\n`;
} else if (audioRegex.test(url)) {
return `\n${url}\n\n`;
} else {
return url;
}
};
const parseBody = async (body: string) => {
const imgTagRegex = /
]*\/?>/;
const fileRegex = /https:\/\/browndash\.com\/files/;
const parts = body.split('\n');
const modifiedParts = await Promise.all(
parts.map(async part => {
if (imgTagRegex.test(part)) {
return `\n${await getLinkFromTag(part)}\n`;
} else if (fileRegex.test(part)) {
const tag = await getTagFromUrl(part);
return tag;
} else {
return part;
}
})
);
setIssueBody(modifiedParts.join('\n'));
};
React.useEffect(() => {
parseBody((issue.body as string) ?? '');
}, [issue]);
return (
Issue{' '}
#{issue.number}
{issue.title}
Opened on {new Date(issue.created_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })} {issue.user?.login && `by ${issue.user?.login}`}
{issue.labels.length > 0 && (
{issue.labels.map(label => {
const labelString = typeof label === 'string' ? label : label.name ?? '';
const colors = getLabelColors(labelString);
return ;
})}
)}
);
};
interface TagProps {
text: string;
fontSize?: string;
color?: string;
backgroundColor?: string;
borderColor?: string;
border?: boolean;
onClick?: () => void;
}
export const Tag = ({ text, color, backgroundColor, fontSize, border, borderColor, onClick }: TagProps) => {
return (
{})}
className="report-tag"
style={{ color: color ?? '#ffffff', backgroundColor: backgroundColor ?? '#347bff', cursor: onClick ? 'pointer' : 'auto', fontSize: fontSize ?? '10px', border: border ? '1px solid' : 'none', borderColor: borderColor ?? '#94a3b8' }}>
{text}
);
};