mirror of https://github.com/buster-so/buster.git
embeddable dashboard
This commit is contained in:
parent
178cc86a7e
commit
96731d86d0
|
@ -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';
|
||||||
|
|
|
@ -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} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" />;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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..."
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>> = {
|
||||||
|
|
Loading…
Reference in New Issue