mirror of https://github.com/buster-so/buster.git
download metric file in three dot
This commit is contained in:
parent
3488f8798b
commit
5708592a51
|
@ -18,6 +18,7 @@ import {
|
|||
setProtectedAssetPasswordError,
|
||||
useProtectedAssetPassword,
|
||||
} from '@/context/BusterAssets/useProtectedAssetStore';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
import { setOriginalMetric } from '@/context/Metrics/useOriginalMetricStore';
|
||||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||
import { upgradeMetricToIMetric } from '@/lib/metrics';
|
||||
|
@ -226,8 +227,20 @@ export const usePrefetchGetMetricDataClient = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export const useDownloadMetricFile = () => {
|
||||
export const useDownloadMetricFile = (downloadImmediate = true) => {
|
||||
const { openInfoMessage } = useBusterNotifications();
|
||||
return useMutation({
|
||||
mutationFn: downloadMetricFile,
|
||||
onSuccess: (data) => {
|
||||
if (downloadImmediate) {
|
||||
const link = document.createElement('a');
|
||||
link.href = data.downloadUrl;
|
||||
link.download = ''; // This will use the filename from the response-content-disposition header
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
openInfoMessage(`Downloading ${data.rowCount} records...`);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Route as AuthRoute } from '@/routes/auth.login';
|
|||
import { BASE_URL_V2 } from './config';
|
||||
import { rustErrorHandler } from './errors';
|
||||
|
||||
const AXIOS_TIMEOUT = 180000; // 3 minutes
|
||||
const AXIOS_TIMEOUT = 120000; // 2 minutes
|
||||
|
||||
export const createAxiosInstance = (baseURL = BASE_URL_V2) => {
|
||||
const apiInstance = axios.create({
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import type React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useDownloadMetricFile } from '@/api/buster_rest/metrics/getMetricQueryRequests';
|
||||
import { Button } from '@/components/ui/buttons';
|
||||
import { CircleWarning, Download4 } from '@/components/ui/icons';
|
||||
|
@ -16,38 +15,13 @@ export const MetricDataTruncatedWarning: React.FC<MetricDataTruncatedWarningProp
|
|||
metricId,
|
||||
}) => {
|
||||
const {
|
||||
mutateAsync: downloadMetricFile,
|
||||
mutateAsync: handleDownload,
|
||||
isPending: isGettingFile,
|
||||
error: downloadError,
|
||||
} = useDownloadMetricFile();
|
||||
|
||||
const hasError = !!downloadError;
|
||||
|
||||
const handleDownload = async () => {
|
||||
try {
|
||||
// Create a timeout promise that rejects after 2 minutes (matching backend timeout)
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Download timeout')), 2 * 60 * 1000); // 2 minutes
|
||||
});
|
||||
|
||||
// Race between the API call and the timeout
|
||||
const response = (await Promise.race([
|
||||
downloadMetricFile(metricId),
|
||||
timeoutPromise,
|
||||
])) as Awaited<ReturnType<typeof downloadMetricFile>>;
|
||||
|
||||
// Create a temporary anchor element to trigger download without navigation
|
||||
const link = document.createElement('a');
|
||||
link.href = response.downloadUrl;
|
||||
link.download = ''; // This will use the filename from the response-content-disposition header
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
} catch (error) {
|
||||
console.error('Failed to download metric file:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
|
@ -67,7 +41,7 @@ export const MetricDataTruncatedWarning: React.FC<MetricDataTruncatedWarningProp
|
|||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleDownload}
|
||||
onClick={() => handleDownload(metricId)}
|
||||
loading={isGettingFile}
|
||||
variant={hasError ? 'danger' : 'default'}
|
||||
className="ml-4"
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import React from 'react';
|
||||
import type { BusterMetric, BusterMetricData } from '@/api/asset_interfaces/metric';
|
||||
import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
|
||||
import type { BusterMetricData } from '@/api/asset_interfaces/metric';
|
||||
import { useGetMetricData } from '@/api/buster_rest/metrics';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { MetricChartCard } from '../MetricChartCard';
|
||||
import { MetricChartEvaluation } from './MetricChartEvaluation';
|
||||
import { MetricDataTruncatedWarning } from './MetricDataTruncatedWarning';
|
||||
|
||||
const stableMetricSelect = ({ evaluation_score, evaluation_summary }: BusterMetric) => ({
|
||||
evaluation_score,
|
||||
evaluation_summary,
|
||||
});
|
||||
const stableMetricDataSelect = (x: BusterMetricData) => x?.has_more_records;
|
||||
|
||||
export const MetricViewChart: React.FC<{
|
||||
|
@ -21,10 +15,6 @@ export const MetricViewChart: React.FC<{
|
|||
cardClassName?: string;
|
||||
}> = React.memo(
|
||||
({ metricId, versionNumber, readOnly = false, className = '', cardClassName = '' }) => {
|
||||
const { data: metric } = useGetMetric(
|
||||
{ id: metricId, versionNumber },
|
||||
{ select: stableMetricSelect, enabled: true }
|
||||
);
|
||||
const { data: hasMoreRecords } = useGetMetricData(
|
||||
{ id: metricId, versionNumber },
|
||||
{ select: stableMetricDataSelect }
|
||||
|
@ -41,11 +31,6 @@ export const MetricViewChart: React.FC<{
|
|||
/>
|
||||
{hasMoreRecords && <MetricDataTruncatedWarning metricId={metricId} />}
|
||||
</div>
|
||||
|
||||
<MetricChartEvaluationWrapper
|
||||
evaluationScore={metric?.evaluation_score}
|
||||
evaluationSummary={metric?.evaluation_summary}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -59,22 +44,3 @@ const animation = {
|
|||
exit: { opacity: 0 },
|
||||
transition: { duration: 0.4 },
|
||||
};
|
||||
|
||||
const MetricChartEvaluationWrapper: React.FC<{
|
||||
evaluationScore: BusterMetric['evaluation_score'] | undefined;
|
||||
evaluationSummary: string | undefined;
|
||||
}> = ({ evaluationScore, evaluationSummary }) => {
|
||||
const show = !!evaluationScore && !!evaluationSummary;
|
||||
return (
|
||||
<AnimatePresence initial={false}>
|
||||
{show && (
|
||||
<motion.div {...animation}>
|
||||
<MetricChartEvaluation
|
||||
evaluationScore={evaluationScore}
|
||||
evaluationSummary={evaluationSummary}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useNavigate } from '@tanstack/react-router';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import type { BusterMetric } from '@/api/asset_interfaces/metric';
|
||||
import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
|
||||
import { useDownloadMetricFile, useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
|
||||
import {
|
||||
createDropdownItem,
|
||||
createDropdownItems,
|
||||
|
@ -25,11 +25,10 @@ import { Star as StarFilled } from '@/components/ui/icons/NucleoIconFilled';
|
|||
import { useStartChatFromAsset } from '@/context/BusterAssets/useStartChatFromAsset';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
import { ensureElementExists } from '@/lib/element';
|
||||
import { downloadElementToImage, exportJSONToCSV } from '@/lib/exportUtils';
|
||||
import { downloadElementToImage } from '@/lib/exportUtils';
|
||||
import { canEdit } from '../../../lib/share';
|
||||
import { FollowUpWithAssetContent } from '../assets/FollowUpWithAsset';
|
||||
import { useFavoriteStar } from '../favorites';
|
||||
import { ASSET_ICONS } from '../icons/assetIcons';
|
||||
import { getShareAssetConfig } from '../ShareMenu/helpers';
|
||||
import { useListMetricVersionDropdownItems } from '../versionHistory/useListMetricVersionDropdownItems';
|
||||
import { METRIC_CHART_CONTAINER_ID } from './MetricChartCard/config';
|
||||
|
@ -165,15 +164,10 @@ export const useDownloadMetricDataCSV = ({
|
|||
metricVersionNumber: number | undefined;
|
||||
cacheDataId?: string;
|
||||
}) => {
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
const { data: metricData } = useGetMetricData(
|
||||
{ id: metricId, versionNumber: metricVersionNumber, cacheDataId },
|
||||
{ enabled: false }
|
||||
);
|
||||
const { data: name } = useGetMetric(
|
||||
{ id: metricId },
|
||||
{ select: useCallback((x: BusterMetric) => x.name, []) }
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
|
@ -183,14 +177,12 @@ export const useDownloadMetricDataCSV = ({
|
|||
loading: isDownloading,
|
||||
onClick: async () => {
|
||||
const data = metricData?.data;
|
||||
if (data && name) {
|
||||
setIsDownloading(true);
|
||||
await exportJSONToCSV(data, name);
|
||||
setIsDownloading(false);
|
||||
if (data) {
|
||||
await handleDownload(metricId);
|
||||
}
|
||||
},
|
||||
}),
|
||||
[metricData, isDownloading, name]
|
||||
[metricData, isDownloading]
|
||||
);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue