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 { useContext } from "react";
|
||||||
import MainContext from "../../contexts/MainContext";
|
import MainContext from "../../contexts/MainContext";
|
||||||
import Scenery from "../../model/scenery";
|
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() {
|
export default function FileSelect() {
|
||||||
const {setScenery, setIsLoading} = useContext(MainContext);
|
const {setScenery, setIsLoading} = useContext(MainContext);
|
||||||
@ -9,17 +12,22 @@ export default function FileSelect() {
|
|||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
|
SceneryParserLog.clear();
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
setIsLoading(false);
|
let loadingError = null;
|
||||||
if(!e.target || !e.target.result) {
|
try {
|
||||||
console.error("File reading failed or no content found.");
|
const scenery = Scenery.fromText(e.target?.result);
|
||||||
}
|
setScenery(scenery);
|
||||||
|
} catch (error) {
|
||||||
|
loadingError = error;
|
||||||
|
setScenery(null);
|
||||||
|
}
|
||||||
|
|
||||||
const scenery = Scenery.fromText(e.target.result);
|
setIsLoading(false);
|
||||||
setScenery(scenery);
|
showCustomDialog(<SceneryLoadedDialog loadingError={loadingError} />);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,8 @@ const Constants = {
|
|||||||
parser: {
|
parser: {
|
||||||
forceAutoSwitches: false,
|
forceAutoSwitches: false,
|
||||||
logNewAutoSwitches: true,
|
logNewAutoSwitches: true,
|
||||||
sceneryInfoVersion: 29
|
sceneryInfoVersion: 29,
|
||||||
|
alwaysShowLogDialog: false
|
||||||
},
|
},
|
||||||
warnings: {
|
warnings: {
|
||||||
all: false, // enable all warnings
|
all: false, // enable all warnings
|
||||||
|
|||||||
@ -1,13 +1,32 @@
|
|||||||
import Constants from "../helpers/constants";
|
import Constants from "../helpers/constants";
|
||||||
|
|
||||||
export default class SceneryParserLog {
|
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) {
|
static warn(type, message) {
|
||||||
if(!Constants.warnings[type] && !Constants.warnings.all) return;
|
if(!Constants.warnings[type] && !Constants.warnings.all) return;
|
||||||
|
SceneryParserLog.hasWarnings = true;
|
||||||
|
SceneryParserLog.log.push({logType: 'warn', type, message});
|
||||||
|
|
||||||
console.warn(`[SceneryParserLog] ${message}`);
|
console.warn(`[SceneryParserLog] ${message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static error(type, message) {
|
static error(type, message) {
|
||||||
|
SceneryParserLog.hasErrors = true;
|
||||||
|
SceneryParserLog.log.push({logType: 'error', type, message});
|
||||||
|
|
||||||
throw new Error(`[SceneryParserLog] ${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;
|
let def = DefinedSwitches[this.bare_model] || null;
|
||||||
|
|
||||||
if(!def && !Constants.parser.forceAutoSwitches) {
|
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) {
|
if(!def || Constants.parser.forceAutoSwitches) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user