Cb 4178 te cloud storage improvements (#2532)

* CB-4178 chore: makes tree nodes names visible in react dev tools

* CB-4178 adds validation for loading files in cloud storage

* CB-4178 pr fixes

* CB-4178 pr fixes

* CB-4178 code cleanup

* CB-4178 selectFiles can return empty array

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
This commit is contained in:
sergeyteleshev
2024-04-09 16:35:13 +03:00
committed by GitHub
co-authored by Evgenia Bezborodova
parent 433eaacd24
commit 9e3e4322a3
14 changed files with 41 additions and 25 deletions
@@ -121,3 +121,5 @@ export const TreeNode = observer<Props, HTMLDivElement | null>(
);
}),
);
TreeNode.displayName = 'TreeNode';
@@ -127,3 +127,5 @@ export const TreeNodeControl = observer<Props & React.HTMLAttributes<HTMLDivElem
);
}),
);
TreeNodeControl.displayName = 'TreeNodeControl';
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
export function selectFiles(callback: (files: FileList | null) => any, multiple?: boolean): void {
export function selectFiles(callback: (files: File[]) => any, multiple?: boolean): void {
let removed = false;
const input = document.createElement('input');
input.type = 'file';
@@ -16,7 +16,7 @@ export function selectFiles(callback: (files: FileList | null) => any, multiple?
}
input.onchange = () => {
callback(input.files);
callback(input.files?.length ? Array.from(input.files) : []);
removed = true;
input.remove();
};
@@ -30,9 +30,12 @@ export function selectFiles(callback: (files: FileList | null) => any, multiple?
input.click();
setTimeout(() => {
if (!removed) {
input.remove();
}
}, 30 * 60 * 1000);
setTimeout(
() => {
if (!removed) {
input.remove();
}
},
30 * 60 * 1000,
);
}
@@ -85,7 +85,7 @@ export class DBDriverResource extends CachedMapResource<string, DBDriver, DBDriv
return this.data;
}
async addDriverLibraries(driverId: string, files: FileList) {
async addDriverLibraries(driverId: string, files: File[]) {
await this.graphQLService.sdk.uploadDriverLibrary(driverId, files);
await this.refresh(driverId);
}
@@ -45,7 +45,7 @@ export class CustomGraphQLClient extends GraphQLClient {
async uploadFiles<T = any, V extends Variables = Variables>(
url: string,
files: FileList,
files: File[],
query?: string,
variables?: V,
onUploadProgress?: (event: UploadProgressEvent) => void,
@@ -122,7 +122,7 @@ export class CustomGraphQLClient extends GraphQLClient {
private async overrideFilesUpload<T, V extends Variables = Variables>(
url: string,
files: FileList | Blob,
files: File[] | Blob,
query?: string,
variables?: V,
onUploadProgress?: (event: UploadProgressEvent) => void,
@@ -139,7 +139,7 @@ export class CustomGraphQLClient extends GraphQLClient {
fileData: undefined as any,
};
if (files instanceof FileList) {
if (files instanceof Array) {
data['files[]'] = files;
} else {
data.fileData = files;
@@ -10,12 +10,12 @@ import { GlobalConstants } from '@cloudbeaver/core-utils';
import type { CustomGraphQLClient, UploadProgressEvent } from '../CustomGraphQLClient';
export interface IUploadDriverLibraryExtension {
uploadDriverLibrary: (driverId: string, files: FileList, onUploadProgress?: (event: UploadProgressEvent) => void) => Promise<void>;
uploadDriverLibrary: (driverId: string, files: File[], onUploadProgress?: (event: UploadProgressEvent) => void) => Promise<void>;
}
export function uploadDriverLibraryExtension(client: CustomGraphQLClient): IUploadDriverLibraryExtension {
return {
uploadDriverLibrary(driverId: string, files: FileList, onUploadProgress?: (event: UploadProgressEvent) => void): Promise<void> {
uploadDriverLibrary(driverId: string, files: File[], onUploadProgress?: (event: UploadProgressEvent) => void): Promise<void> {
return client.uploadFiles(GlobalConstants.absoluteServiceUrl('drivers', 'library'), files, undefined, { driverId }, onUploadProgress);
},
};
@@ -8,19 +8,16 @@
import { selectFiles } from '@cloudbeaver/core-browser';
import { injectable } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import {
createResultSetBlobValue,
ResultSetDataContentAction,
ResultSetDataKeysUtils,
ResultSetEditAction,
ResultSetFormatAction,
} from '@cloudbeaver/plugin-data-viewer';
import { createResultSetBlobValue, ResultSetDataContentAction, ResultSetEditAction, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer';
import { DataGridContextMenuService } from './DataGridContextMenuService';
@injectable()
export class DataGridContextMenuSaveContentService {
constructor(private readonly dataGridContextMenuService: DataGridContextMenuService, private readonly notificationService: NotificationService) {}
constructor(
private readonly dataGridContextMenuService: DataGridContextMenuService,
private readonly notificationService: NotificationService,
) {}
register(): void {
this.dataGridContextMenuService.add(this.dataGridContextMenuService.getMenuToken(), {
@@ -60,7 +57,7 @@ export class DataGridContextMenuSaveContentService {
onClick: async context => {
selectFiles(files => {
const edit = context.data.model.source.getAction(context.data.resultIndex, ResultSetEditAction);
const file = files?.item(0) ?? undefined;
const file = files?.[0] ?? undefined;
if (file) {
edit.set(context.data.key, createResultSetBlobValue(file));
}
@@ -156,7 +156,7 @@ export const ImageValuePresentation: TabContainerPanelComponent<IDataValuePanelP
},
async upload() {
selectFiles(files => {
const file = files?.item(0) ?? undefined;
const file = files?.[0] ?? undefined;
if (file && this.selectedCell) {
this.editAction.set(this.selectedCell, createResultSetBlobValue(file));
}
@@ -96,15 +96,15 @@ export const NavigationNodeProjectControl: NavTreeControlComponent = observer<Na
return (
<TreeNodeControl
ref={ref}
className={s(styles, { treeNodeControl: true, outdated }, className)}
onClick={handleClick}
onContextMenu={handleContextMenuOpen}
className={s(styles, { treeNodeControl: true, outdated, }, className)}
>
<TreeNodeName title={name} className={s(styles, { treeNodeName: true })}>
<div className={s(styles, { nameBox: true })}>{name}</div>
</TreeNodeName>
{!dndPlaceholder && (
<div onClick={handlePortalClick} className={s(styles, { portal: true })}>
<div className={s(styles, { portal: true })} onClick={handlePortalClick}>
<TreeNodeMenuLoader mouseContextMenu={mouseContextMenu} node={node} selected={selected} />
</div>
)}
@@ -112,3 +112,5 @@ export const NavigationNodeProjectControl: NavTreeControlComponent = observer<Na
);
}),
);
NavigationNodeProjectControl.displayName = 'NavigationNodeProjectControl';
@@ -84,3 +84,5 @@ export const ConnectionNavNodeControl: NavTreeControlComponent = observer<NavTre
);
}),
);
ConnectionNavNodeControl.displayName = 'ConnectionNavNodeControl';
@@ -158,3 +158,5 @@ export const NavigationNodeControl: NavTreeControlComponent = observer(
);
}),
);
NavigationNodeControl.displayName = 'NavigationNodeControl';
@@ -72,3 +72,5 @@ export const NavigationNodeNested = observer(
);
}),
);
NavigationNodeNested.displayName = 'NavigationNodeNested';
@@ -108,3 +108,5 @@ export const NavigationNodeControlRenderer = observer<Props, HTMLDivElement>(
);
}),
);
NavigationNodeControlRenderer.displayName = 'NavigationNodeControlRenderer';
@@ -79,3 +79,5 @@ export const NavigationNodeProjectControl: NavTreeControlComponent = observer<Na
);
}),
);
NavigationNodeProjectControl.displayName = 'NavigationNodeProjectControl';