Skip to content

Commit

Permalink
better status handling for importer, upload on importer page
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas committed Apr 26, 2024
1 parent fd6bd69 commit 794950c
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 95 deletions.
9 changes: 5 additions & 4 deletions server/avnav_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,15 +582,16 @@ def setConfigChanger(self, changer):
self.configChanger=changer
def getStatusProperties(self):
return {}
def getInfo(self):
def getInfo(self,children=None):
try:
st=self.status.copy()
rta=[]
for k,v in st.items():
try:
elem=v.toDict()
if elem is not None:
rta.append(elem)
if children is None or k in children:
elem=v.toDict()
if elem is not None:
rta.append(elem)
except Exception as e:
pass
return {'name':self.getStatusName(),'items':rta}
Expand Down
64 changes: 48 additions & 16 deletions server/handler/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,25 +213,34 @@ def getState(self):
if self._isConverted():
return self.State.DONE
return self.State.ERROR
def setInfo(self,setter):
key=self.getInfoKey()
st=self.getState()
def getWstate(self,st=None):
if st is None:
st=self.getState()
if st == self.State.CONVERTING:
setter.setInfo(key,"converting %d files"%self.score,WorkerStatus.NMEA)
return
return WorkerStatus.NMEA
if st == self.State.DONENC:
setter.setInfo(key,"no converter yet but converted at %s"%self.result.dateStr(),WorkerStatus.INACTIVE)
return
return WorkerStatus.INACTIVE
if st == self.State.NOCONV:
setter.setInfo(key,"no converter",WorkerStatus.ERROR)
return
return WorkerStatus.ERROR
if st == self.State.SETTLE:
setter.setInfo(key,"changed, waiting to settle (%d files)"%self.score,WorkerStatus.RUNNING)
return
return WorkerStatus.RUNNING
if st == self.State.DONE:
setter.setInfo(key,"already converted at %s"%self.result.dateStr(),WorkerStatus.INACTIVE)
return
setter.setInfo(key,"conversion failed at %s: %s"%(self.result.dateStr(),str(self.result.error)),WorkerStatus.ERROR)
return WorkerStatus.INACTIVE
return WorkerStatus.ERROR
def getStateInfo(self,st=None):
if st is None:
st=self.getState()
if st == self.State.CONVERTING:
return "converting %d files"%self.score
if st == self.State.DONENC:
return "no converter yet but converted at %s"%self.result.dateStr()
if st == self.State.NOCONV:
return "no converter"
if st == self.State.SETTLE:
return "changed, waiting to settle (%d files)"%self.score
if st == self.State.DONE:
return "already converted at %s"%self.result.dateStr()
return "conversion failed at %s: %s"%(self.result.dateStr(),str(self.result.error))

class Conversion:
def __init__(self,process,candidate:ConversionCandidate):
Expand Down Expand Up @@ -354,7 +363,7 @@ def _syncInfo(self,candidates):
keys=set()
for c in candidates: # type: ConversionCandidate
keys.add(c.getInfoKey())
c.setInfo(self)
self.setInfo(c.getInfoKey(),c.getStateInfo(),c.getState())
def check(k,v):
if not k.startswith(ConversionCandidate.KPRFX):
return True
Expand Down Expand Up @@ -639,10 +648,33 @@ def findCandidate(self,key,isName=False):

def handleApiRequest(self, type, subtype, requestparam, **kwargs):
if type == "list":
status=self.getInfo()
status=self.getInfo(['main','converter'])
items=[]
if status is not None and status.get('items') is not None:
items=status['items']
candidates=self.candidates
for can in candidates: # type: ConversionCandidate
canDownload=False
st=can.getState()
if st == ConversionCandidate.State.DONE or st == ConversionCandidate.State.DONENC:
if can.converter is not None:
downloadFile=can.converter.getOutFileOrDir(can.name)
if downloadFile is not None and os.path.exists(downloadFile):
canDownload=True
hasLog=self.getLogFileName(can.name,True) is not None
path,ext=os.path.splitext(can.filename)
basename=os.path.basename(path)+ext
canst={
'name':ConversionCandidate.KPRFX+can.name,
'istate':can.getState(),
'status':can.getWstate(),
'info':can.getStateInfo(),
'fullname':can.filename,
'basename':basename,
'running':can.running,
'canDownload': canDownload,
'hasLog': hasLog}
items.append(canst)
return AVNUtil.getReturnData(items=items)
if type == "delete":
name=AVNUtil.getHttpRequestParam(requestparam,'name',True)
Expand Down
90 changes: 90 additions & 0 deletions viewer/components/ImportDialog.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
*###############################################################################
# Copyright (c) 2012-2024 Andreas Vogel [email protected]
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERtime
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
###############################################################################
*/
import React from 'react';
import PropTypes from 'prop-types';
import {Checkbox, Input, InputReadOnly} from "./Inputs";
import DB from "./DialogButton";
class ImportDialog extends React.Component{
constructor(props){
super(props);
this.state={
subdir:props.subdir,
useSubdir:props.subdir?true:false
};
}
render(){
return (
<React.Fragment>
<div className="importDialog flexInner">
<h3 className="dialogTitle">Upload Chart to Importer</h3>
<InputReadOnly
dialogRow={true}
label="name"
value={this.props.name}
/>
{this.props.allowSubDir && <Checkbox
dialogRow={true}
label="use set name"
value={this.state.useSubdir}
onChange={(nv)=>this.setState({useSubdir:nv})}
/>}
{this.props.allowSubDir && this.state.useSubdir?<Input
dialogRow={true}
label="set name"
value={this.state.subdir}
onChange={(nv)=>{this.setState({subdir:nv})}}
/>
:
null}

<div className="dialogButtons">
<DB name="cancel"
onClick={()=>{
this.props.cancelFunction();
this.props.closeCallback();
}}
>Cancel</DB>
<DB name="ok"
onClick={()=>{
this.props.okFunction(this.props,this.state.useSubdir?this.state.subdir:undefined);
this.props.closeCallback();
}}
disabled={this.state.useSubdir && !this.state.subdir}
>OK</DB>
</div>
</div>
</React.Fragment>
);
}
}
ImportDialog.propTypes={
okFunction: PropTypes.func.isRequired,
cancelFunction: PropTypes.func.isRequired,
subdir: PropTypes.string,
name: PropTypes.string.isRequired,
allowSubDir: PropTypes.bool
}

export default ImportDialog;
23 changes: 14 additions & 9 deletions viewer/components/UploadHandler.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ class UploadHandler extends React.Component{
this.checkName(file.name)
.then((res)=>{
if (!this.props.local){
this.uploadServer(file,res.name,res.type||this.props.type,res.uploadParameters)
this.uploadServer(file,res.name,res.type||this.props.type,res.uploadParameters,res)
}
else{
this.uploadFileReader(file,res.name)
this.uploadFileReader(file,res.name,res)
}
})
.catch((err)=>{
this.props.errorCallback(err);
});
}

uploadFileReader(file, name) {
uploadFileReader(file, name,param) {
this.stateHelper.setState({}, true);
if (file.size) {
if (file.size > MAXUPLOADSIZE) {
Expand All @@ -100,13 +100,13 @@ class UploadHandler extends React.Component{
this.props.errorCallback("unable to load file " + file.name);
return;
}
this.props.doneCallback({data: content, name: name});
this.props.doneCallback({data: content, name: name,param:param});


};
reader.readAsText(file);
}
uploadServer(file, name,type, opt_options) {
uploadServer(file, name,type, opt_options,opt_param) {
let self=this;
let url = globalStore.getData(keys.properties.navUrl)
+ "?request=upload&type=" + type
Expand Down Expand Up @@ -150,7 +150,9 @@ class UploadHandler extends React.Component{
if (self.props.uploadSequence !== currentSequence) return;
self.stateHelper.setState({}, true);
if (self.props.doneCallback) {
self.props.doneCallback();
self.props.doneCallback({
param:opt_param
});
}
}
});
Expand Down Expand Up @@ -198,7 +200,8 @@ class UploadHandler extends React.Component{
.then((res) => {
this.props.doneCallback({
name: res.name,
data: data
data: data,
param: res
})
})
.catch((err) => {
Expand Down Expand Up @@ -228,7 +231,8 @@ class UploadHandler extends React.Component{
},
total: avnav.android.getFileSize(id),
loaded: 0,
loadedPercent: true
loadedPercent: true,
param: res
};
this.stateHelper.setState(copyInfo, true);
if (avnav.android.copyFile(id,res.name)) {
Expand All @@ -254,8 +258,9 @@ class UploadHandler extends React.Component{
}
else{
//done, error already reported from java side
let param=this.stateHelper.getValue('param')
this.stateHelper.setState({},true);
this.props.doneCallback();
this.props.doneCallback({param:param});
}
}

Expand Down
64 changes: 9 additions & 55 deletions viewer/gui/DownloadPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import EditOverlaysDialog, {DEFAULT_OVERLAY_CHARTENTRY} from '../components/Edit
import {getOverlayConfigName} from "../map/chartsourcebase"
import PropertyHandler from '../util/propertyhandler';
import {SaveItemDialog} from "../components/LoadSaveDialogs";
import ImportDialog from "../components/ImportDialog";

const RouteHandler=NavHandler.getRoutingHandler();

Expand Down Expand Up @@ -146,59 +147,6 @@ const DownloadItem=(props)=>{



class ImportDialog extends React.Component{
constructor(props){
super(props);
this.state={
subdir:props.subdir,
useSubdir:props.subdir?true:false
};
}
render(){
return (
<React.Fragment>
<div className="importDialog flexInner">
<h3 className="dialogTitle">Upload Chart to Importer</h3>
<InputReadOnly
dialogRow={true}
label="name"
value={this.props.name}
/>
<Checkbox
dialogRow={true}
label="use set name"
value={this.state.useSubdir}
onChange={(nv)=>this.setState({useSubdir:nv})}
/>
{this.state.useSubdir?<Input
dialogRow={true}
label="set name"
value={this.state.subdir}
onChange={(nv)=>{this.setState({subdir:nv})}}
/>
:
null}

<div className="dialogButtons">
<DB name="cancel"
onClick={()=>{
this.props.cancelFunction();
this.props.closeCallback();
}}
>Cancel</DB>
<DB name="ok"
onClick={()=>{
this.props.okFunction(this.props,this.state.useSubdir?this.state.subdir:undefined);
this.props.closeCallback();
}}
disabled={this.state.useSubdir && !this.state.subdir}
>OK</DB>
</div>
</div>
</React.Fragment>
);
}
}



Expand Down Expand Up @@ -474,11 +422,12 @@ class DownloadPage extends React.Component{
if (subdir !== this.state.importSubDir){
this.setState({importSubDir: subdir});
}
resolve({name:name,type:'import',uploadParameters:{subdir:subdir}});
resolve({name:name,type:'import',uploadParameters:{subdir:subdir},showImportPage:true});
}}
cancelFunction={()=>reject("canceled")}
name={name}
subdir={this.state.importSubDir}
allowSubDir={ext !== 'zip'}
/>
);
});
Expand Down Expand Up @@ -589,7 +538,12 @@ class DownloadPage extends React.Component{
<UploadHandler
local={localDoneFunction !== undefined}
type={this.state.type}
doneCallback={localDoneFunction?localDoneFunction:this.fillData}
doneCallback={(param)=>{
if (param.param && param.param.showImportPage){
this.props.history.push('importerpage');
}
localDoneFunction?localDoneFunction():this.fillData()
}}
errorCallback={(err)=>{if (err) Toast(err);this.fillData();}}
uploadSequence={this.state.uploadSequence}
checkNameCallback={this.checkNameForUpload}
Expand Down
Loading

0 comments on commit 794950c

Please sign in to comment.