embeddable dashboard

This commit is contained in:
Nate Kelley 2025-03-18 14:19:56 -06:00
parent 178cc86a7e
commit 96731d86d0
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
8 changed files with 34 additions and 24 deletions

View File

@ -1,4 +1,3 @@
import { BusterRoutes } from '@/routes/busterRoutes/busterRoutes';
import axios, { AxiosError } from 'axios'; import axios, { AxiosError } from 'axios';
import { rustErrorHandler } from './buster_rest/errors'; import { rustErrorHandler } from './buster_rest/errors';
import { AxiosRequestHeaders } from 'axios'; import { AxiosRequestHeaders } from 'axios';

View File

@ -1,11 +1,16 @@
import { DashboardController } from '@/controllers/DashboardController'; 'use client';
export default async function EmbedDashboardsPage(props: { import { useGetDashboard } from '@/api/buster_rest/dashboards';
params: Promise<{ dashboardId: string }>; import { CircleSpinnerLoaderContainer } from '@/components/ui/loaders';
}) { import { DashboardViewDashboardController } from '@/controllers/DashboardController/DashboardViewDashboardController';
const params = await props.params;
const { dashboardId } = params; export default function EmbedDashboardsPage(props: { params: { dashboardId: string } }) {
const { dashboardId } = props.params;
const { isFetched: isFetchedDashboard } = useGetDashboard(dashboardId);
return <DashboardController dashboardId={dashboardId} />; if (!isFetchedDashboard) {
return <CircleSpinnerLoaderContainer className="min-h-screen" />;
}
return <DashboardViewDashboardController dashboardId={dashboardId} readOnly={true} />;
} }

View File

@ -6,7 +6,7 @@ import { MetricViewChart } from '@/controllers/MetricController/MetricViewChart/
export default function EmbedMetricsPage({ params }: { params: { metricId: string } }) { export default function EmbedMetricsPage({ params }: { params: { metricId: string } }) {
const { metricId } = params; const { metricId } = params;
const { data, isFetched, error } = useGetMetric(metricId); const { isFetched } = useGetMetric(metricId);
if (!isFetched) { if (!isFetched) {
return <CircleSpinnerLoaderContainer className="min-h-screen" />; return <CircleSpinnerLoaderContainer className="min-h-screen" />;

View File

@ -9,6 +9,7 @@ import { BusterDragColumnMarkers } from './_BusterDragColumnMarkers';
import { calculateColumnSpan, columnSpansToPercent } from './config'; import { calculateColumnSpan, columnSpansToPercent } from './config';
import SplitPane, { Pane } from '../layouts/AppSplitter/SplitPane'; import SplitPane, { Pane } from '../layouts/AppSplitter/SplitPane';
import { cn } from '@/lib/classMerge'; import { cn } from '@/lib/classMerge';
import '../layouts/AppSplitter/splitterStyles.css';
type ContainerProps = { type ContainerProps = {
rowId: string; rowId: string;

View File

@ -8,7 +8,10 @@ import { AddTypeModal } from '@/components/features/modal/AddTypeModal';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { useGetDashboard } from '@/api/buster_rest/dashboards'; import { useGetDashboard } from '@/api/buster_rest/dashboards';
export const DashboardController: React.FC<{ dashboardId: string }> = ({ dashboardId }) => { export const DashboardController: React.FC<{ dashboardId: string; readOnly?: boolean }> = ({
dashboardId,
readOnly = false
}) => {
const { data: dashboardResponse, isFetched: isFetchedDashboard } = useGetDashboard(dashboardId); const { data: dashboardResponse, isFetched: isFetchedDashboard } = useGetDashboard(dashboardId);
const selectedFileView = useChatLayoutContextSelector((x) => x.selectedFileView) || 'dashboard'; const selectedFileView = useChatLayoutContextSelector((x) => x.selectedFileView) || 'dashboard';
const [openAddTypeModal, setOpenAddTypeModal] = useState(false); const [openAddTypeModal, setOpenAddTypeModal] = useState(false);

View File

@ -10,20 +10,16 @@ export const DashboardEditTitles: React.FC<{
title: string; title: string;
onUpdateDashboard: ReturnType<typeof useUpdateDashboard>['mutateAsync']; onUpdateDashboard: ReturnType<typeof useUpdateDashboard>['mutateAsync'];
description: string; description: string;
allowEdit?: boolean; readOnly?: boolean;
dashboardId: string; dashboardId: string;
}> = React.memo(({ onUpdateDashboard, allowEdit, title, description, dashboardId }) => { }> = React.memo(({ onUpdateDashboard, readOnly, title, description, dashboardId }) => {
const onChangeTitle = useMemoizedFn((name: string) => { const onChangeTitle = useMemoizedFn((name: string) => {
onUpdateDashboard({ name, id: dashboardId }); if (!readOnly) onUpdateDashboard({ name, id: dashboardId });
});
const onChangeDescription = useMemoizedFn((description: string) => {
onUpdateDashboard({ description, id: dashboardId });
}); });
const onChangeDashboardDescription = useMemoizedFn( const onChangeDashboardDescription = useMemoizedFn(
(value: React.ChangeEvent<HTMLInputElement>) => { (value: React.ChangeEvent<HTMLInputElement>) => {
onChangeDescription(value.target.value); if (!readOnly) onUpdateDashboard({ description: value.target.value, id: dashboardId });
} }
); );
@ -31,7 +27,7 @@ export const DashboardEditTitles: React.FC<{
<div className="flex flex-col space-y-0"> <div className="flex flex-col space-y-0">
<EditableTitle <EditableTitle
className="w-full truncate" className="w-full truncate"
disabled={!allowEdit} readOnly={readOnly}
onChange={onChangeTitle} onChange={onChangeTitle}
id={DASHBOARD_TITLE_INPUT_ID} id={DASHBOARD_TITLE_INPUT_ID}
placeholder="New Dashboard" placeholder="New Dashboard"
@ -39,11 +35,11 @@ export const DashboardEditTitles: React.FC<{
{title} {title}
</EditableTitle> </EditableTitle>
{(description || allowEdit) && ( {(description || !readOnly) && (
<Input <Input
variant="ghost" variant="ghost"
className={'pl-0!'} className={'pl-0!'}
disabled={!allowEdit} readOnly={readOnly}
onChange={onChangeDashboardDescription} onChange={onChangeDashboardDescription}
defaultValue={description} defaultValue={description}
placeholder="Add description..." placeholder="Add description..."

View File

@ -13,14 +13,18 @@ import {
useUpdateDashboardConfig useUpdateDashboardConfig
} from '@/api/buster_rest/dashboards'; } from '@/api/buster_rest/dashboards';
export const DashboardViewDashboardController: React.FC<DashboardViewProps> = ({ dashboardId }) => { export const DashboardViewDashboardController: React.FC<DashboardViewProps> = ({
dashboardId,
readOnly = false
}) => {
const isAnonymousUser = useUserConfigContextSelector((state) => state.isAnonymousUser); const isAnonymousUser = useUserConfigContextSelector((state) => state.isAnonymousUser);
const { data: dashboardResponse } = useGetDashboard(dashboardId); const { data: dashboardResponse } = useGetDashboard(dashboardId);
const { mutateAsync: onUpdateDashboard } = useUpdateDashboard(); const { mutateAsync: onUpdateDashboard } = useUpdateDashboard();
const { mutateAsync: onUpdateDashboardConfig } = useUpdateDashboardConfig(); const { mutateAsync: onUpdateDashboardConfig } = useUpdateDashboardConfig();
const [openAddContentModal, setOpenAddContentModal] = useState(false); const [openAddContentModal, setOpenAddContentModal] = useState(false);
const allowEdit = dashboardResponse?.permission !== ShareRole.VIEWER && !isAnonymousUser; const allowEdit =
!readOnly && dashboardResponse?.permission !== ShareRole.VIEWER && !isAnonymousUser;
const metrics = dashboardResponse?.metrics; const metrics = dashboardResponse?.metrics;
const dashboard = dashboardResponse?.dashboard; const dashboard = dashboardResponse?.dashboard;
@ -33,7 +37,7 @@ export const DashboardViewDashboardController: React.FC<DashboardViewProps> = ({
<DashboardEditTitles <DashboardEditTitles
onUpdateDashboard={onUpdateDashboard} onUpdateDashboard={onUpdateDashboard}
dashboardId={dashboardId} dashboardId={dashboardId}
allowEdit={allowEdit} readOnly={readOnly}
title={dashboardResponse?.dashboard?.name || ''} title={dashboardResponse?.dashboard?.name || ''}
description={dashboardResponse?.dashboard?.description || ''} description={dashboardResponse?.dashboard?.description || ''}
/> />
@ -43,6 +47,7 @@ export const DashboardViewDashboardController: React.FC<DashboardViewProps> = ({
dashboard={dashboard} dashboard={dashboard}
onUpdateDashboardConfig={onUpdateDashboardConfig} onUpdateDashboardConfig={onUpdateDashboardConfig}
onOpenAddContentModal={onOpenAddContentModal} onOpenAddContentModal={onOpenAddContentModal}
readOnly={readOnly}
/> />
</div> </div>
); );

View File

@ -5,6 +5,7 @@ import React from 'react';
export interface DashboardViewProps { export interface DashboardViewProps {
dashboardId: string; dashboardId: string;
readOnly?: boolean;
} }
export const DashboardViewComponents: Record<DashboardFileView, React.FC<DashboardViewProps>> = { export const DashboardViewComponents: Record<DashboardFileView, React.FC<DashboardViewProps>> = {