now allow files_sp paths to work (and support folders). Highlighting with folders is broken (likely dodgy ecnt). viewing still broken, but basic navigations is finally working with folders now
This commit is contained in:
79
files.py
79
files.py
@@ -179,6 +179,7 @@ class FileSchema(ma.SQLAlchemyAutoSchema):
|
|||||||
class DirSchema(ma.SQLAlchemyAutoSchema):
|
class DirSchema(ma.SQLAlchemyAutoSchema):
|
||||||
class Meta: model = Dir
|
class Meta: model = Dir
|
||||||
load_instance = True
|
load_instance = True
|
||||||
|
eid = ma.auto_field() # Explicitly include eid
|
||||||
in_path = ma.Nested(PathSchema)
|
in_path = ma.Nested(PathSchema)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -404,39 +405,70 @@ def process_ids():
|
|||||||
# return entries as json
|
# return entries as json
|
||||||
return jsonify(entries_schema.dump(entries))
|
return jsonify(entries_schema.dump(entries))
|
||||||
|
|
||||||
###
|
|
||||||
# query_data = { 'entry_lst': entry_lst, 'query_id': query_id, ... }
|
################################################################################
|
||||||
###
|
# /get_dir_entries -> show thumbnail view of files from import_path(s)
|
||||||
|
################################################################################
|
||||||
|
@app.route("/get_dir_entries", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def get_dir_entries():
|
||||||
|
data = request.get_json() # Parse JSON body
|
||||||
|
dir_id = data.get('dir_id', []) # Extract list of ids
|
||||||
|
back = data.get('back', False) # Extract back boolean
|
||||||
|
|
||||||
|
# if we are going back, find the parent id and use that instead
|
||||||
|
if back:
|
||||||
|
stmt=( select(EntryDirLink.dir_eid).filter(EntryDirLink.entry_id==dir_id) )
|
||||||
|
dir_id = db.session.execute(stmt).scalars().all() [0]
|
||||||
|
|
||||||
|
# get content of dir_id
|
||||||
|
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
||||||
|
# FIXME: what do we do with ordering anyway???
|
||||||
|
#stmt=stmt.order_by(*order_map.get(OPT.noo) )
|
||||||
|
ids=db.session.execute(stmt).scalars().all()
|
||||||
|
entries_schema = EntrySchema(many=True)
|
||||||
|
entries = Entry.query.filter(Entry.id.in_(ids)).all()
|
||||||
|
return jsonify(entries_schema.dump(entries))
|
||||||
|
|
||||||
|
################################################################################
|
||||||
# Call this ONCE on first menu choice of View files, or search box submission
|
# Call this ONCE on first menu choice of View files, or search box submission
|
||||||
|
# create the list of entry ids that matcht the required viewing/list
|
||||||
|
################################################################################
|
||||||
def GetQueryData( OPT ):
|
def GetQueryData( OPT ):
|
||||||
query_data = {}
|
query_data={}
|
||||||
query_data['query_id']=None
|
query_data['query_id']=None
|
||||||
query_data['entry_list']=None
|
query_data['entry_list']=None
|
||||||
|
|
||||||
# set up the sql order strings (back in OPT) based on value of noo
|
|
||||||
# FIXME: remove this for all last/first eid usage AND use order_map
|
|
||||||
SetOrderStrings( OPT )
|
|
||||||
|
|
||||||
if OPT.path_type == 'Search':
|
if OPT.path_type == 'Search':
|
||||||
print ("NOT YET")
|
print ("NOT YET")
|
||||||
return query_data
|
return query_data
|
||||||
|
|
||||||
|
# always get the top of the (OPT.prefix) Path's eid and keep it for OPT.folders toggling/use
|
||||||
|
dir_stmt=( select(Entry.id).join(Dir).join(PathDirLink).join(Path).filter(Dir.rel_path == '').filter(Path.path_prefix==OPT.prefix) )
|
||||||
|
# this should return the 1 Dir (that we want to see the content of) - and with only 1, no need to worry about order
|
||||||
|
dir_arr=db.session.execute(dir_stmt).scalars().all()
|
||||||
|
dir_id=dir_arr[0]
|
||||||
|
query_data['root_eid']=dir_id
|
||||||
|
|
||||||
if OPT.folders:
|
if OPT.folders:
|
||||||
entries, tmp_num_ents = GetEntriesInFolderView( OPT, prefix )
|
# start folder view with only the root folder
|
||||||
|
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
||||||
|
query_data['entry_list']=db.session.execute(stmt).scalars().all()
|
||||||
else:
|
else:
|
||||||
stmt = ( select(Entry.id).join(File).join(EntryDirLink).join(Dir).join(PathDirLink).
|
# get every File that is in the OPT.prefix Path
|
||||||
join(Path).filter(Path.path_prefix == OPT.prefix) )
|
stmt=( select(Entry.id).join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix == OPT.prefix) )
|
||||||
stmt = stmt.order_by(*order_map.get(OPT.noo) )
|
stmt=stmt.order_by(*order_map.get(OPT.noo) )
|
||||||
query_data['entry_list']= db.session.execute(stmt).scalars().all()
|
query_data['entry_list']= db.session.execute(stmt).scalars().all()
|
||||||
|
|
||||||
# first time we get the data q_offset is 0, current=first one, search never gets here, so search_term=''
|
# not sure I need this in hindsight - any value at all???
|
||||||
# FIXME: Doubt we need cwd -- I only need originals to either invalidate this list, or recreate it... need to think about that a lot more
|
# # first time we get the data q_offset is 0, current=first one, search never gets here, so search_term=''
|
||||||
query = Query( path_type=OPT.path_type, noo=OPT.noo, q_offset=0, folder=OPT.folders, grouping=OPT.grouping, root=OPT.root, cwd=OPT.cwd, search_term='',
|
# # FIXME: Doubt we need cwd -- I only need originals to either invalidate this list, or recreate it... need to think about that a lot more
|
||||||
entry_list=query_data['entry_list'], current=query_data['entry_list'][0], created=datetime.now(pytz.utc) )
|
# query = Query( path_type=OPT.path_type, noo=OPT.noo, q_offset=0, folder=OPT.folders, grouping=OPT.grouping, root=OPT.root, cwd=OPT.cwd, search_term='',
|
||||||
db.session.add(query)
|
# entry_list=query_data['entry_list'], current=query_data['entry_list'][0], created=datetime.now(pytz.utc) )
|
||||||
db.session.commit()
|
# db.session.add(query)
|
||||||
|
# db.session.commit()
|
||||||
query_data['query_id']=query.id
|
#
|
||||||
|
# query_data['query_id']=query.id
|
||||||
return query_data
|
return query_data
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -519,11 +551,10 @@ def files_ip():
|
|||||||
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
||||||
if request.method=='POST':
|
if request.method=='POST':
|
||||||
redirect("/files_ip")
|
redirect("/files_ip")
|
||||||
entries=GetEntries( OPT )
|
|
||||||
people = Person.query.all()
|
people = Person.query.all()
|
||||||
move_paths = MovePathDetails()
|
move_paths = MovePathDetails()
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", entry_data=entries, OPT=OPT, people=people, move_paths=move_paths, query_data=query_data )
|
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, people=people, move_paths=move_paths, query_data=query_data )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /files -> show thumbnail view of files from storage_path
|
# /files -> show thumbnail view of files from storage_path
|
||||||
@@ -535,10 +566,10 @@ def files_sp():
|
|||||||
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
||||||
if request.method=='POST':
|
if request.method=='POST':
|
||||||
redirect("/files_sp")
|
redirect("/files_sp")
|
||||||
entries=GetEntries( OPT )
|
|
||||||
people = Person.query.all()
|
people = Person.query.all()
|
||||||
move_paths = MovePathDetails()
|
move_paths = MovePathDetails()
|
||||||
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", entry_data=entries, OPT=OPT, people=people, move_paths=move_paths )
|
query_data = GetQueryData( OPT )
|
||||||
|
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, people=people, move_paths=move_paths, query_data=query_data )
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -351,6 +351,11 @@ function addFigure( obj, last, ecnt)
|
|||||||
last.printed = obj.file_details.month;
|
last.printed = obj.file_details.month;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
{% if not entry_data %}
|
||||||
|
<span class="alert alert-danger p-2 col-auto"> No matches for: '{{search_term}}'</span>
|
||||||
|
{% endif %}
|
||||||
|
*/
|
||||||
|
|
||||||
// Image/Video/Unknown entry
|
// Image/Video/Unknown entry
|
||||||
if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") {
|
if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") {
|
||||||
@@ -384,7 +389,7 @@ function addFigure( obj, last, ecnt)
|
|||||||
html += `
|
html += `
|
||||||
<figure class="col col-auto g-0 dir entry m-1" id="${obj.id}" ecnt="${ecnt}" dir="${dirname}" type="Directory">
|
<figure class="col col-auto g-0 dir entry m-1" id="${obj.id}" ecnt="${ecnt}" dir="${dirname}" type="Directory">
|
||||||
<svg class="svg" width="${OPT.size - 22}" height="${OPT.size - 22}" fill="currentColor">
|
<svg class="svg" width="${OPT.size - 22}" height="${OPT.size - 22}" fill="currentColor">
|
||||||
<use xlink:href="/static/icons.svg#Directory"></use>
|
<use xlink:href="/internal/icons.svg#Directory"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<figcaption class="svg_cap figure-caption text-center text-wrap text-break">${obj.name}</figcaption>
|
<figcaption class="svg_cap figure-caption text-center text-wrap text-break">${obj.name}</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
@@ -394,7 +399,6 @@ function addFigure( obj, last, ecnt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$('#figures').append( html )
|
$('#figures').append( html )
|
||||||
// console.log( html )
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,7 +409,7 @@ function renderMedia(obj) {
|
|||||||
const path = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}/${obj.name}`;
|
const path = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}/${obj.name}`;
|
||||||
const thumb = obj.file_details.thumbnail
|
const thumb = obj.file_details.thumbnail
|
||||||
? `<a href="${path}"><img alt="${obj.name}" class="thumb" height="${OPT.size}" src="data:image/jpeg;base64,${obj.file_details.thumbnail}"></a>`
|
? `<a href="${path}"><img alt="${obj.name}" class="thumb" height="${OPT.size}" src="data:image/jpeg;base64,${obj.file_details.thumbnail}"></a>`
|
||||||
: `<a href="${path}"><svg width="${OPT.size}" height="${OPT.size}" fill="white"><use xlink:href="/static/icons.svg#unknown_ftype"/></svg></a>`;
|
: `<a href="${path}"><svg width="${OPT.size}" height="${OPT.size}" fill="white"><use xlink:href="/internal/icons.svg#unknown_ftype"/></svg></a>`;
|
||||||
|
|
||||||
let mediaHtml = `<div style="position:relative; width:100%">${thumb}`;
|
let mediaHtml = `<div style="position:relative; width:100%">${thumb}`;
|
||||||
|
|
||||||
@@ -413,25 +417,25 @@ function renderMedia(obj) {
|
|||||||
if (OPT.search_term) {
|
if (OPT.search_term) {
|
||||||
mediaHtml += `
|
mediaHtml += `
|
||||||
<div style="position:absolute; bottom: 0px; left: 2px;">
|
<div style="position:absolute; bottom: 0px; left: 2px;">
|
||||||
<svg width="16" height="16" fill="white"><use xlink:href="/static/icons.svg#${getLocationIcon(obj)}"/></svg>
|
<svg width="16" height="16" fill="white"><use xlink:href="/internal/icons.svg#${getLocationIcon(obj)}"/></svg>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
mediaHtml += `
|
mediaHtml += `
|
||||||
<div id="s${obj.id}" style="display:none; position:absolute; top: 50%; left:50%; transform:translate(-50%, -50%);">
|
<div id="s${obj.id}" style="display:none; position:absolute; top: 50%; left:50%; transform:translate(-50%, -50%);">
|
||||||
<img height="64px" src="/static/throbber.gif">
|
<img height="64px" src="/internal/throbber.gif">
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else if (isVideo) {
|
} else if (isVideo) {
|
||||||
mediaHtml += `
|
mediaHtml += `
|
||||||
<div style="position:absolute; top: 0px; left: 2px;">
|
<div style="position:absolute; top: 0px; left: 2px;">
|
||||||
<svg width="16" height="16" fill="white"><use xlink:href="/static/icons.svg#film"/></svg>
|
<svg width="16" height="16" fill="white"><use xlink:href="/internal/icons.svg#film"/></svg>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
if (OPT.search_term) {
|
if (OPT.search_term) {
|
||||||
mediaHtml += `
|
mediaHtml += `
|
||||||
<div style="position:absolute; bottom: 0px; left: 2px;">
|
<div style="position:absolute; bottom: 0px; left: 2px;">
|
||||||
<svg width="16" height="16" fill="white"><use xlink:href="/static/icons.svg#${getLocationIcon(obj)}"/></svg>
|
<svg width="16" height="16" fill="white"><use xlink:href="/internal/icons.svg#${getLocationIcon(obj)}"/></svg>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -452,6 +456,31 @@ function getLocationIcon(obj) {
|
|||||||
return ICON[obj.in_dir.in_path.type.name]
|
return ICON[obj.in_dir.in_path.type.name]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST to get entry ids, and then getPage for a specified directory
|
||||||
|
function getDirEntries(dir_id, back)
|
||||||
|
{
|
||||||
|
data={}
|
||||||
|
data.dir_id=dir_id
|
||||||
|
data.back=back
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/get_dir_entries',
|
||||||
|
data: JSON.stringify(data), // Stringify the data
|
||||||
|
contentType: 'application/json', // Set content type
|
||||||
|
dataType: 'json', // Expect JSON response
|
||||||
|
success: function(res) {
|
||||||
|
document.entries=res
|
||||||
|
if( back )
|
||||||
|
document.back_id = res[0].in_dir.eid
|
||||||
|
drawPageOfFigures()
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error("Error:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// this function draws all the figures from document.entries - called when we
|
// this function draws all the figures from document.entries - called when we
|
||||||
// change pages, but also when we change say grouping/other OPTs
|
// change pages, but also when we change say grouping/other OPTs
|
||||||
function drawPageOfFigures()
|
function drawPageOfFigures()
|
||||||
@@ -459,11 +488,44 @@ function drawPageOfFigures()
|
|||||||
$('#figures').empty()
|
$('#figures').empty()
|
||||||
var last = { printed: null }
|
var last = { printed: null }
|
||||||
var ecnt=0
|
var ecnt=0
|
||||||
|
|
||||||
|
if( OPT.folders )
|
||||||
|
{
|
||||||
|
if( document.entries.length && document.entries[0].in_dir.rel_path == '' )
|
||||||
|
{
|
||||||
|
gray="_gray"
|
||||||
|
back=""
|
||||||
|
cl=""
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gray=""
|
||||||
|
back="Back"
|
||||||
|
cl="back"
|
||||||
|
}
|
||||||
|
// back button, if gray/back decide if we see grayed out folder and/or the name of the folder we go back to
|
||||||
|
html=`<div class="col col-auto g-0 m-1">
|
||||||
|
<figure id="${document.back_id}" class="${cl} entry m-1" type="Directory">
|
||||||
|
<svg class="svg" width="${OPT.size-22}" height="${OPT.size-22}">
|
||||||
|
<use xlink:href="internal/icons.svg#folder_back${gray}"/>
|
||||||
|
</svg>
|
||||||
|
<figcaption class="figure-caption text-center">${back}</figcaption>
|
||||||
|
</figure>
|
||||||
|
</div>`
|
||||||
|
/*
|
||||||
|
<script>f=$('#_back'); w=f.find('svg').width(); f.find('figcaption').width(w);</script>
|
||||||
|
*/
|
||||||
|
$('#figures').append(html)
|
||||||
|
}
|
||||||
for (const obj of document.entries) {
|
for (const obj of document.entries) {
|
||||||
addFigure( obj, last, ecnt )
|
addFigure( obj, last, ecnt )
|
||||||
ecnt++
|
ecnt++
|
||||||
}
|
}
|
||||||
$('.figure').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
$('.figure').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
||||||
|
$('.figure').dblclick( CallViewRouteWrapper )
|
||||||
|
// for dir, getDirEntries 2nd param is back (or "up" a dir)
|
||||||
|
$(".dir").click( function(e) { document.back_id=this.id; getDirEntries(this.id,false) } )
|
||||||
|
$(".back").click( function(e) { getDirEntries(this.id,true) } )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to get the 'page' of entry ids out of entryList
|
// Function to get the 'page' of entry ids out of entryList
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
var OPT={}
|
var OPT={}
|
||||||
OPT.grouping='{{OPT.grouping}}'
|
OPT.grouping='{{OPT.grouping}}'
|
||||||
OPT.cwd='{{OPT.cwd}}'
|
OPT.cwd='{{OPT.cwd}}'
|
||||||
|
OPT.root_eid={{query_data.root_eid}}
|
||||||
OPT.search_term='{{OPT.orig_search_term}}'
|
OPT.search_term='{{OPT.orig_search_term}}'
|
||||||
OPT.folders="{{OPT.folders}}" === "True"
|
OPT.folders="{{OPT.folders}}" === "True"
|
||||||
OPT.howMany={{OPT.how_many}}
|
OPT.howMany={{OPT.how_many}}
|
||||||
@@ -143,12 +144,7 @@
|
|||||||
</div class="form-row">
|
</div class="form-row">
|
||||||
{% set eids=namespace( str="" ) %}
|
{% set eids=namespace( str="" ) %}
|
||||||
{# gather all the file eids and collect them in case we go gallery mode #}
|
{# gather all the file eids and collect them in case we go gallery mode #}
|
||||||
{% for obj in entry_data %}
|
<input name="eids" id="eids" type="hidden" value="{{query_data.entry_list}}">
|
||||||
{% if obj.type.name != "Directory" %}
|
|
||||||
{% set eids.str = eids.str + obj.id|string +"," %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
<input name="eids" id="eids" type="hidden" value="{{eids.str}}">
|
|
||||||
</div>
|
</div>
|
||||||
{% set ecnt=namespace( val=0 ) %}
|
{% set ecnt=namespace( val=0 ) %}
|
||||||
<div id="figures" class="row ms-2">
|
<div id="figures" class="row ms-2">
|
||||||
@@ -320,8 +316,6 @@ function CallViewRoute(id)
|
|||||||
$(s).appendTo('body').submit();
|
$(s).appendTo('body').submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.figure').dblclick( CallViewRouteWrapper )
|
|
||||||
|
|
||||||
// different context menu on files
|
// different context menu on files
|
||||||
$.contextMenu({
|
$.contextMenu({
|
||||||
selector: '.entry',
|
selector: '.entry',
|
||||||
|
|||||||
Reference in New Issue
Block a user