Skip to content

Commit 102f701

Browse files
author
SM_SAYEED
committed
upload form correction
1 parent 2f77f1f commit 102f701

File tree

2 files changed

+72
-36
lines changed

2 files changed

+72
-36
lines changed

app.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,42 @@ def property_detail(property_name, tab):
11991199
)
12001200
##############################################################################################################################################################
12011201

1202+
# NEW: JSON endpoint to save one row without full-page reload
1203+
@app.route('/materials/<property_name>/<tab>/edit', methods=['POST'])
1204+
def materials_edit_row(property_name, tab):
1205+
if not session.get('admin'):
1206+
return jsonify({"ok": False, "error": "not_authorized"}), 403
1207+
if tab not in ('dataset', 'results'):
1208+
return jsonify({"ok": False, "error": "bad_tab"}), 400
1209+
1210+
row_filename = (request.form.get('row_filename') or '').strip()
1211+
if not row_filename:
1212+
return jsonify({"ok": False, "error": "missing_filename"}), 400
1213+
1214+
new_desc = (request.form.get('row_description') or '').strip()
1215+
1216+
try:
1217+
with sqlite3.connect(DB_NAME) as conn:
1218+
c = conn.cursor()
1219+
if tab == 'dataset':
1220+
new_source = (request.form.get('row_source') or '').strip()
1221+
c.execute("""
1222+
UPDATE uploads_log
1223+
SET source = ?, description = ?
1224+
WHERE property=? AND tab=? AND filename=? AND storage='drive'
1225+
""", (new_source, new_desc, property_name, tab, row_filename))
1226+
else:
1227+
c.execute("""
1228+
UPDATE uploads_log
1229+
SET description = ?
1230+
WHERE property=? AND tab=? AND filename=? AND storage='drive'
1231+
""", (new_desc, property_name, tab, row_filename))
1232+
conn.commit()
1233+
return jsonify({"ok": True, "message": f"Saved: {row_filename}"})
1234+
except Exception as e:
1235+
return jsonify({"ok": False, "error": str(e)}), 500
1236+
##############################################################################################################################################################
1237+
12021238
@app.route('/uploads/<path:filename>')
12031239
def uploaded_file(filename):
12041240
full_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)

templates/property_detail.html

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,18 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
6868

6969
<!-- Link a FOLDER (import all allowed files) -->
7070
<form method="post" class="stack" style="margin-bottom:1em;">
71-
<div class="small">Or link a Drive FOLDER (we’ll import all allowed files, including subfolders).</div>
71+
<div class="small">Or link a Drive FOLDER (we’ll import all allowed files, incl. subfolders).</div>
7272
<div>
7373
<input type="text" name="drive_folder_link" placeholder="Drive FOLDER link or folder ID" style="width:560px" required>
7474
<button type="submit" name="link_folder" value="1">Link Folder</button>
7575
</div>
7676
</form>
7777

78-
<!-- Upload a ZIP and push to Drive (currently optional) -->
78+
<!-- Upload a ZIP and push to Drive -->
7979
<form method="post" enctype="multipart/form-data" class="stack">
8080
<div class="small">Or upload a .zip; allowed files inside will be uploaded to Drive automatically.</div>
8181
<div>
82-
<input type="file" name="zipfile" accept=".zip">
82+
<input type="file" name="zipfile" accept=".zip" required>
8383
<button type="submit" name="zip_upload" value="1">Upload ZIP to Drive</button>
8484
</div>
8585
</form>
@@ -108,16 +108,16 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
108108
{% set uploaded_at = (row.uploaded_at if row.uploaded_at is defined else row['uploaded_at']) %}
109109
{% set preview_url = (row.preview_url if row.preview_url is defined else row['preview_url']) %}
110110
{% set download_url = (row.download_url if row.download_url is defined else row['download_url']) %}
111+
{% set form_id = 'f_' ~ loop.index %}
111112

112113
<tr>
113114
<td>{{ filename }}</td>
114115

115116
{% if tab == 'dataset' %}
116117
<td>
117118
{% if admin %}
118-
<form method="post" class="row-edit" style="display:inline;">
119-
<input type="hidden" name="row_filename" value="{{ filename }}">
120-
<input type="text" name="row_source" value="{{ source or '' }}" size="18">
119+
<!-- This input belongs to the row form via the HTML5 'form' attribute -->
120+
<input type="text" name="row_source" form="{{ form_id }}" value="{{ source or '' }}" size="18">
121121
{% else %}
122122
{{ source or '' }}
123123
{% endif %}
@@ -126,17 +126,15 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
126126

127127
<td>
128128
{% if admin %}
129-
{% if tab == 'dataset' %}
129+
<!-- One form per row; keeps page from reloading via JS -->
130+
<form id="{{ form_id }}" class="row-edit-form"
131+
action="{{ url_for('materials_edit_row', property_name=property_name, tab=tab) }}"
132+
method="post" style="display:inline;">
133+
<input type="hidden" name="row_filename" value="{{ filename }}">
130134
<input type="text" name="row_description" value="{{ description or '' }}" size="22">
131135
<button type="submit" name="edit_row" value="1" style="margin-left:6px;">Save</button>
132-
</form>
133-
{% else %}
134-
<form method="post" class="row-edit" style="display:inline;">
135-
<input type="hidden" name="row_filename" value="{{ filename }}">
136-
<input type="text" name="row_description" value="{{ description or '' }}" size="22">
137-
<button type="submit" name="edit_row" value="1" style="margin-left:6px;">Save</button>
138-
</form>
139-
{% endif %}
136+
<span class="save-result" style="margin-left:.5em;font-size:.9em;"></span>
137+
</form>
140138
{% else %}
141139
{{ description or '' }}
142140
{% endif %}
@@ -150,20 +148,20 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
150148

151149
<td>
152150
{% if (storage or 'local') == 'drive' %}
153-
{% if preview_url %}<a href="{{ preview_url }}" target="_blank" rel="noopener">View</a>{% endif %}
154-
{% if download_url %} | <a href="{{ download_url }}" target="_blank" rel="noopener">Download</a>{% endif %}
151+
{% if preview_url %}<a href="{{ preview_url }}" target="_blank">View</a>{% endif %}
152+
{% if download_url %} | <a href="{{ download_url }}" target="_blank">Download</a>{% endif %}
155153
{% else %}
156154
{% if tab == 'dataset' and (filename.endswith('.csv') or filename.endswith('.npy')) %}
157155
{% set tname = table_map.get(filename) %}
158156
{% if tname %}
159-
<a href="{{ url_for('public_view', table=tname) }}" target="_blank" rel="noopener">View</a>
157+
<a href="{{ url_for('public_view', table=tname) }}" target="_blank">View</a>
160158
{% else %}
161159
<span class="small">No table yet</span>
162160
{% endif %}
163161
{% elif tab == 'results' %}
164-
<a href="{{ url_for('view_result_file', property_name=property_name, tab=tab, filename=filename) }}" target="_blank" rel="noopener">View</a>
162+
<a href="{{ url_for('view_result_file', property_name=property_name, tab=tab, filename=filename) }}" target="_blank">View</a>
165163
{% endif %}
166-
| <a href="{{ url_for('uploaded_file', filename=property_name ~ '/' ~ tab ~ '/' ~ filename) }}" download>Download</a>
164+
| <a href="{{ url_for('uploaded_file', filename=property_name ~ '/' ~ tab ~ '/' ~ filename) }}" download>Download</a>
167165
{% endif %}
168166

169167
{% if admin %}
@@ -190,33 +188,35 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
190188

191189
{% if admin %}
192190
<script>
193-
// Intercept per-row Save to avoid page reload (preserves other unsaved edits)
194-
document.querySelectorAll('form.row-edit').forEach(function(form) {
191+
document.addEventListener('DOMContentLoaded', function () {
192+
document.querySelectorAll('.row-edit-form').forEach(function (form) {
195193
form.addEventListener('submit', async function (e) {
196194
e.preventDefault();
197-
const fd = new FormData(form);
198-
// Ensure the intent flag is present
199-
if (!fd.has('edit_row')) fd.append('edit_row', '1');
200-
const btn = form.querySelector('button[type="submit"]');
201-
const old = btn.textContent;
202-
btn.disabled = true;
203-
195+
const btn = form.querySelector('button[type=submit]');
196+
const result = form.querySelector('.save-result');
197+
if (btn) { btn.disabled = true; btn.textContent = 'Saving…'; }
204198
try {
205-
const resp = await fetch(location.href, {
199+
const fd = new FormData(form);
200+
const resp = await fetch(form.action, {
206201
method: 'POST',
207202
body: fd,
208203
headers: { 'X-Requested-With': 'XMLHttpRequest' }
209204
});
210-
let data = {};
211-
try { data = await resp.json(); } catch { /* ignore */ }
212-
btn.textContent = data.ok ? 'Saved ✓' : 'Saved';
205+
const data = await resp.json();
206+
if (data.ok) {
207+
if (result) result.textContent = 'Saved ✓';
208+
} else {
209+
if (result) result.textContent = 'Error: ' + (data.error || 'failed');
210+
}
213211
} catch (err) {
214-
btn.textContent = 'Error';
212+
if (result) result.textContent = 'Error: ' + err;
213+
} finally {
214+
if (btn) { btn.disabled = false; btn.textContent = 'Save'; }
215+
setTimeout(() => { if (result) result.textContent = ''; }, 2500);
215216
}
216-
217-
setTimeout(() => { btn.disabled = false; btn.textContent = old; }, 1200);
218217
});
219218
});
219+
});
220220
</script>
221221
{% endif %}
222222
</body>

0 commit comments

Comments
 (0)