revamp whole EA flow. Server created EAs when we do certain jobs (transform, delete_files, restore_files), then instead of faking amendments in the jscript, get job creation to return EA from job ORM, then check is now generic for end of any amendment job, and when it finishes, use that to clear our amendments in document, and redraw through normal UI code. No smarts in client, all driven by state from server, and if we reload a page mid jobs, it has required state, and because an amendment job is still progressing, it runs check code again
This commit is contained in:
@@ -151,6 +151,37 @@ function MoveDBox(path_details)
|
||||
$("#suffix").keypress(function (e) { if (e.which == 13) { $("#move_submit").click(); return false; } } )
|
||||
}
|
||||
|
||||
// This function is called anytime we have a job that returns amendments
|
||||
// (visually we want to show this entry is being amended by a job)
|
||||
// as we check for a job to end every second, we can call this multiple times
|
||||
// during the runtime of a job, so only redraw/react to a new amendment
|
||||
// NOTE: we update all views, as we might go into one via jscript before the job ends
|
||||
function processAmendments( ams )
|
||||
{
|
||||
for (const am of ams)
|
||||
{
|
||||
// if we return anything here, we already have this amendment, so continue to next
|
||||
if( document.amendments.filter(obj => obj.eid === am.eid).length > 0 )
|
||||
continue
|
||||
|
||||
document.amendments.push(am)
|
||||
|
||||
if( document.viewing && document.viewing.id == am.eid )
|
||||
{
|
||||
im.src=im.src + '?t=' + new Date().getTime();
|
||||
DrawImg()
|
||||
}
|
||||
|
||||
// find where in the page this image is being viewed
|
||||
idx = pageList.indexOf(am.eid)
|
||||
// createFigureHtml uses matching document.amendments to show thobber, etc
|
||||
html = createFigureHtml( document.entries[idx] )
|
||||
$('#'+am.eid).replaceWith( html )
|
||||
}
|
||||
}
|
||||
|
||||
// function to add data for document.amendment based on id and amt
|
||||
// used when we transform several images in files_*, or single image in viewer
|
||||
// show the DBox for a delete/restore file, includes all thumbnails of selected files
|
||||
// with appropriate coloured button to Delete or Restore files`
|
||||
function DelDBox(del_or_undel)
|
||||
@@ -159,28 +190,36 @@ function DelDBox(del_or_undel)
|
||||
$('#dbox-title').html(del_or_undel+' Selected File(s)')
|
||||
div ='<div class="row col-12"><p class="col">' + del_or_undel + ' the following files?</p></div>'
|
||||
div+=GetSelnAsDiv()
|
||||
if( del_or_undel == "Delete" )
|
||||
{
|
||||
which="delete"
|
||||
col="danger"
|
||||
}
|
||||
else
|
||||
{
|
||||
which="restore"
|
||||
col="sucess"
|
||||
}
|
||||
|
||||
document.ents_to_del=[]
|
||||
$('.highlight').each(function( cnt ) { document.ents_to_del[cnt]=parseInt($(this).attr('id')) } )
|
||||
div+=`<div class="row col-12 mt-3">
|
||||
<button onClick="$('#dbox').modal('hide')" class="btn btn-outline-secondary col-2">Cancel</button>
|
||||
`
|
||||
div+=`
|
||||
<button onClick="MoveOrDelCleanUpUI(); $.ajax({ type: 'POST', data: to_del, url:
|
||||
`
|
||||
if( del_or_undel == "Delete" )
|
||||
div+=`
|
||||
'/delete_files',
|
||||
success: function(data){
|
||||
if( $(location).attr('pathname').match('search') !== null || document.viewing ) { window.location='/' }; CheckForJobs() } }); return false" class="btn btn-outline-danger col-2">Ok</button>
|
||||
</div>
|
||||
`
|
||||
else
|
||||
// just force page reload to / for now if restoring files from a search path -- a search (by name)
|
||||
// would match the deleted/restored file, so it would be complex to clean up the UI (and can't reload, as DB won't be changed yet)
|
||||
div+=`
|
||||
'/restore_files',
|
||||
success: function(data){
|
||||
if( $(location).attr('pathname').match('search') !== null || document.viewing ) { window.location='/' }; CheckForJobs() } }); return false" class="btn btn-outline-success col-2">Ok</button>
|
||||
</div>
|
||||
`
|
||||
<button onClick="
|
||||
$.ajax({ type: 'POST', data: to_del, url: '/${which}_files',
|
||||
success: function(data) {
|
||||
// FIXME: what is the ! search stuff for???
|
||||
// FIXME: really, also why not show 'delete' throbber, and on success of actual delete go back to /
|
||||
if( $(location).attr('pathname').match('search') !== null || document.viewing ) { window.location='/' }
|
||||
|
||||
processAmendments( data.job.amendments )
|
||||
checkForAmendmentJobToComplete(data.job.id)
|
||||
}
|
||||
});
|
||||
$('#dbox').modal('hide')
|
||||
return false"
|
||||
class="btn btn-outline-${col} col-2">Ok</button>
|
||||
</div>`
|
||||
$('#dbox-content').html(div)
|
||||
$('#dbox').modal('show')
|
||||
}
|
||||
@@ -378,37 +417,37 @@ function createFigureHtml( obj )
|
||||
|
||||
// Image/Video/Unknown entry
|
||||
if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") {
|
||||
const pathType = obj.in_dir.in_path.type.name;
|
||||
const size = obj.file_details.size_mb;
|
||||
const hash = obj.file_details.hash;
|
||||
const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`;
|
||||
const fname = obj.name;
|
||||
const yr = obj.file_details.year;
|
||||
const date = `${yr}${String(obj.file_details.month).padStart(2, '0')}${String(obj.file_details.day).padStart(2, '0')}`;
|
||||
const prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`;
|
||||
const type = obj.type.name;
|
||||
const pathType = obj.in_dir.in_path.type.name;
|
||||
const size = obj.file_details.size_mb;
|
||||
const hash = obj.file_details.hash;
|
||||
const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`;
|
||||
const fname = obj.name;
|
||||
const yr = obj.file_details.year;
|
||||
const date = `${yr}${String(obj.file_details.month).padStart(2, '0')}${String(obj.file_details.day).padStart(2, '0')}`;
|
||||
const prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`;
|
||||
const type = obj.type.name;
|
||||
|
||||
// if amendment for this obj, do not add entry class - prevents highlighting
|
||||
if( am ) {
|
||||
ent=""
|
||||
gs="style='filter: grayscale(100%);'"
|
||||
am_html ='<img class="position-absolute top-50 start-50 translate-middle" height="60" src="/internal/white-circle.png">'
|
||||
am_html +='<img class="position-absolute top-50 start-50 translate-middle" height="64" src="/internal/throbber.gif">'
|
||||
if( am.type.which == 'icon' )
|
||||
am_html+=`<svg class="position-absolute top-50 start-50 translate-middle" height="32" style="color:${am.type.colour}" fill="${am.type.colour}"><use xlink:href="/internal/icons.svg#${am.type.what}"></use></svg>`
|
||||
else
|
||||
am_html+=`<img class="position-absolute top-50 start-50 translate-middle" src="/internal/${am.type.what}?v={{js_vers['r270']}}" height="32">`
|
||||
} else {
|
||||
ent="entry"
|
||||
gs=""
|
||||
am_html=""
|
||||
}
|
||||
html += `
|
||||
<figure id="${obj.id}" class="col col-auto g-0 figure ${ent} m-1"
|
||||
path_type="${pathType}" size="${size}" hash="${hash}" in_dir="${inDir}"
|
||||
fname="${fname}" yr="${yr}" date="${date}" pretty_date="${prettyDate}" type="${type}">
|
||||
${renderMedia(obj,gs,am_html)}
|
||||
</figure>`;
|
||||
// if amendment for this obj, do not add entry class - prevents highlighting
|
||||
if( am ) {
|
||||
ent=""
|
||||
gs="style='filter: grayscale(100%);'"
|
||||
am_html ='<img class="position-absolute top-50 start-50 translate-middle" height="60" src="/internal/white-circle.png">'
|
||||
am_html+='<img class="position-absolute top-50 start-50 translate-middle" height="64" src="/internal/throbber.gif">'
|
||||
if( am.type.which == 'icon' )
|
||||
am_html+=`<svg class="position-absolute top-50 start-50 translate-middle" height="32" style="color:${am.type.colour}" fill="${am.type.colour}"><use xlink:href="/internal/icons.svg#${am.type.what}"></use></svg>`
|
||||
else
|
||||
am_html+=`<img class="position-absolute top-50 start-50 translate-middle" src="/internal/${am.type.what}?v={{js_vers['r270']}}" height="32">`
|
||||
} else {
|
||||
ent="entry"
|
||||
gs=""
|
||||
am_html=""
|
||||
}
|
||||
html += `
|
||||
<figure id="${obj.id}" class="col col-auto g-0 figure ${ent} m-1"
|
||||
path_type="${pathType}" size="${size}" hash="${hash}" in_dir="${inDir}"
|
||||
fname="${fname}" yr="${yr}" date="${date}" pretty_date="${prettyDate}" type="${type}">
|
||||
${renderMedia(obj,gs,am_html)}
|
||||
`
|
||||
}
|
||||
// Directory entry
|
||||
else if (obj.type.name === "Directory" && OPT.folders) {
|
||||
@@ -422,7 +461,6 @@ function createFigureHtml( obj )
|
||||
<use xlink:href="/internal/icons.svg#Directory"></use>
|
||||
</svg>
|
||||
<figcaption class="svg_cap figure-caption text-center text-wrap text-break">${obj.name}</figcaption>
|
||||
</figure>
|
||||
`;
|
||||
html += `<script>f=$('#${obj.id}'); w=f.find('svg').width(); f.find('figcaption').width(w);</script>`;
|
||||
}
|
||||
@@ -434,7 +472,8 @@ function createFigureHtml( obj )
|
||||
$('#${obj.id}').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
||||
$('#${obj.id}').dblclick( function(e) { startViewing( $(this).attr('id') ) } )
|
||||
}
|
||||
</script>`
|
||||
</script>
|
||||
</figure>`
|
||||
return html
|
||||
}
|
||||
|
||||
@@ -621,6 +660,7 @@ function getEntriesByIdSuccessHandler(res,pageNumber,successCallback,viewingIdx)
|
||||
document.entries=res;
|
||||
// cache this
|
||||
document.page[pageNumber]=res
|
||||
// FIXME: I want to remove successCallback, instead: if viewing, or files_*, or file_list, then call relevant draw routine
|
||||
successCallback(res,viewingIdx)
|
||||
resetNextPrevButtons()
|
||||
// if search, disable folders
|
||||
@@ -663,11 +703,11 @@ function getPage(pageNumber, successCallback, viewingIdx=0)
|
||||
data: JSON.stringify(data), contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
document.amendments=res.amend;
|
||||
// this is only called when we are viewing a page in files/list view, so check for job(s) ending...
|
||||
for (const tmp of document.amendments) {
|
||||
CheckTransformJob(tmp.eid,tmp.job_id,handleTransformFiles)
|
||||
}
|
||||
document.amendments=res.amendments;
|
||||
// only called when an amendment is pending & we are viewing a page in files/list view
|
||||
// so check for amendment job(s) ending...
|
||||
for (const tmp of document.amendments)
|
||||
checkForAmendmentJobToComplete(tmp.job_id)
|
||||
getEntriesByIdSuccessHandler( res.entries, pageNumber, successCallback, viewingIdx )
|
||||
},
|
||||
error: function(xhr, status, error) { console.error("Error:", error); } });
|
||||
@@ -811,6 +851,64 @@ function changeSize()
|
||||
$('.svg_cap').width(sz);
|
||||
}
|
||||
|
||||
// when a delete or restore files job has completed successfullly, then get ids
|
||||
// find the page we are on, remove amendments & ids from entryList and re-get page
|
||||
// which will reset pageList and the UI of images for that page
|
||||
function handleDeleteOrRestoreFileJobCompleted(job)
|
||||
{
|
||||
// this grabs the values from the object attributes of eid-0, eid-1, etc.
|
||||
const ids = job.extra.map(item => item.value)
|
||||
|
||||
// find page number of first element to delete (this is the page we will return too)
|
||||
pnum=getPageNumberForId( ids[0] )
|
||||
|
||||
// remove amendment data
|
||||
for (const ent of ids)
|
||||
{
|
||||
id=parseInt(ent)
|
||||
removeAmendment( id )
|
||||
// remove the item in the entryList
|
||||
index=entryList.indexOf(id);
|
||||
if( index != -1 )
|
||||
entryList.splice(index, 1); // Remove the element
|
||||
else
|
||||
{
|
||||
return; // have to get out of here, or calling getPage() below will loop forever
|
||||
}
|
||||
}
|
||||
|
||||
// re-create pageList by reloading the page
|
||||
getPage(pnum,getPageFigures)
|
||||
}
|
||||
|
||||
// POST to a check URL, that will tell us if the amendment job has completed,
|
||||
// it also calls CheckForJobs() which will fix up the Active Jobs badge,
|
||||
function checkForAmendmentJobToComplete(job_id)
|
||||
{
|
||||
CheckForJobs()
|
||||
$.ajax( { type: 'POST', data: '&job_id='+job_id, url: '/check_amend_job_status',
|
||||
success: function(res) { handleCheckAmendmentJobStatus(res); } } )
|
||||
}
|
||||
|
||||
// the status of a Amendment Job has been returned, finished is True/False
|
||||
// if not finished try again in 1 second... If finished then invalidate page
|
||||
// cache and based on job type call code correct func to update the UI appropriately
|
||||
function handleCheckAmendmentJobStatus(data)
|
||||
{
|
||||
if( data.finished )
|
||||
{
|
||||
// invalidate the cache
|
||||
document.page.length=0
|
||||
|
||||
// transforms contain the single transformed entry data for convenience
|
||||
if( data.job.name == 'transform_image' )
|
||||
handleTransformImageJobCompleted(data.job, data.entry)
|
||||
else if ( data.job.name == 'delete_files' || data.job.name == 'restore_files' )
|
||||
handleDeleteOrRestoreFileJobCompleted(data.job)
|
||||
}
|
||||
else { setTimeout( function() { checkForAmendmentJobToComplete(data.job.id) }, 1000 ); }
|
||||
}
|
||||
|
||||
// different context menu on files
|
||||
$.contextMenu({
|
||||
selector: '.entry',
|
||||
|
||||
Reference in New Issue
Block a user