modify itemlist interactivity
This commit is contained in:
parent
b9285fe97e
commit
708b625fbe
46
src/app.py
46
src/app.py
@ -108,6 +108,44 @@ def deleteList():
|
||||
except:
|
||||
return str('item not found in list'), 400
|
||||
|
||||
@app.route('/app/change-list-name', methods=['POST'])
|
||||
def changeListName():
|
||||
data = request.get_json()
|
||||
name = data.get('name')
|
||||
uuid = data.get('uuid')
|
||||
try:
|
||||
change_list_name(uuid, name)
|
||||
return jsonify({'name changed': uuid}), 200
|
||||
except:
|
||||
return str('error changing name'), 400
|
||||
|
||||
@app.route('/app/change-list-description', methods=['POST'])
|
||||
def changeListDescription():
|
||||
data = request.get_json()
|
||||
description = data.get('description')
|
||||
uuid = data.get('uuid')
|
||||
try:
|
||||
change_list_description(uuid, description)
|
||||
return jsonify({'name changed': uuid}), 200
|
||||
except:
|
||||
return str('error changing description'), 400
|
||||
|
||||
@app.route('/app/change-list-content', methods=['POST'])
|
||||
def changeListContent():
|
||||
data = request.get_json()
|
||||
uuid = data.get('uuid')
|
||||
new = data.get('content')
|
||||
try:
|
||||
remove_all_from_list(uuid)
|
||||
if len(new)>0 :
|
||||
for item in new.split('#'):
|
||||
add_to_list(uuid, item)
|
||||
return jsonify({'content changed': uuid}), 200
|
||||
except:
|
||||
return str('error changing content'), 400
|
||||
|
||||
|
||||
|
||||
@app.route('/app/datahistory',methods = ['GET'])
|
||||
def data_history_request():
|
||||
if request.method == 'GET':
|
||||
@ -142,11 +180,17 @@ def data_history_request_filtered():
|
||||
lists_uuid = []
|
||||
return jsonify(get_history_filtered(lists_uuid))
|
||||
|
||||
@app.route('/app/datalist',methods = ['GET'])
|
||||
@app.route('/app/datalist',methods = ['GET', 'POST'])
|
||||
def data_list_request():
|
||||
if request.method == 'GET':
|
||||
print("fetching data item")
|
||||
return jsonify(get_lists())
|
||||
elif request.method == 'POST':
|
||||
data = request.get_json()
|
||||
list_uuid = data.get('uuid')
|
||||
details = get_list(list_uuid)
|
||||
return jsonify(details), 200
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug = True)
|
||||
|
53
src/db.py
53
src/db.py
@ -304,6 +304,19 @@ def remove_from_list(list_uuid, item_uuid):
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
def remove_all_from_list(list_uuid):
|
||||
'''remove every items from an itemlist'''
|
||||
connection = connect_db()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("""
|
||||
DELETE
|
||||
FROM listcontent
|
||||
WHERE list_uuid = %s
|
||||
""", (list_uuid,))
|
||||
cursor.close()
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
def get_lists():
|
||||
connection = connect_db()
|
||||
cursor = connection.cursor()
|
||||
@ -316,6 +329,46 @@ def get_lists():
|
||||
connection.close()
|
||||
return results
|
||||
|
||||
def get_list(list_uuid):
|
||||
'''return details of a single list'''
|
||||
connection = connect_db()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("""
|
||||
SELECT name, description
|
||||
FROM itemlist
|
||||
WHERE uuid = %s
|
||||
""", (list_uuid,))
|
||||
results = cursor.fetchall()
|
||||
cursor.close()
|
||||
connection.close()
|
||||
return results[0]
|
||||
|
||||
def change_list_name(uuid, name):
|
||||
'''modify itemlist name'''
|
||||
connection = connect_db()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("""
|
||||
UPDATE itemlist
|
||||
SET name = %s
|
||||
WHERE uuid = %s
|
||||
""", (name, uuid))
|
||||
cursor.close()
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
def change_list_description(uuid, description):
|
||||
'''modify itemlist description'''
|
||||
connection = connect_db()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("""
|
||||
UPDATE itemlist
|
||||
SET description = %s
|
||||
WHERE uuid = %s
|
||||
""", (description, uuid))
|
||||
cursor.close()
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
def export_csv():
|
||||
'''join item and history data from database and export it in ./output.csv'''
|
||||
connection = connect_db()
|
||||
|
13
web/app.html
13
web/app.html
@ -60,7 +60,7 @@
|
||||
<button id="create_list_add" type="button" class="btn btn-secondary">add</button>
|
||||
<button id="create_list_cancel" type="button" class="btn btn-secondary">cancel</button>
|
||||
<p>Include items</p>
|
||||
<div id="checkbox-container"></div>
|
||||
<div id="checkbox-container" class="item_checkboxes"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -69,14 +69,18 @@
|
||||
<div class="popup-content">
|
||||
<p>Modify list</p>
|
||||
<div class="dropdown btn-group mr-2" id="modifylist_dropdown">
|
||||
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown">
|
||||
<button id="modify_itemlist_dropdown" type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown">
|
||||
Itemlist
|
||||
</button>
|
||||
<ul id="modify_itemlist_choice" class="dropdown-menu">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modifylist_content">
|
||||
<div id="modifylist_content">
|
||||
</div>
|
||||
<div id="modifylist_buttons">
|
||||
<button id="modifylist_ok" type="button" class="btn btn-secondary">ok</button>
|
||||
<button id="modifylist_cancel" type="button" class="btn btn-secondary">cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -104,6 +108,7 @@
|
||||
|
||||
<!-- Load scripts-->
|
||||
<script src="{{ url_for('static', filename='fetch.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='filters_checkboxes.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='popups.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='rendergraphs.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='list.js') }}"></script>
|
||||
|
22
web/app.js
22
web/app.js
@ -52,28 +52,8 @@ function refresh_graphs() {
|
||||
render_graphs_wrapper();
|
||||
|
||||
// filters checkboxes
|
||||
function filters_checkboxes() {
|
||||
fetch_list().then(function(data){
|
||||
{
|
||||
const node = document.getElementById("filters_checkboxes");
|
||||
while (node.firstChild) {
|
||||
node.removeChild(node.lastChild);
|
||||
}
|
||||
}
|
||||
const node = d3.select("#filters_checkboxes");
|
||||
for (const itemlist of data) {
|
||||
var label = node.append("label");
|
||||
var input = label.append("input")
|
||||
.attr("type", "checkbox")
|
||||
.attr("class", "checkbox-filters")
|
||||
.attr("id", `checkbox-${itemlist.uuid}`);
|
||||
label.append("span")
|
||||
.text(`${itemlist.name}`);
|
||||
node.append("br");
|
||||
}
|
||||
})
|
||||
}
|
||||
filters_checkboxes()
|
||||
|
||||
// listen to filters changes
|
||||
var checkedBefore = getCheckedCheckboxIds('.checkbox-filters');
|
||||
$(document).ready(function(){
|
||||
|
37
web/fetch.js
37
web/fetch.js
@ -181,3 +181,40 @@ async function get_data_filtered(id_array) {
|
||||
history_data = await fetch_history_filtered(id_array);
|
||||
return Array(items_data, history_data);
|
||||
}
|
||||
|
||||
async function get_list_details(list_uuid) {
|
||||
try {
|
||||
// SELECT name, description
|
||||
const apiUrl = `${currentUrl}app/datalist`;
|
||||
const postData = {
|
||||
uuid: list_uuid
|
||||
};
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
};
|
||||
|
||||
const response = await fetch(apiUrl, requestOptions)
|
||||
.catch(error => {
|
||||
console.error('Error during POST request:', error);
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const rawData = await response.json();
|
||||
const listData = {
|
||||
name: rawData[0],
|
||||
description: rawData[1],
|
||||
};
|
||||
return listData;
|
||||
} else {
|
||||
throw new Error('Error in server response');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data item: ', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
22
web/filters_checkboxes.js
Normal file
22
web/filters_checkboxes.js
Normal file
@ -0,0 +1,22 @@
|
||||
function filters_checkboxes() {
|
||||
console.log("refresh filters");
|
||||
fetch_list().then(function(data){
|
||||
{
|
||||
const node = document.getElementById("filters_checkboxes");
|
||||
while (node.firstChild) {
|
||||
node.removeChild(node.lastChild);
|
||||
}
|
||||
}
|
||||
const node = d3.select("#filters_checkboxes");
|
||||
for (const itemlist of data) {
|
||||
var label = node.append("label");
|
||||
var input = label.append("input")
|
||||
.attr("type", "checkbox")
|
||||
.attr("class", "checkbox-filters")
|
||||
.attr("id", `checkbox-${itemlist.uuid}`);
|
||||
label.append("span")
|
||||
.text(`${itemlist.name}`);
|
||||
node.append("br");
|
||||
}
|
||||
})
|
||||
}
|
82
web/list.js
82
web/list.js
@ -23,3 +23,85 @@ async function delItemlist(uuid) {
|
||||
throw new Error('Error in server response');
|
||||
}
|
||||
}
|
||||
|
||||
async function changeListName(uuid, new_name) {
|
||||
const apiUrl = `${currentUrl}app/change-list-name`;
|
||||
const postData = {
|
||||
uuid: uuid,
|
||||
name: new_name,
|
||||
};
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
};
|
||||
|
||||
const response = await fetch(apiUrl, requestOptions)
|
||||
.catch(error => {
|
||||
console.error('Error during POST request:', error);
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(response);
|
||||
} else {
|
||||
throw new Error('Error in server response');
|
||||
}
|
||||
}
|
||||
|
||||
async function changeListDescription(uuid, new_description) {
|
||||
const apiUrl = `${currentUrl}app/change-list-description`;
|
||||
const postData = {
|
||||
uuid: uuid,
|
||||
description: new_description,
|
||||
};
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
};
|
||||
|
||||
const response = await fetch(apiUrl, requestOptions)
|
||||
.catch(error => {
|
||||
console.error('Error during POST request:', error);
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(response);
|
||||
} else {
|
||||
throw new Error('Error in server response');
|
||||
}
|
||||
}
|
||||
|
||||
async function changeListContent(uuid, new_content) {
|
||||
const apiUrl = `${currentUrl}app/change-list-content`;
|
||||
const content = new_content.join('#');
|
||||
const postData = {
|
||||
uuid: uuid,
|
||||
content: content,
|
||||
};
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(postData)
|
||||
};
|
||||
|
||||
const response = await fetch(apiUrl, requestOptions)
|
||||
.catch(error => {
|
||||
console.error('Error during POST request:', error);
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(response);
|
||||
} else {
|
||||
throw new Error('Error in server response');
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,6 @@ document.getElementById("create_list_cancel").addEventListener("click", function
|
||||
createListPopup.style.display = 'none';
|
||||
});
|
||||
|
||||
// modify list
|
||||
|
||||
// delete list
|
||||
document.getElementById("delete_list").addEventListener("click", function () {
|
||||
// remove div content
|
||||
@ -79,11 +77,11 @@ document.getElementById("delete_list").addEventListener("click", function () {
|
||||
deleteListPopup.style.display = 'flex';
|
||||
});
|
||||
// confirm delete list
|
||||
document.getElementById("delete_list_ok").addEventListener("click", function () {
|
||||
document.getElementById("delete_list_ok").addEventListener("click", async function () {
|
||||
const checked_delete = getCheckedCheckboxIds('.checkbox-delete-list');
|
||||
const id_array = checked_delete.map(str => str.substring(9));
|
||||
for (const uuid of id_array) {
|
||||
delItemlist(uuid);
|
||||
await delItemlist(uuid);
|
||||
}
|
||||
// refresh filters checkboxes
|
||||
filters_checkboxes();
|
||||
@ -95,11 +93,16 @@ document.getElementById("delete_list_cancel").addEventListener("click", function
|
||||
});
|
||||
|
||||
// modify list popup
|
||||
var previous_modify = Object();
|
||||
document.getElementById("modify_list").addEventListener("click", function () {
|
||||
generate_modifylist_buttons();
|
||||
//
|
||||
modifyListPopup.style.display = 'flex';
|
||||
});
|
||||
// cancel list modify
|
||||
document.getElementById("modifylist_cancel").addEventListener("click", function () {
|
||||
modifyListPopup.style.display = 'none';
|
||||
});
|
||||
function generate_modifylist_buttons() {
|
||||
// remove div content
|
||||
const node = document.getElementById("modify_itemlist_choice");
|
||||
@ -125,24 +128,36 @@ function generate_modifylist_buttons() {
|
||||
});
|
||||
}
|
||||
async function toggle_modify(itemlist_uuid) {
|
||||
// <div id="modifylist_content">
|
||||
// <input id="listName" type="text" placeholder="name">
|
||||
// <input id="listDescription" type="text" placeholder="description">
|
||||
// <button id="create_list_add" type="button" class="btn btn-secondary">add</button>
|
||||
// <button id="create_list_cancel" type="button" class="btn btn-secondary">cancel</button>
|
||||
// <p>Include items</p>
|
||||
// <div id="checkbox-container"></div>
|
||||
// remove div content
|
||||
const node = document.getElementById("modifylist_content");
|
||||
while (node.firstChild) {
|
||||
node.removeChild(node.lastChild);
|
||||
}
|
||||
// input name
|
||||
// input description
|
||||
// content
|
||||
// new content
|
||||
previous_modify.uuid = itemlist_uuid;
|
||||
const existing_content = Object.keys(await fetch_item_filtered([itemlist_uuid]));
|
||||
previous_modify.content = existing_content;
|
||||
const list_data = await get_list_details(itemlist_uuid);
|
||||
const modify_content = d3.select("#modifylist_content");
|
||||
const checkboxContainer = modify_content.append("div");
|
||||
// dropdown menu text
|
||||
document.getElementById("modify_itemlist_dropdown").innerHTML = `${list_data.name}`;
|
||||
// input name
|
||||
previous_modify.name = list_data.name;
|
||||
const input_name = modify_content.append("input")
|
||||
.attr("type", "text")
|
||||
.attr("placeholder", "name")
|
||||
.attr("value", `${list_data.name}`)
|
||||
.attr("id", `input_name-${itemlist_uuid}`);
|
||||
// input description
|
||||
const input_description = modify_content.append("input")
|
||||
.attr("type", "text")
|
||||
.attr("placeholder", "description")
|
||||
.attr("value", `${list_data.description}`)
|
||||
.attr("id", `input_description-${itemlist_uuid}`);
|
||||
previous_modify.description = list_data.description;
|
||||
// content
|
||||
const checkboxContainer = modify_content.append("div")
|
||||
.attr("class", "item_checkboxes");
|
||||
fetch_item().then(function(data){
|
||||
Object.keys(data).forEach(uuid => {
|
||||
const item = data[uuid];
|
||||
@ -150,7 +165,7 @@ async function toggle_modify(itemlist_uuid) {
|
||||
|
||||
const checkbox = div.append("input")
|
||||
.attr("type", "checkbox")
|
||||
.attr("class", "checkbox-itemlist")
|
||||
.attr("class", "checkbox-modify-itemlist")
|
||||
.attr("id", `checkbox-${uuid}`);
|
||||
if (existing_content.includes(`${uuid}`)) {
|
||||
checkbox.property("checked", true);
|
||||
@ -167,6 +182,35 @@ async function toggle_modify(itemlist_uuid) {
|
||||
});
|
||||
});
|
||||
}
|
||||
// confirm list modify
|
||||
document.getElementById("modifylist_ok").addEventListener("click", async function () {
|
||||
const uuid = previous_modify.uuid;
|
||||
const new_name = document.getElementById(`input_name-${uuid}`).value;
|
||||
const new_description = document.getElementById(`input_description-${uuid}`).value;
|
||||
const checked = getCheckedCheckboxIds('.checkbox-modify-itemlist');
|
||||
const new_content = checked.map(str => str.substring(9));
|
||||
var diff = false;
|
||||
if (new_name != previous_modify.name) {
|
||||
// name different
|
||||
diff = true;
|
||||
await changeListName(uuid, new_name);
|
||||
}
|
||||
if (new_description != previous_modify.description) {
|
||||
// description different
|
||||
diff = true;
|
||||
await changeListDescription(uuid, new_description);
|
||||
}
|
||||
if (!(new_content.every(item => previous_modify.content.includes(item)) && previous_modify.content.every(item => new_content.includes(item)))) {
|
||||
// content different
|
||||
diff = true;
|
||||
await changeListContent(uuid, new_content);
|
||||
}
|
||||
if (diff) {
|
||||
// refresh filters checkboxes
|
||||
filters_checkboxes();
|
||||
}
|
||||
modifyListPopup.style.display = 'none';
|
||||
});
|
||||
|
||||
// delete item, pop-up confirm
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
@ -42,14 +42,14 @@ body {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#checkbox-container {
|
||||
.item_checkboxes {
|
||||
max-height: 50%;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#checkbox-container div {
|
||||
.item_checkboxes div {
|
||||
margin-bottom: 10px;
|
||||
width: calc(50% - 10px);
|
||||
display: flex;
|
||||
|
Loading…
x
Reference in New Issue
Block a user