mirror of https://github.com/buster-so/buster.git
Refactor sharing request types and enhance asset icon mapping
- Updated sharing request types to use SharePermissionsUpdateRequest for clarity across collections, dashboards, and metrics. - Enhanced asset icon mapping to include additional asset types for better UI representation. - Improved error handling in the MetricDataTruncatedWarning component to provide user feedback during download failures.
This commit is contained in:
parent
a133653ccc
commit
895e28f8d4
|
@ -234,7 +234,7 @@ export const useUpdateCollectionShare = () => {
|
||||||
return create(previousData, (draft) => {
|
return create(previousData, (draft) => {
|
||||||
draft.individual_permissions = (
|
draft.individual_permissions = (
|
||||||
draft.individual_permissions?.map((t) => {
|
draft.individual_permissions?.map((t) => {
|
||||||
const found = params.users?.find((v) => v.email === t.email);
|
const found = params.users?.find((v: { email: string; role: string }) => v.email === t.email);
|
||||||
if (found) return { ...t, ...found };
|
if (found) return { ...t, ...found };
|
||||||
return t;
|
return t;
|
||||||
}) || []
|
}) || []
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type { ShareAssetType } from '@buster/server-shared/share';
|
||||||
import type { BusterCollection, BusterCollectionListItem } from '@/api/asset_interfaces/collection';
|
import type { BusterCollection, BusterCollectionListItem } from '@/api/asset_interfaces/collection';
|
||||||
import mainApi from '@/api/buster_rest/instances';
|
import mainApi from '@/api/buster_rest/instances';
|
||||||
import type { SharePostRequest } from '@buster/server-shared/share';
|
import type { SharePostRequest } from '@buster/server-shared/share';
|
||||||
import type { ShareDeleteRequest, ShareUpdateRequest } from '@buster/server-shared/share';
|
import type { ShareDeleteRequest, SharePermissionsUpdateRequest } from '@buster/server-shared/share';
|
||||||
|
|
||||||
export const collectionsGetList = async (params: {
|
export const collectionsGetList = async (params: {
|
||||||
/** Current page number (1-based indexing) */
|
/** Current page number (1-based indexing) */
|
||||||
|
@ -91,7 +91,7 @@ export const updateCollectionShare = async ({
|
||||||
id
|
id
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
params: ShareUpdateRequest;
|
params: SharePermissionsUpdateRequest;
|
||||||
}) => {
|
}) => {
|
||||||
return mainApi
|
return mainApi
|
||||||
.put<BusterCollection>(`/collections/${id}/sharing`, params)
|
.put<BusterCollection>(`/collections/${id}/sharing`, params)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type {
|
||||||
import type {
|
import type {
|
||||||
SharePostRequest,
|
SharePostRequest,
|
||||||
ShareDeleteRequest,
|
ShareDeleteRequest,
|
||||||
ShareUpdateRequest
|
SharePermissionsUpdateRequest
|
||||||
} from '@buster/server-shared/share';
|
} from '@buster/server-shared/share';
|
||||||
import mainApi from '@/api/buster_rest/instances';
|
import mainApi from '@/api/buster_rest/instances';
|
||||||
import { serverFetch } from '@/api/createServerInstance';
|
import { serverFetch } from '@/api/createServerInstance';
|
||||||
|
@ -103,7 +103,7 @@ export const updateDashboardShare = async ({
|
||||||
id
|
id
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
params: ShareUpdateRequest;
|
params: SharePermissionsUpdateRequest;
|
||||||
}) => {
|
}) => {
|
||||||
return mainApi
|
return mainApi
|
||||||
.put<BusterDashboardResponse>(`/dashboards/${id}/sharing`, params)
|
.put<BusterDashboardResponse>(`/dashboards/${id}/sharing`, params)
|
||||||
|
|
|
@ -17,7 +17,7 @@ import type {
|
||||||
ShareUpdateResponse,
|
ShareUpdateResponse,
|
||||||
MetricDownloadResponse
|
MetricDownloadResponse
|
||||||
} from '@buster/server-shared/metrics';
|
} from '@buster/server-shared/metrics';
|
||||||
import type { ShareDeleteRequest, ShareUpdateRequest } from '@buster/server-shared/share';
|
import type { ShareDeleteRequest, SharePermissionsUpdateRequest } from '@buster/server-shared/share';
|
||||||
import { serverFetch } from '@/api/createServerInstance';
|
import { serverFetch } from '@/api/createServerInstance';
|
||||||
import { mainApi, mainApiV2 } from '../instances';
|
import { mainApi, mainApiV2 } from '../instances';
|
||||||
import { SharePostRequest } from '@buster/server-shared/share';
|
import { SharePostRequest } from '@buster/server-shared/share';
|
||||||
|
@ -99,7 +99,7 @@ export const updateMetricShare = async ({
|
||||||
id
|
id
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
params: ShareUpdateRequest;
|
params: SharePermissionsUpdateRequest;
|
||||||
}) => {
|
}) => {
|
||||||
return mainApi
|
return mainApi
|
||||||
.put<ShareUpdateResponse>(`/metric_files/${id}/sharing`, params)
|
.put<ShareUpdateResponse>(`/metric_files/${id}/sharing`, params)
|
||||||
|
|
|
@ -25,15 +25,26 @@ export const ASSET_ICONS = {
|
||||||
export const assetTypeToIcon = (assetType: ShareAssetType) => {
|
export const assetTypeToIcon = (assetType: ShareAssetType) => {
|
||||||
switch (assetType) {
|
switch (assetType) {
|
||||||
case 'metric':
|
case 'metric':
|
||||||
|
case 'metric_file':
|
||||||
return ASSET_ICONS.metrics;
|
return ASSET_ICONS.metrics;
|
||||||
case 'dashboard':
|
case 'dashboard':
|
||||||
|
case 'dashboard_file':
|
||||||
return ASSET_ICONS.dashboards;
|
return ASSET_ICONS.dashboards;
|
||||||
case 'collection':
|
case 'collection':
|
||||||
|
case 'collection_file':
|
||||||
return ASSET_ICONS.collections;
|
return ASSET_ICONS.collections;
|
||||||
case 'chat':
|
case 'chat':
|
||||||
|
case 'thread':
|
||||||
return ASSET_ICONS.chats;
|
return ASSET_ICONS.chats;
|
||||||
case 'report':
|
case 'report':
|
||||||
return ASSET_ICONS.reports;
|
return ASSET_ICONS.reports;
|
||||||
|
case 'data_source':
|
||||||
|
case 'filter':
|
||||||
|
case 'dataset':
|
||||||
|
case 'tool':
|
||||||
|
case 'source':
|
||||||
|
case 'dataset_permission':
|
||||||
|
return ASSET_ICONS.table;
|
||||||
default: {
|
default: {
|
||||||
const _result: never = assetType;
|
const _result: never = assetType;
|
||||||
return ASSET_ICONS.metrics;
|
return ASSET_ICONS.metrics;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Text } from '@/components/ui/typography';
|
import { Text } from '@/components/ui/typography';
|
||||||
import { Button } from '@/components/ui/buttons';
|
import { Button } from '@/components/ui/buttons';
|
||||||
import { Download4 } from '@/components/ui/icons';
|
import { Download4, CircleWarning } from '@/components/ui/icons';
|
||||||
import { cn } from '@/lib/classMerge';
|
import { cn } from '@/lib/classMerge';
|
||||||
import { downloadMetricFile } from '@/api/buster_rest/metrics/requests';
|
import { downloadMetricFile } from '@/api/buster_rest/metrics/requests';
|
||||||
|
|
||||||
|
@ -15,21 +15,30 @@ export const MetricDataTruncatedWarning: React.FC<MetricDataTruncatedWarningProp
|
||||||
metricId
|
metricId
|
||||||
}) => {
|
}) => {
|
||||||
const [isDownloading, setIsDownloading] = useState(false);
|
const [isDownloading, setIsDownloading] = useState(false);
|
||||||
|
const [hasError, setHasError] = useState(false);
|
||||||
|
|
||||||
const handleDownload = async () => {
|
const handleDownload = async () => {
|
||||||
try {
|
try {
|
||||||
setIsDownloading(true);
|
setIsDownloading(true);
|
||||||
|
setHasError(false);
|
||||||
// Call the API to get the download URL
|
|
||||||
const response = await downloadMetricFile(metricId);
|
// Create a timeout promise that rejects after 3 minutes
|
||||||
|
const timeoutPromise = new Promise((_, reject) => {
|
||||||
|
setTimeout(() => reject(new Error('Download timeout')), 3 * 60 * 1000); // 3 minutes
|
||||||
|
});
|
||||||
|
|
||||||
|
// Race between the API call and the timeout
|
||||||
|
const response = await Promise.race([
|
||||||
|
downloadMetricFile(metricId),
|
||||||
|
timeoutPromise
|
||||||
|
]) as Awaited<ReturnType<typeof downloadMetricFile>>;
|
||||||
|
|
||||||
// Simply navigate to the download URL
|
// Simply navigate to the download URL
|
||||||
// The response-content-disposition header will force a download
|
// The response-content-disposition header will force a download
|
||||||
window.location.href = response.downloadUrl;
|
window.location.href = response.downloadUrl;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to download metric file:', error);
|
console.error('Failed to download metric file:', error);
|
||||||
// You might want to show an error toast here
|
setHasError(true);
|
||||||
} finally {
|
} finally {
|
||||||
// Add a small delay before removing loading state since download happens async
|
// Add a small delay before removing loading state since download happens async
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -40,22 +49,31 @@ export const MetricDataTruncatedWarning: React.FC<MetricDataTruncatedWarningProp
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn('bg-background flex items-center justify-between rounded border p-4 shadow', className)}>
|
className={cn(
|
||||||
|
'bg-background flex items-center justify-between rounded border p-4 shadow',
|
||||||
|
hasError && 'border-red-500',
|
||||||
|
className
|
||||||
|
)}>
|
||||||
<div className="flex flex-col space-y-1">
|
<div className="flex flex-col space-y-1">
|
||||||
<Text className="font-medium">This request returned more than 5,000 records</Text>
|
<Text className="font-medium">
|
||||||
<Text size="xs" variant="secondary">
|
{hasError
|
||||||
To see all records, you'll need to download the results.
|
? 'Download failed'
|
||||||
|
: 'This request returned more than 5,000 records'}
|
||||||
|
</Text>
|
||||||
|
<Text size="xs" variant={hasError ? 'danger' : 'secondary'}>
|
||||||
|
{hasError
|
||||||
|
? 'The download took too long or encountered an error. Please try again.'
|
||||||
|
: 'To see all records, you\'ll need to download the results.'}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleDownload}
|
onClick={handleDownload}
|
||||||
loading={isDownloading}
|
loading={isDownloading}
|
||||||
variant="default"
|
variant={hasError ? 'danger' : 'default'}
|
||||||
className="ml-4"
|
className="ml-4"
|
||||||
prefix={<Download4 />}
|
prefix={hasError ? <CircleWarning /> : <Download4 />}>
|
||||||
>
|
{hasError ? 'Try Again' : 'Download'}
|
||||||
Download
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue