report asset layout

This commit is contained in:
Nate Kelley 2025-08-02 23:47:27 -06:00
parent 21b3c22e5c
commit 08d7014725
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
9 changed files with 85 additions and 13 deletions

View File

@ -65,18 +65,19 @@ export const prefetchGetReportsList = async (
/** /**
* Hook to get an individual report by ID * Hook to get an individual report by ID
*/ */
export const useGetReportById = ( export const useGetReport = (
reportId: string, reportId: string | undefined,
options?: Omit<UseQueryOptions<GetReportIndividualResponse, RustApiError>, 'queryKey' | 'queryFn'> options?: Omit<UseQueryOptions<GetReportIndividualResponse, RustApiError>, 'queryKey' | 'queryFn'>
) => { ) => {
const queryFn = useMemoizedFn(() => { const queryFn = useMemoizedFn(() => {
return getReportById(reportId); return getReportById(reportId!);
}); });
return useQuery({ return useQuery({
...queryKeys.reportsGetById(reportId), ...queryKeys.reportsGetById(reportId!),
queryFn, queryFn,
enabled: !!reportId, enabled: !!reportId,
select: options?.select,
...options ...options
}); });
}; };

View File

@ -0,0 +1,46 @@
import { AppAssetCheckLayout } from '@/layouts/AppAssetCheckLayout';
import type { Metadata } from 'next';
import { getTitle_server } from '@/api/buster_rest/title';
export default async function ReportLayout({
children,
params
}: {
children: React.ReactNode;
params: Promise<{ reportId: string }>;
}) {
const { reportId } = await params;
return (
<AppAssetCheckLayout assetId={reportId} type="report">
{children}
</AppAssetCheckLayout>
);
}
// Generate metadata dynamically based on the report - shared across all child pages
export async function generateMetadata({
params
}: {
params: Promise<{ reportId: string }>;
}): Promise<Metadata> {
const { reportId } = await params;
try {
// Fetch the report title using the server-side request
const response = await getTitle_server({
assetId: reportId,
assetType: 'report'
});
return {
title: response.title || 'New Report'
};
} catch (error) {
// Fallback title if the request fails
console.error('Failed to fetch report title:', error);
return {
title: 'New Report'
};
}
}

View File

@ -0,0 +1,5 @@
import { FileIndeterminateLoader } from '@/components/features/FileIndeterminateLoader';
export default function Loading() {
return <FileIndeterminateLoader />;
}

View File

@ -1,10 +1,7 @@
'use client'; 'use client';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import type { import type { GetDatasetGroupDatasetsResponse } from '@/api/asset_interfaces';
GetDatasetGroupDatasetsResponse,
GetPermissionGroupUsersResponse
} from '@/api/asset_interfaces';
import { useUpdateDatasetGroupDatasets } from '@/api/buster_rest/dataset_groups'; import { useUpdateDatasetGroupDatasets } from '@/api/buster_rest/dataset_groups';
import { PermissionAssignedCell } from '@/components/features/PermissionComponents'; import { PermissionAssignedCell } from '@/components/features/PermissionComponents';
import { import {
@ -42,7 +39,7 @@ export const DatasetGroupDatasetsListContainer: React.FC<{
title: 'Assigned', title: 'Assigned',
dataIndex: 'assigned', dataIndex: 'assigned',
width: 130 + 85, width: 130 + 85,
render: (assigned, permissionGroup: GetPermissionGroupUsersResponse) => { render: (assigned, permissionGroup) => {
return ( return (
<div className="flex justify-end"> <div className="flex justify-end">
<PermissionAssignedCell <PermissionAssignedCell

View File

@ -3,7 +3,7 @@ import React from 'react';
export default function FileText() { export default function FileText() {
return ( return (
<svg xmlns="http://www.w3.org/2000/svg" height="1em" width="1em" viewBox="0 0 24 24"> <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<title>file-text</title> <title>file-text</title>
<g fill="currentColor" strokeLinejoin="miter" strokeLinecap="butt"> <g fill="currentColor" strokeLinejoin="miter" strokeLinecap="butt">
<path <path

View File

@ -11,7 +11,7 @@ import { useDocumentTitle } from '@/hooks';
export type AppAssetCheckLayoutProps = { export type AppAssetCheckLayoutProps = {
assetId: string; assetId: string;
type: 'metric' | 'dashboard' | 'collection'; type: 'metric' | 'dashboard' | 'collection' | 'report';
versionNumber?: number; versionNumber?: number;
}; };

View File

@ -6,8 +6,8 @@ import { useGetCollection } from '@/api/buster_rest/collections';
import { useGetDashboard } from '@/api/buster_rest/dashboards'; import { useGetDashboard } from '@/api/buster_rest/dashboards';
import type { RustApiError } from '@/api/buster_rest/errors'; import type { RustApiError } from '@/api/buster_rest/errors';
import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics'; import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
import type { AssetType } from '@buster/server-shared/assets';
type AssetType = 'metric' | 'dashboard' | 'collection'; import { useGetReport } from '@/api/buster_rest/reports';
interface BaseGetAssetProps { interface BaseGetAssetProps {
assetId: string; assetId: string;
@ -81,6 +81,7 @@ export const useGetAsset = (
const isMetric = props.type === 'metric'; const isMetric = props.type === 'metric';
const isDashboard = props.type === 'dashboard'; const isDashboard = props.type === 'dashboard';
const isCollection = props.type === 'collection'; const isCollection = props.type === 'collection';
const isReport = props.type === 'report';
// Always call hooks at the top level with appropriate enabled flags // Always call hooks at the top level with appropriate enabled flags
const { const {
@ -126,6 +127,15 @@ export const useGetAsset = (
select: (x) => x?.name select: (x) => x?.name
}); });
const {
isFetched: reportIsFetched,
error: reportError,
isError: reportIsError,
data: reportTitle
} = useGetReport(isReport ? props.assetId : undefined, {
select: (x) => x?.name
});
const currentQuery = useMemo((): AssetQueryResult => { const currentQuery = useMemo((): AssetQueryResult => {
switch (props.type) { switch (props.type) {
case 'metric': case 'metric':
@ -149,6 +159,14 @@ export const useGetAsset = (
isError: collectionIsError, isError: collectionIsError,
showLoader: !collectionIsFetched && !collectionIsError showLoader: !collectionIsFetched && !collectionIsError
}; };
case 'report':
return {
isFetched: reportIsFetched,
error: reportError,
isError: reportIsError,
showLoader: !reportIsFetched && !reportIsError
};
default: { default: {
const exhaustiveCheck: never = props.type; const exhaustiveCheck: never = props.type;
return { isFetched: false, error: null, isError: false, showLoader: false }; return { isFetched: false, error: null, isError: false, showLoader: false };

View File

@ -21,6 +21,10 @@
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"default": "./dist/index.js" "default": "./dist/index.js"
}, },
"./assets": {
"types": "./dist/assets/index.d.ts",
"default": "./dist/assets/index.js"
},
"./chats": { "./chats": {
"types": "./dist/chats/index.d.ts", "types": "./dist/chats/index.d.ts",
"default": "./dist/chats/index.js" "default": "./dist/chats/index.js"

View File

@ -0,0 +1 @@
export * from './asset-types.types';