Skip to content

Commit 0fae807

Browse files
committed
Added: UI all approval page (#62)
1 parent 113bad2 commit 0fae807

File tree

3 files changed

+98
-27
lines changed

3 files changed

+98
-27
lines changed

libreforms_fastapi/app/__init__.py

+35-6
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def make_immutable_map(nested_dict):
170170
for k, v in nested_dict.items()
171171
})
172172

173-
# @parameterized_lru_cache(maxsize=128)
173+
@parameterized_lru_cache(maxsize=128)
174174
def cache_form_stage_data(
175175
form_name: str,
176176
form_stages: Map,
@@ -196,7 +196,7 @@ def cache_form_stage_data(
196196
return stage_dict
197197

198198
# @parameterized_lru_cache(maxsize=128)
199-
# @lru_cache() # Opt for a standard cache because we probably need to rebuild this entire cache when there are changes
199+
@lru_cache() # Opt for a standard cache because we probably need to rebuild this entire cache when there are changes
200200
def cache_form_stage_data_for_specified_user(
201201
form_name: str,
202202
form_stages: Map,
@@ -1371,10 +1371,15 @@ async def api_form_read_all_needing_action(
13711371
mailer = Depends(get_mailer),
13721372
doc_db = Depends(get_doc_db),
13731373
session: SessionLocal = Depends(get_db),
1374-
key: str = Depends(X_API_KEY)
1374+
key: str = Depends(X_API_KEY),
1375+
return_full_records_flat: bool = False,
1376+
return_count_only: bool = False,
1377+
13751378
):
13761379
"""
1377-
This method returns a dict of all the documents needing action from the current user.
1380+
This method returns a dict of all the documents needing action from the current user. Pass the
1381+
`return_full_records_flat` option to get all the records in full, and to flatten these into a
1382+
list of documents. Pass the `return_count_only` option to return an int count of actions needed.
13781383
"""
13791384

13801385
# Ugh, I'd like to find a more efficient way to get the user data. But alas, that
@@ -1404,7 +1409,7 @@ async def api_form_read_all_needing_action(
14041409
# Create a recursive Map of the form_stages
14051410
__mapped_form_stages = make_immutable_map(__form_model.form_stages)
14061411

1407-
print ('\n\n\n', __mapped_form_stages)
1412+
# print ('\n\n\n', __mapped_form_stages)
14081413

14091414
__documents = cache_form_stage_data_for_specified_user(
14101415
form_name=form_name,
@@ -1416,6 +1421,30 @@ async def api_form_read_all_needing_action(
14161421
dict_of_return_values[form_name] = __documents
14171422

14181423

1424+
if return_count_only:
1425+
1426+
__record_count = sum(len(records) for records in dict_of_return_values.values())
1427+
1428+
return {"record_count": __record_count}
1429+
1430+
if return_full_records_flat:
1431+
1432+
__temp = []
1433+
seen_records = set()
1434+
1435+
for __form_name, __records in dict_of_return_values.items():
1436+
for __record_id in __records:
1437+
if __record_id not in seen_records:
1438+
__record = doc_db.get_one_document(
1439+
form_name=__form_name,
1440+
document_id=__record_id,
1441+
)
1442+
__temp.append(__record)
1443+
seen_records.add(__record_id)
1444+
1445+
return {"documents": __temp}
1446+
1447+
14191448
# Write this query to the TransactionLog
14201449
if config.COLLECT_USAGE_STATISTICS:
14211450

@@ -1431,7 +1460,7 @@ async def api_form_read_all_needing_action(
14311460
)
14321461

14331462

1434-
return dict_of_return_values
1463+
return {"documents": dict_of_return_values}
14351464

14361465

14371466
# Read one form

libreforms_fastapi/app/templates/base.html.jinja

+42-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,17 @@
8181
</div>
8282
</li>
8383
{% endif %}
84-
<li><a class="dropdown-item" href="{{ url_for('ui_form_review_and_approval') }}">Review & Approval</a></li>
84+
<li>
85+
<a class="dropdown-item" href="{{ url_for('ui_form_review_and_approval') }}">
86+
<div class="d-flex justify-content-between align-items-center">
87+
<span>Review & Approval</span>
88+
<span id="actionBadgeContainer" style="margin-left: 5px;"></span>
89+
</div>
90+
</a>
91+
</li>
92+
93+
94+
8595
</ul>
8696
</div>
8797

@@ -426,6 +436,36 @@
426436
427437
{% if request.user.is_authenticated %}
428438
439+
440+
$.ajax({
441+
url: '/api/form/read_all_needing_action?return_count_only=true',
442+
type: 'GET',
443+
dataType: 'json',
444+
beforeSend: function(xhr) {
445+
xhr.setRequestHeader('X-API-KEY', "{{ request.user.api_key }}");
446+
},
447+
success: function(response) {
448+
449+
// console.log('AJAX response:', response); // Debugging: log the entire response
450+
451+
// Assuming response.record_count contains the number of actions needed
452+
if (response.record_count && response.record_count > 0) {
453+
// Create the badge
454+
var badge = `<span class="badge bg-primary">${response.record_count}</span>`;
455+
456+
// Insert the badge into the container
457+
$('#actionBadgeContainer').html(badge);
458+
} else {
459+
// Clear the badge if record_count is 0 or undefined
460+
$('#actionBadgeContainer').empty();
461+
}
462+
},
463+
error: function(xhr, status, error) {
464+
console.error('Error:', status, error);
465+
}
466+
});
467+
468+
429469
if (localStorage.getItem('jwt_token')) {
430470
$.ajax({
431471
url: '/api/auth/refresh',
@@ -444,6 +484,7 @@
444484
445485
446486
});
487+
447488
} else {
448489
console.log("No JWT token found in localStorage.");
449490
}

libreforms_fastapi/app/templates/review_and_approval.html.jinja

+21-20
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
There are no submissions that require your review or approval at this time.
1515
</p>
1616

17-
{#
17+
1818
<div class="container table-responsive">
1919
<div class="spinner-border spinner-border-sm loading-circle" role="status"></div>
2020
<table id="readAllTable" class="table table-hover table-striped table-light" style="display: none;">
@@ -33,15 +33,15 @@
3333
</tbody>
3434
</table>
3535
</div>
36-
#}
36+
3737

3838
{% endblock %}
3939

4040
{% block scripts %}
4141
<script src="{{url_for('static', path='js/datatables.js')}}"></script>
4242
<script>
4343
44-
/*
44+
4545
$(document).ready(function () {
4646
4747
const spinner = document.querySelector('.loading-circle');
@@ -58,16 +58,25 @@ $(document).ready(function () {
5858
}
5959
return str;
6060
}
61+
62+
function formatObject(obj) {
63+
return Object.entries(obj)
64+
.map(([key, value]) => `<strong>${key}</strong>: ${value}`)
65+
.join(', ');
66+
}
67+
68+
6169
// Wrap the AJAX call in a function that returns a Promise
62-
function fetchData(formName) {
70+
function fetchData() {
6371
return new Promise((resolve, reject) => {
6472
$.ajax({
65-
url: `/api/form/read_all/${formName}?return_when_empty=true`,
73+
url: `/api/form/read_all_needing_action?return_full_records_flat=true`,
6674
type: "GET",
6775
dataType: 'json',
6876
beforeSend: function(xhr){xhr.setRequestHeader('X-API-KEY', apiKey);},
6977
success: function(formData) {
7078
resolve(formData.documents);
79+
console.log(formData.documents);
7180
},
7281
error: function(xhr, status, error) {
7382
reject(error);
@@ -76,19 +85,11 @@ $(document).ready(function () {
7685
});
7786
}
7887
79-
// Create an array of promises
80-
let promises = formNames.map(formName => fetchData(formName));
81-
82-
// Use Promise.allSettled to process data after all AJAX calls are complete
83-
Promise.allSettled(promises).then(results => {
84-
results.forEach(result => {
85-
if (result.status === 'fulfilled') {
86-
allFormData = allFormData.concat(result.value);
87-
}
88-
// else {
89-
// console.error("Failed to fetch data for form:", result.reason);
90-
// }
91-
});
88+
89+
90+
// Use .then() to process data after the AJAX call is complete
91+
fetchData().then(formData => {
92+
allFormData = allFormData.concat(formData);
9293
9394
console.log(allFormData);
9495
@@ -97,7 +98,8 @@ $(document).ready(function () {
9798
let row = `<tr>
9899
<td><a href="/ui/form/read_one/${form['metadata']['form_name']}/${form['metadata']['document_id']}">${form['metadata']['document_id']}</a></td>
99100
<td>${form['metadata']['form_name'].replace(/_/g, ' ')}</td>
100-
<td>${GFG(JSON.stringify(form['data']), 60)}</td>
101+
{# <td>${GFG(JSON.stringify(form['data']), 60)}</td> #}
102+
<td>${formatObject(form['data'])}</td>
101103
<td>
102104
<a target="_blank" href="/ui/auth/p/${form['metadata']['last_editor']}" class="badge bg-primary text-decoration-none" style=" {%if not config['OTHER_PROFILES_ENABLED'] and not request.user.site_admin%} pointer-events: none;{%endif%}" aria-label="Link to ${form['metadata']['last_editor']}">
103105
${form['metadata']['last_editor']}
@@ -140,7 +142,6 @@ $(document).ready(function () {
140142
});
141143
});
142144
143-
*/
144145
</script>
145146

146147
{% endblock %}

0 commit comments

Comments
 (0)