Skip to content

Commit

Permalink
EPMUII-8317 Add errors handling for load from URL
Browse files Browse the repository at this point in the history
  • Loading branch information
OleksandrZhynzher committed Nov 17, 2023
1 parent 6d60f90 commit cd1c627
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 16 deletions.
22 changes: 15 additions & 7 deletions src/engine/lib/core/loaders/MRIFileLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class MRIFileLoader {
* @param {string} url - The URL of the file to load.
* @returns {Promise<File[]>} A promise that resolves to an array of Files or rejects with an error.
*/
async load(url: string): Promise<File[]> {
async load(url: string): Promise<File[] | null> {
this.filesLoaded = 0;
this.filesProgressByLength = false;
this.store.setLoadingProgress(0);
Expand Down Expand Up @@ -52,15 +52,16 @@ export class MRIFileLoader {
* @param {string} url - The URL from which to fetch the file.
* @returns {Promise<File[]>} A promise that resolves to an array containing the fetched file as a File object.
*/
async fetchSingleFile(url: string): Promise<File[]> {
async fetchSingleFile(url: string): Promise<File[] | null> {
const response = await this.fetchWithProgress(url, this.callbackLoadProgress);

if (!response.ok) {
this.handleVolumeLoadFailed(`Failed to fetch file from URL: ${url}`);
return [];
return null;
}

const blob = await response.blob();

const fileName = getFileNameFromUrl(url);
const file = new File([blob], fileName, {
type: blob.type,
Expand Down Expand Up @@ -91,14 +92,15 @@ export class MRIFileLoader {
* @param {string} txtUrl - The URL of the .txt file containing the list of file URLs.
* @returns {Promise<File[]>} A promise that resolves to an array of File objects.
*/
async fetchTxtFile(txtUrl: string): Promise<File[]> {
async fetchTxtFile(txtUrl: string): Promise<File[] | null> {
this.filesProgressByLength = true;
const base = txtUrl.substring(0, txtUrl.lastIndexOf('/') + 1);
const fileNames = await this.fetchTxtContent(txtUrl);
this.filesLength = fileNames.length;
const filePromises = fileNames.map((filename: string) => this.fetchSingleFile(base + filename));
const files = await Promise.all(filePromises);
return files.flat();
const validFalies = files.filter(Boolean) as Array<File[]>;
return validFalies.flat();
}

/**
Expand Down Expand Up @@ -131,7 +133,9 @@ export class MRIFileLoader {

const files = await Promise.all(filePromises);

return files.flat();
const validFalies = files.filter(Boolean) as Array<File[]>;

return validFalies.flat();
}

/**
Expand All @@ -154,6 +158,10 @@ export class MRIFileLoader {
};

xhr.onload = () => {
if (xhr.status === 403) {
return this.handleVolumeLoadFailed(`Error 403 Forbiden, failed to fetch file from URL: ${url}`);
}

if (this.filesProgressByLength) {
this.filesLoaded = this.filesLoaded + 1;
const percentComplete = this.filesLoaded / this.filesLength;
Expand Down Expand Up @@ -189,6 +197,6 @@ export class MRIFileLoader {
*/
handleVolumeLoadFailed(error: string) {
this.events.emit(MriEvents.FILE_READ_ERROR, { error });
this.store.setVolumeLoadFailed(this.fileName, [error]);
this.store.setVolumeLoadFailed(this.fileName);
}
}
7 changes: 5 additions & 2 deletions src/engine/lib/core/readers/MRIReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ export class MRIReader {
if (data && data.length && data[0] instanceof File) {
this.fileReader.read(data as File[]);
} else if (isValidUrl(data as string)) {
const files: File[] = await this.fileLoader.load(data as string);
this.fileReader.read(files);
const files: File[] | null = await this.fileLoader.load(data as string);

if (files) {
this.fileReader.read(files);
}
} else {
throw new Error('Invalid input. Expected a File or URL.');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export abstract class AbstractFileReader {
*/
public handleVolumeReadFailed(error: string) {
this.events.emit(MriEvents.FILE_READ_ERROR, { error });
this.store.setVolumeLoadFailed(this.fileName, [error]);
this.store.setVolumeLoadFailed(this.fileName);
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/engine/lib/services/StoreService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,10 @@ export class MRIStoreService {
this.dispatchActions(actions);
}

public setVolumeLoadFailed(fileName: string, errors: string[]): void {
public setVolumeLoadFailed(fileName: string): void {
const actions = [
{ type: StoreActionType.SET_ERR_ARRAY, errors },
{ type: StoreActionType.SET_VOLUME_SET, volume: null },
{ type: StoreActionType.SET_FILENAME, fileName: fileName },
{ type: StoreActionType.SET_FILENAME, fileName },
{ type: StoreActionType.SET_PROGRESS, progress: 0 },
{ type: StoreActionType.SET_SPINNER, spinner: false },
{ type: StoreActionType.SET_IS_LOADED, isLoaded: false },
Expand Down
25 changes: 22 additions & 3 deletions src/ui/Main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import StoreActionType from '../store/ActionTypes';
import FullScreenToggle from './Toolbars/FullScreen';
import UiModalText from './Modals/UiModalText';
import UiModalAlert from './Modals/ModalAlert';
import UiErrConsole from './UiErrConsole';
import ModeView from '../store/ViewMode';
import Graphics2d from '../engine/Graphics2d';
import BrowserDetector from '../engine/utils/BrowserDetector';
Expand All @@ -28,13 +27,16 @@ import { TopToolbar } from './TopToolbar/TopToolbar';
import { UiAbout } from './Header/UiAbout';
import { MobileSettings } from './MobileSettings/MobileSettings';
import StartScreen from './StartScreen/StartScreen';
import MriViwer from '../engine/lib/MRIViewer';
import { MriEvents } from '../engine/lib/enums';

import css from './Main.module.css';
import cx from 'classnames';
import '../nouislider-custom.css';

export const Main = () => {
const dispatch = useDispatch();
const { arrErrors, isLoaded, progress, spinner, viewMode, showModalText, showModalAlert } = useSelector((state) => state);
const { isLoaded, progress, spinner, viewMode, showModalText, showModalAlert } = useSelector((state) => state);

const [m_fileNameOnLoad, setM_fileNameOnLoad] = useState(false);
const [isWebGl20supported, setIsWebGl20supported] = useState(true);
Expand All @@ -43,6 +45,7 @@ export const Main = () => {
const [isFullMode, setIsFullMode] = useState(false);
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
const appRef = useRef();
const mriViwer = useRef(MriViwer).current;

useEffect(() => {
function handleResize() {
Expand All @@ -55,6 +58,23 @@ export const Main = () => {
window.removeEventListener('resize', handleResize);
};
}, []);

useEffect(() => {
const handleFileReadError = (eventData) => {
setStrAlertTitle('File Read Error');
setStrAlertText(eventData.error);
onShowModalAlert();
};

// Subscribe to the FILE_READ_ERROR event
mriViwer.events.on(MriEvents.FILE_READ_ERROR, handleFileReadError);

// Clean up
return () => {
mriViwer.events.off(MriEvents.FILE_READ_ERROR, handleFileReadError);
};
}, []);

const [, drop] = useDrop(
() => ({
accept: DnDItemTypes.SETTINGS,
Expand Down Expand Up @@ -204,7 +224,6 @@ export const Main = () => {
<MobileSettings />
</div>
)}
{arrErrors.length > 0 && <UiErrConsole />}
{showModalText && (
<UiModalText stateVis={showModalText} onHide={onHideModalText.bind(this)} onShow={onShowModalText.bind(this)} />
)}
Expand Down

0 comments on commit cd1c627

Please sign in to comment.