mirror of https://github.com/buster-so/buster.git
create additional refs and playground
This commit is contained in:
parent
14e1680f43
commit
8a5ee5b417
|
@ -7,6 +7,8 @@ import type { ReportElements } from '@buster/server-shared/reports';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { mainApiV2 } from '@/api/buster_rest/instances';
|
import { mainApiV2 } from '@/api/buster_rest/instances';
|
||||||
import { useDebounceEffect } from '@/hooks';
|
import { useDebounceEffect } from '@/hooks';
|
||||||
|
import { useThemesConfig } from '@/components/ui/report/ThemeWrapper/useThemesConfig';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const ReportEditor = dynamic(
|
const ReportEditor = dynamic(
|
||||||
() => import('@/components/ui/report/ReportEditor').then((mod) => mod.ReportEditor),
|
() => import('@/components/ui/report/ReportEditor').then((mod) => mod.ReportEditor),
|
||||||
|
@ -14,6 +16,66 @@ const ReportEditor = dynamic(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Status indicator component with dynamic backgrounds
|
// Status indicator component with dynamic backgrounds
|
||||||
|
|
||||||
|
export const ReportPlayground: React.FC = () => {
|
||||||
|
const [markdown, setMarkdown] = useState<string>('');
|
||||||
|
const [hasBeenSuccessFullAtLeastOnce, setHasBeenSuccessFullAtLeastOnce] = useState(false);
|
||||||
|
|
||||||
|
const { data, refetch, isLoading, isFetched, error } = useQuery({
|
||||||
|
queryKey: ['report-playground', markdown],
|
||||||
|
queryFn: () => {
|
||||||
|
return mainApiV2
|
||||||
|
.post<{ elements: ReportElements }>('/temp/validate-markdown', { markdown })
|
||||||
|
.then((res) => {
|
||||||
|
setHasBeenSuccessFullAtLeastOnce(true);
|
||||||
|
return res.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
enabled: false
|
||||||
|
});
|
||||||
|
|
||||||
|
useDebounceEffect(
|
||||||
|
() => {
|
||||||
|
if (markdown.length > 0) {
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[markdown, refetch],
|
||||||
|
{ wait: 150 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const usedValue: ReportElements = hasBeenSuccessFullAtLeastOnce ? data?.elements || [] : value;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid max-h-screen min-h-screen grid-cols-[270px_1fr] gap-5 rounded border p-7">
|
||||||
|
<div className="flex h-full flex-col space-y-5">
|
||||||
|
<InputTextArea
|
||||||
|
className="flex-1 resize-none"
|
||||||
|
placeholder="Put markdown here"
|
||||||
|
value={markdown}
|
||||||
|
onChange={(e) => setMarkdown(e.target.value)}
|
||||||
|
/>
|
||||||
|
<ValidationStatus isLoading={isLoading} error={error} isFetched={isFetched} data={data} />
|
||||||
|
{data && (
|
||||||
|
<div className="max-h-[28vh] min-h-0 flex-1">
|
||||||
|
<div className="flex h-full flex-col">
|
||||||
|
<h3 className="mb-2 text-sm font-medium text-gray-700">Successful Response:</h3>
|
||||||
|
<pre className="flex-1 overflow-auto rounded border bg-gray-50 p-3 font-mono text-xs">
|
||||||
|
{JSON.stringify(data.elements, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ThemePicker />
|
||||||
|
</div>
|
||||||
|
<div className="bg-background h-full max-h-[calc(100vh-56px)] overflow-y-auto rounded border shadow">
|
||||||
|
<ReportEditor value={usedValue} readOnly={false} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface ValidationStatusProps {
|
interface ValidationStatusProps {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
error: unknown;
|
error: unknown;
|
||||||
|
@ -92,62 +154,37 @@ const ValidationStatus: React.FC<ValidationStatusProps> = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReportPlayground: React.FC = () => {
|
const ThemePicker = React.memo(() => {
|
||||||
const [markdown, setMarkdown] = useState<string>('');
|
const { activeTheme, setActiveTheme, allThemes } = useThemesConfig();
|
||||||
const [hasBeenSuccessFullAtLeastOnce, setHasBeenSuccessFullAtLeastOnce] = useState(false);
|
|
||||||
|
|
||||||
const { data, refetch, isLoading, isFetched, error } = useQuery({
|
const themesList = Object.values(allThemes);
|
||||||
queryKey: ['report-playground', markdown],
|
|
||||||
queryFn: () => {
|
|
||||||
return mainApiV2
|
|
||||||
.post<{ elements: ReportElements }>('/temp/validate-markdown', { markdown })
|
|
||||||
.then((res) => {
|
|
||||||
setHasBeenSuccessFullAtLeastOnce(true);
|
|
||||||
return res.data;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
enabled: false
|
|
||||||
});
|
|
||||||
|
|
||||||
useDebounceEffect(
|
|
||||||
() => {
|
|
||||||
if (markdown.length > 0) {
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[markdown, refetch],
|
|
||||||
{ wait: 150 }
|
|
||||||
);
|
|
||||||
|
|
||||||
const usedValue: ReportElements = hasBeenSuccessFullAtLeastOnce ? data?.elements || [] : value;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid max-h-screen min-h-screen grid-cols-[400px_1fr] gap-5 rounded border p-7">
|
<div className="bg-background flex gap-x-2 overflow-x-auto rounded border p-2">
|
||||||
<div className="flex h-full flex-col space-y-5">
|
{themesList.map((theme) => {
|
||||||
<InputTextArea
|
const firstThreeColors = Object.values(theme.light).slice(0, 3);
|
||||||
className="flex-1 resize-none"
|
|
||||||
placeholder="Put markdown here"
|
const isActive = activeTheme.id === theme.id;
|
||||||
value={markdown}
|
return (
|
||||||
onChange={(e) => setMarkdown(e.target.value)}
|
<div
|
||||||
/>
|
key={theme.id}
|
||||||
<ValidationStatus isLoading={isLoading} error={error} isFetched={isFetched} data={data} />
|
className={cn(
|
||||||
{data && (
|
'min-h-7 min-w-7 cursor-pointer rounded-full border transition-all duration-200 hover:scale-110',
|
||||||
<div className="max-h-[28vh] min-h-0 flex-1">
|
isActive && 'border-primary shadow-2xl'
|
||||||
<div className="flex h-full flex-col">
|
)}
|
||||||
<h3 className="mb-2 text-sm font-medium text-gray-700">Successful Response:</h3>
|
style={{
|
||||||
<pre className="flex-1 overflow-auto rounded border bg-gray-50 p-3 font-mono text-xs">
|
background: `linear-gradient(0deg, hsl(${firstThreeColors[0]}) 0%, hsl(${firstThreeColors[0]}) 33%, hsl(${firstThreeColors[1]}) 33%, hsl(${firstThreeColors[1]}) 66%, hsl(${firstThreeColors[2]}) 66%, hsl(${firstThreeColors[2]}) 100%)`
|
||||||
{JSON.stringify(data.elements, null, 2)}
|
}}
|
||||||
</pre>
|
onClick={() => setActiveTheme(theme)}
|
||||||
</div>
|
title={theme.id}
|
||||||
</div>
|
/>
|
||||||
)}
|
);
|
||||||
</div>
|
})}
|
||||||
<div className="bg-background h-full max-h-[calc(100vh-56px)] overflow-y-auto rounded border shadow">
|
|
||||||
<ReportEditor value={usedValue} readOnly={false} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
|
ThemePicker.displayName = 'ThemePicker';
|
||||||
|
|
||||||
const value: ReportElements = [
|
const value: ReportElements = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,7 +59,7 @@ export const ReportEditor = React.memo(
|
||||||
variant={variant}
|
variant={variant}
|
||||||
readonly={readOnly}
|
readonly={readOnly}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={cn('pb-[20vh]', className)}>
|
className={cn('pb-[15vh]', className)}>
|
||||||
<Editor style={style} placeholder={placeholder} disabled={disabled} />
|
<Editor style={style} placeholder={placeholder} disabled={disabled} />
|
||||||
</EditorContainer>
|
</EditorContainer>
|
||||||
</Plate>
|
</Plate>
|
||||||
|
|
|
@ -13,5 +13,5 @@ export function useThemesConfig() {
|
||||||
const activeTheme = useThemesConfigStore((state) => state.activeTheme);
|
const activeTheme = useThemesConfigStore((state) => state.activeTheme);
|
||||||
const setActiveTheme = useThemesConfigStore((state) => state.setActiveTheme);
|
const setActiveTheme = useThemesConfigStore((state) => state.setActiveTheme);
|
||||||
|
|
||||||
return { activeTheme, setActiveTheme };
|
return { activeTheme, setActiveTheme, allThemes: THEMES };
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ function withTooltip<T extends React.ElementType>(Component: T) {
|
||||||
tooltip,
|
tooltip,
|
||||||
tooltipContentProps,
|
tooltipContentProps,
|
||||||
tooltipProps,
|
tooltipProps,
|
||||||
tooltipTriggerProps,
|
ref,
|
||||||
...props
|
...props
|
||||||
}: TooltipProps<T>) {
|
}: TooltipProps<T>) {
|
||||||
const [mounted, setMounted] = React.useState(false);
|
const [mounted, setMounted] = React.useState(false);
|
||||||
|
@ -287,15 +287,7 @@ function withTooltip<T extends React.ElementType>(Component: T) {
|
||||||
const component = <Component {...(props as React.ComponentProps<T>)} />;
|
const component = <Component {...(props as React.ComponentProps<T>)} />;
|
||||||
|
|
||||||
if (tooltip && mounted) {
|
if (tooltip && mounted) {
|
||||||
return (
|
return <Tooltip title={tooltip}>{component}</Tooltip>;
|
||||||
<Tooltip {...tooltipProps}>
|
|
||||||
<TooltipTrigger asChild {...tooltipTriggerProps}>
|
|
||||||
{component}
|
|
||||||
</TooltipTrigger>
|
|
||||||
|
|
||||||
<TooltipContent {...tooltipContentProps}>{tooltip}</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return component;
|
return component;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
@import './tailwindAnimations.css';
|
@import './tailwindAnimations.css';
|
||||||
@plugin 'tailwind-scrollbar';
|
@plugin 'tailwind-scrollbar';
|
||||||
@plugin "tailwindcss-animate";
|
@plugin "tailwindcss-animate";
|
||||||
|
@plugin 'tailwind-scrollbar-hide';
|
||||||
|
|
||||||
@custom-variant dark (&:where(.dark, .dark *));
|
@custom-variant dark (&:where(.dark, .dark *));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue