Added scenery loaded dialog
+Added a dialog shown after scenery parsing is complete, displaying whether any warnings/errors occurred and, if so, showing the parser logs *Improved parser's error handling *Fixed a typo in the switch parsing related warning
This commit is contained in:
parent
9419f613be
commit
c56f471d65
14
src/components/scenery-loaded-dialog/SceneryLoadedDialog.css
Normal file
14
src/components/scenery-loaded-dialog/SceneryLoadedDialog.css
Normal file
@ -0,0 +1,14 @@
|
||||
.scenery-loaded-dialog-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.scenery-loaded-dialog-content .main-message {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.scenery-loaded-dialog-content .scenery-parser-log-view {
|
||||
max-height: 30vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
46
src/components/scenery-loaded-dialog/SceneryLoadedDialog.js
Normal file
46
src/components/scenery-loaded-dialog/SceneryLoadedDialog.js
Normal file
@ -0,0 +1,46 @@
|
||||
import { forwardRef, useImperativeHandle } from 'react';
|
||||
import SceneryParserLog from '../../model/scenery-parser-log';
|
||||
import SceneryParserLogView from '../scenery-loaded-dialog/SceneryParserLogView';
|
||||
import '../dialog/Dialog.css';
|
||||
import './SceneryLoadedDialog.css'
|
||||
import Constants from '../../helpers/constants';
|
||||
|
||||
const SceneryLoadedDialog = forwardRef((props, ref) => {
|
||||
const {onClose, loadingError} = props;
|
||||
|
||||
const onBgClick = () => {
|
||||
onClose();
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
onBgClick: onBgClick
|
||||
}));
|
||||
|
||||
const warningsOrError = SceneryParserLog.hasWarnings || !!loadingError;
|
||||
const showLog = Constants.parser.alwaysShowLogDialog || warningsOrError;
|
||||
|
||||
const message = loadingError ? "An error occurred while loading the scenery"
|
||||
:( SceneryParserLog.hasWarnings ? "Scenery loaded with warnings"
|
||||
: "Scenery loaded successfully" );
|
||||
|
||||
const additionalErr = (loadingError && !SceneryParserLog.hasErrors) ?
|
||||
loadingError.message : undefined;
|
||||
|
||||
return (
|
||||
<div className='dialog wide'>
|
||||
<div className='dialog-content scenery-loaded-dialog-content'>
|
||||
<div className='main-message'>
|
||||
{message}
|
||||
</div>
|
||||
{showLog && <SceneryParserLogView log={SceneryParserLog.getLog()} additionalErr={additionalErr} />}
|
||||
</div>
|
||||
<div className='dialog-buttons'>
|
||||
<button onClick={() => onClose()} autoFocus={true}>
|
||||
Ok
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default SceneryLoadedDialog;
|
||||
@ -0,0 +1,22 @@
|
||||
.scenery-parser-log-view {
|
||||
padding: 1em;
|
||||
border-radius: 8px;
|
||||
border: 2px solid #444;
|
||||
background-color: #0004;
|
||||
}
|
||||
|
||||
.scenery-parser-log-view ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-indent: -1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.scenery-parser-log-view .log-entry.warn {
|
||||
color: #aa4;
|
||||
}
|
||||
|
||||
.scenery-parser-log-view .log-entry.error {
|
||||
color: #f44;
|
||||
}
|
||||
27
src/components/scenery-loaded-dialog/SceneryParserLogView.js
Normal file
27
src/components/scenery-loaded-dialog/SceneryParserLogView.js
Normal file
@ -0,0 +1,27 @@
|
||||
import './SceneryParserLogView.css';
|
||||
|
||||
export default function SceneryParserLogView({ log, additionalErr }) {
|
||||
const extendedLog = additionalErr ? [...log, { logType: 'error', message: additionalErr }] : log;
|
||||
|
||||
return (
|
||||
<div className="scenery-parser-log-view">
|
||||
{extendedLog.length === 0 ? (
|
||||
<div className="no-log">No log entries.</div>
|
||||
) : (
|
||||
<ul className="log-list">
|
||||
{extendedLog.map((entry, index) => <LogEntry entry={entry} key={index} />)}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LogEntry({ entry }) {
|
||||
const { logType, message } = entry;
|
||||
|
||||
return (
|
||||
<li className={`log-entry ${logType}`}>
|
||||
{message}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
import { useContext } from "react";
|
||||
import MainContext from "../../contexts/MainContext";
|
||||
import Scenery from "../../model/scenery";
|
||||
import { showCustomDialog } from "../../services/dialogService";
|
||||
import SceneryLoadedDialog from "../scenery-loaded-dialog/SceneryLoadedDialog";
|
||||
import SceneryParserLog from "../../model/scenery-parser-log";
|
||||
|
||||
export default function FileSelect() {
|
||||
const {setScenery, setIsLoading} = useContext(MainContext);
|
||||
@ -9,17 +12,22 @@ export default function FileSelect() {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
SceneryParserLog.clear();
|
||||
setIsLoading(true);
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(file);
|
||||
reader.onload = (e) => {
|
||||
setIsLoading(false);
|
||||
if(!e.target || !e.target.result) {
|
||||
console.error("File reading failed or no content found.");
|
||||
let loadingError = null;
|
||||
try {
|
||||
const scenery = Scenery.fromText(e.target?.result);
|
||||
setScenery(scenery);
|
||||
} catch (error) {
|
||||
loadingError = error;
|
||||
setScenery(null);
|
||||
}
|
||||
|
||||
const scenery = Scenery.fromText(e.target.result);
|
||||
setScenery(scenery);
|
||||
setIsLoading(false);
|
||||
showCustomDialog(<SceneryLoadedDialog loadingError={loadingError} />);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -6,7 +6,8 @@ const Constants = {
|
||||
parser: {
|
||||
forceAutoSwitches: false,
|
||||
logNewAutoSwitches: true,
|
||||
sceneryInfoVersion: 29
|
||||
sceneryInfoVersion: 29,
|
||||
alwaysShowLogDialog: false
|
||||
},
|
||||
warnings: {
|
||||
all: false, // enable all warnings
|
||||
|
||||
@ -1,13 +1,32 @@
|
||||
import Constants from "../helpers/constants";
|
||||
|
||||
export default class SceneryParserLog {
|
||||
static log = [];
|
||||
static hasWarnings = false;
|
||||
static hasErrors = false;
|
||||
|
||||
static clear() {
|
||||
SceneryParserLog.log = [];
|
||||
SceneryParserLog.hasWarnings = false;
|
||||
SceneryParserLog.hasErrors = false;
|
||||
}
|
||||
|
||||
static warn(type, message) {
|
||||
if(!Constants.warnings[type] && !Constants.warnings.all) return;
|
||||
SceneryParserLog.hasWarnings = true;
|
||||
SceneryParserLog.log.push({logType: 'warn', type, message});
|
||||
|
||||
console.warn(`[SceneryParserLog] ${message}`);
|
||||
}
|
||||
|
||||
static error(type, message) {
|
||||
SceneryParserLog.hasErrors = true;
|
||||
SceneryParserLog.log.push({logType: 'error', type, message});
|
||||
|
||||
throw new Error(`[SceneryParserLog] ${message}`);
|
||||
}
|
||||
|
||||
static getLog() {
|
||||
return [...SceneryParserLog.log];
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ export default class Switch extends SceneryObject {
|
||||
let def = DefinedSwitches[this.bare_model] || null;
|
||||
|
||||
if(!def && !Constants.parser.forceAutoSwitches) {
|
||||
SceneryParserLog.warn('switchUndefinedModel', `Switch ${this.id} has undefined model "${this.bare_model}", trying to generate auto model definition`);
|
||||
SceneryParserLog.warn('switchUndefinedModel', `Switch ${this.id} has an undefined model "${this.bare_model}", trying to generate auto model definition`);
|
||||
}
|
||||
|
||||
if(!def || Constants.parser.forceAutoSwitches) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user