clean up how we create toasts() [no longer try to reuse dom elements, just add new ones each time], support persistent notifications and close button or not [via separate booleans], created a clear message route and use that now in templates/base.html to clear FE messages. This will break for check dups as I am not setting persistence / close buttons correctly for those jobs, that is next. Converted move_files to new format
This commit is contained in:
34
TODO
34
TODO
@@ -1,32 +1,32 @@
|
||||
### GENERAL
|
||||
* get all status messages to use toasts AND get func to also increase/descrease the job counter as appropriate)
|
||||
- [DONE] all (success/creation) status messages use toasts
|
||||
-- any non-sucess still stays a top of the page as an alert (for now?)
|
||||
-- [DONE] make a helper func for setting toast body and use it in base.html && file_support.js
|
||||
-- [DONE] make a helper func for setting 'Active Jobs' text/badge and call it when document ready (rather/both than start of base.html)
|
||||
-- [DONE] trigger a timeout to play back pa_job_mgr message to FE and reset 'Active Jobs' text/badge until it hits 0
|
||||
-- [DONE] (re)start this code if any new jobs is created (on move only for now - in the long run all job creation should consider this POST/json model)
|
||||
-- [DONE] (re)start this code if any new jobs is created (on move ONLY FOR NOW
|
||||
-- [DONE] make js StatusMsg() take a 'data' (json response) and process that
|
||||
-- [DONE] make it include message from the API endpoint doing the work, not in the js code...
|
||||
-- [TODO] fix base.html to only call toast() and only in document.ready()
|
||||
-- [TODO] this means handling danger, and persistent / no time-out toast()s
|
||||
-- [DONE] this means handling danger, and persistent / no time-out toast()s
|
||||
-- [DONE] warning works now (colors, etc.)
|
||||
-- [TODO] have not thought about danger at all (the StatusMsg() code should work) - but missing Clear*() and persistence
|
||||
* [TODO] delete files should behave like /move_files (stay on same page, job start with toast(), etc.)
|
||||
* [TODO] ALL job creation should follow above pattern
|
||||
-- [DONE] clean up has to be a POST back to server to clear DB (jscript/async has no other way)
|
||||
-- [TODO] go through the crazy persistent status msgs for checkdups, etc. and make sure they all work
|
||||
|
||||
* should be using jsonify to return real json to my API calls, e.g:
|
||||
use make_response( jsonify (... ) )
|
||||
-- [TODO] all POSTs should follow new status behaviour (unless its a form POST, as that immediately renders the form in flask and will show the Status)
|
||||
all GETs stay as is for now (as they expect a html reply, not data, and then html is base.html+ and it handles the status)
|
||||
-- ONLY time this will fail is multiple status messages (which can occur I believe if a Wake of job mgr and then a job is created in DB, the success will only be shown)
|
||||
-- [TODO] simple fix will be to get 'hidden' jobs (wake job_mgr and maybe? metadata) to post failure events to the JobMgr_FE DB queue
|
||||
-- [TODO] when ALL converted, replace 'alert="..."' with 'status="..."'
|
||||
|
||||
* delete files should behave like /move_files (stay on same page) as well as the status messages above
|
||||
|
||||
* change the rotation code to use that jpeg util to reduce/remove compression loss?
|
||||
|
||||
* ignore face should ignore ALL matching faces (re: Declan)
|
||||
|
||||
* should be using jsonify to return real json to my API calls, e.g:
|
||||
response = make_response(
|
||||
jsonify(
|
||||
{"message": str(FLAMSG_ERR_SEC_ACCESS_DENIED), "severity": "danger"}
|
||||
),
|
||||
401,
|
||||
)
|
||||
response.headers["Content-Type"] = "application/json"
|
||||
return response
|
||||
|
||||
* should allow context menu from View thumbs (particularly useful on search) to show other files around this one by date (maybe that folder or something?)
|
||||
|
||||
* could get better AI optim, by keeping track of just new files since scan (even if we did this from the DB),
|
||||
@@ -39,6 +39,8 @@
|
||||
--> OR? https://jsmpeg.com/
|
||||
--> OR? convert all videos to mp4/webm
|
||||
|
||||
* consider whether FE_MSG should exist without a job #, and/or a sep. table, etc.
|
||||
|
||||
* delete folder
|
||||
|
||||
* allow joblog search (less needed with logs visible on a given file now)
|
||||
|
||||
5
files.py
5
files.py
@@ -590,7 +590,10 @@ def move_files():
|
||||
for el in request.form:
|
||||
jex.append( JobExtra( name=f"{el}", value=request.form[el] ) )
|
||||
job=NewJob( "move_files", 0, None, jex )
|
||||
return make_response( jsonify( job_id=job.id, status="success" ) )
|
||||
return make_response( jsonify(
|
||||
job_id=job.id,
|
||||
message=f"Created <a class='link-light' href=/job/{job.id}>Job #{job.id}</a> to move selected file(s)",
|
||||
status="success", alert="success" ) )
|
||||
|
||||
@login_required
|
||||
@app.route("/viewlist", methods=["POST"])
|
||||
|
||||
@@ -64,7 +64,7 @@ function MoveSubmit()
|
||||
// reorder the images via ecnt again, so highlighting can work
|
||||
document.mf_id=0; $('.figure').each( function() { $(this).attr('ecnt', document.mf_id ); document.mf_id++ } )
|
||||
$('#dbox').modal('hide')
|
||||
$.ajax({ type: 'POST', data: $('#mv_fm').serialize(), url: '/move_files', success: function(data){ st=Object; st.message="Created <a class='link-light' href=/job/" + data.job_id + ">Job #" + data.job_id + "</a> to move selected file(s)"; st.alert="success"; StatusMsg(st); CheckForJobs(); return false; } })
|
||||
$.ajax({ type: 'POST', data: $('#mv_fm').serialize(), url: '/move_files', success: function(data){ console.log(data); StatusMsg(data); CheckForJobs(); return false; } })
|
||||
}
|
||||
|
||||
// show the DBox for a move file, includes all thumbnails of selected files to move
|
||||
|
||||
@@ -1,65 +1,55 @@
|
||||
// create a bs toast in the status_container
|
||||
// can reuse any that are hidden, OR, create a new one by appending as needed (so we can have 2+ toasts on screen)
|
||||
function StatusMsg(st)
|
||||
// global
|
||||
var next_toast_id=1
|
||||
|
||||
function NewToast(data)
|
||||
{
|
||||
console.log( 'StatusMsg() -> ' + st.alert + ': ' + st.message )
|
||||
// look for any '.hide' and '.toast'
|
||||
if( $('.toast.hide').length !== 0 )
|
||||
{
|
||||
// as there may be more than 1 and as bs toast deals with ordering on screen, so just grab first()
|
||||
tid=$('.toast.hide').first().attr('id')
|
||||
// reset body, and the text-* and bg-* class for success, danger, etc.
|
||||
$('#'+tid ).find( '.toast-body').html(st.message)
|
||||
$('#'+tid ).removeClass( function( index, className ) { return (className.match( /(^|\s)(bg-|text-)\S+/g) || []).join(' ') } )
|
||||
$('#'+tid ).addClass( 'bg-' + st.alert )
|
||||
// get rid of white on button (if its there)
|
||||
$('#'+tid ).find( 'button' ).removeClass('btn-close-white')
|
||||
if( st.alert == "success" || st.alert == "danger" )
|
||||
{
|
||||
$('#'+tid ).addClass( 'text-white' )
|
||||
$('#'+tid ).find( 'button' ).addClass('btn-close-white')
|
||||
}
|
||||
// show the popup (by default it fades)
|
||||
$('#'+tid ).toast("show")
|
||||
}
|
||||
else
|
||||
{
|
||||
// find the id of the 'last' toast (either there are none, or they are all visible [note: we are in the else already])
|
||||
tmp=$('.toast').last().attr('id')
|
||||
// if none, there are no toasts at all, so make '#1'
|
||||
if( tmp== '' )
|
||||
tid=1
|
||||
else
|
||||
{
|
||||
// skip 'st' at front of DOM id, and then increment to get id for new one
|
||||
tid=tmp.substr(2)
|
||||
tid++
|
||||
}
|
||||
// make new div, include st.alert as background colour, and st.message as toast body
|
||||
div='<div id="st' + tid + '" class="toast hide align-items-center border-0'
|
||||
if( st.alert == "success" || st.alert == "danger" )
|
||||
// make new div, include data.alert as background colour, and data.message as toast body
|
||||
d_id='st' + String(next_toast_id)
|
||||
div='<div id="' + d_id + '"'
|
||||
if( data.persistent === true )
|
||||
div+=' data-bs-autohide="false"'
|
||||
div +=' class="toast hide align-items-center border-0'
|
||||
if( data.alert == "success" || data.alert == "danger" )
|
||||
div += ' text-white'
|
||||
div += ' bg-' + st.alert
|
||||
div += ' bg-' + data.alert
|
||||
div += `" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
`
|
||||
div += st.message
|
||||
div += data.message
|
||||
div += ' </div>'
|
||||
if( data.cant_close !== true )
|
||||
{
|
||||
div += ' <button type="button" class="btn-close me-2 m-auto'
|
||||
if( data.alert === "success" || data.alert === "danger" )
|
||||
div += ' btn-close-white'
|
||||
div += ' " data-bs-dismiss="toast" aria-label="Close"></button>'
|
||||
}
|
||||
div += `
|
||||
</div>
|
||||
<button type="button" class="btn-close me-2 m-auto
|
||||
`
|
||||
if( st.alert == "success" || st.alert == "danger" )
|
||||
div =+ ' btn-close-white'
|
||||
div += `
|
||||
" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
// can be appended straight after st1 as the .toast("show") deals with display ordering
|
||||
$('#st1').append(div)
|
||||
// show the popup (by default it fades)
|
||||
$('#st' + tid ).toast("show")
|
||||
// insert this as the first element in the status_container
|
||||
$('#status_container').prepend(div)
|
||||
|
||||
// make sure we have a new id for next toast
|
||||
next_toast_id++
|
||||
|
||||
return d_id
|
||||
}
|
||||
|
||||
// create a bs toast in the status_container
|
||||
// can reuse any that are hidden, OR, create a new one by appending as needed (so we can have 2+ toasts on screen)
|
||||
function StatusMsg(st)
|
||||
{
|
||||
el=NewToast(st)
|
||||
$('#' + el ).toast("show")
|
||||
// if there is a job_id, then clear the message for it or it will be picked up again on reload
|
||||
// BUT, we dont want to do this immediately, should hook on close, but for
|
||||
// now, we will do this to get a first pass working
|
||||
if( st.job_id !== undefined )
|
||||
{
|
||||
$.ajax( { type: 'POST', url: '/clearmsgforjob/'+st.job_id, success: function(data) { } } )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +85,7 @@ function CheckForJobs()
|
||||
SetActiveJobsBadge(data.num_active_jobs)
|
||||
if( data.num_active_jobs > 0 )
|
||||
{
|
||||
setTimeout( function() { CheckForJobCompletion() }, 1000 );
|
||||
setTimeout( function() { CheckForJobs() }, 1000 );
|
||||
}
|
||||
},
|
||||
} )
|
||||
|
||||
15
job.py
15
job.py
@@ -90,7 +90,6 @@ def GetJM_Message():
|
||||
# ClearJM_Message: used in html to clear any message just displayed
|
||||
################################################################################
|
||||
def ClearJM_Message(id):
|
||||
print("ClearJM_Message called")
|
||||
PA_JobManager_Message.query.filter(PA_JobManager_Message.id==id).delete()
|
||||
db.session.commit()
|
||||
return
|
||||
@@ -313,9 +312,21 @@ def CheckForJobs():
|
||||
for msg in PA_JobManager_Message.query.all():
|
||||
print("there is a PA_J_MGR status message" )
|
||||
u='<a class="link-light" href="' + url_for('joblog', id=msg.job_id) + '">Job # ' + str(msg.job_id) + '</a>: '
|
||||
sts.append( { 'message': u+msg.message, 'alert': msg.alert } )
|
||||
sts.append( { 'message': u+msg.message, 'alert': msg.alert, 'job_id': msg.job_id } )
|
||||
return make_response( jsonify( num_active_jobs=num, sts=sts ) )
|
||||
|
||||
###############################################################################
|
||||
# / -> POST -> looks for pa_job_manager status to F/E jobs and sends json of
|
||||
# them back to F/E (called form internal/js/jobs.js:CheckForJobs()
|
||||
################################################################################
|
||||
@app.route("/clearmsgforjob/<id>", methods=["POST"])
|
||||
@login_required
|
||||
def ClearMessageForJob(id):
|
||||
PA_JobManager_Message.query.filter(PA_JobManager_Message.job_id==id).delete()
|
||||
db.session.commit()
|
||||
# no real need for this response, as if it succeeded/failed the F/E ignores it
|
||||
return make_response( jsonify( status="success" ) )
|
||||
|
||||
###############################################################################
|
||||
# This func creates a new filter in jinja2 to format the time from the db in a
|
||||
# way that is more readable (converted to local tz too)
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
|
||||
{% if not InDBox %}
|
||||
{%block script_content %}{% endblock script_content %}
|
||||
<div id="status_container" class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
|
||||
<div id="status_container" class="position-fixed top-1 end-0 p-1" style="z-index: 11">
|
||||
<div id="st1" class="toast hide align-items-center text-white bg-success border-0" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">
|
||||
@@ -172,24 +172,16 @@
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
<!-- f/e messages are resident in memory of the page being rendered, just process now -->
|
||||
<!-- f/e messages are resident in memory of the page being rendered, just process now (stay this way so faster/dont need DB for some message) -->
|
||||
{% if GetMessage()|length %}
|
||||
msg = "{{ GetMessage()|safe }}"
|
||||
msg=msg.replace('href=', 'class=link-light href=')
|
||||
st=Object; st.message=msg; st.alert='{{GetAlert()}}'; StatusMsg(st)
|
||||
alert( '{{GetAlert()}}' )
|
||||
<!-- call ClearStatus: strictly not needed as we are near finished rendering, and any new page will lose it from memory (better to be explicit) -->
|
||||
{{ ClearStatus() }}
|
||||
{% endif %}
|
||||
CheckForJobs()
|
||||
/*
|
||||
<!-- this this is totally useless as can only live for this 1 page render anyway -->
|
||||
{{ ClearStatus() }}
|
||||
{% if GetJM_Message() != None and GetJM_Message().alert == "success" %}
|
||||
msg="{{GetJM_Message().message}}"
|
||||
msg=msg.replace('href=', 'class=link-light href=')
|
||||
st=Object; st.message=msg; st.alert="success"; StatusMsg(st)
|
||||
StatusMsg(st)
|
||||
{% set dont_print=ClearJM_Message(GetJM_Message().id) %}
|
||||
{% endif %}
|
||||
*/
|
||||
} )
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user