Merge branch 'master' of git.elab.kth.se:davide/ELAB-partsearch

pull/3/head
Davide Bongiovanni 6 years ago
commit b3aad9a1ca

@ -54,7 +54,7 @@ def serveImage(img):
img_io.seek(0) img_io.seek(0)
return send_file(img_io, mimetype='image/png') return send_file(img_io, mimetype='image/png')
@app.route('/parts') @app.route('/parts', strict_slashes=False)
def index(): def index():
return render_template('partsearch.html', containers=getContainers()) return render_template('partsearch.html', containers=getContainers())
@ -80,7 +80,7 @@ def get_locationURL(locationID):
@app.route('/parts/locationEditor') @app.route('/parts/locationEditor')
def locationEditor(): def locationEditor():
query = 'select c.name as container, l.name as name, l.id from locations as l inner join containers as c on l.container_id = c.id order by container, name;' query = 'select c.name as container, l.name as name, l.id, c.id as container_id from locations as l inner join containers as c on l.container_id = c.id order by container, name;'
r = db_engine.execute(text(query)) r = db_engine.execute(text(query))
locations = [] locations = []
for row in r: for row in r:
@ -95,19 +95,19 @@ def alterLocation(locationID):
s = '' s = ''
if locationID < 0: if locationID < 0:
# New entry # New entry
s = 'insert into locations (name, map) ' s = 'insert into locations (name, container_id) '
s += 'values (:name, :map);' s += 'values (:name, :container);'
s = text(s) s = text(s)
r = db_engine.execute(s,name=request.form['name'],map=request.form['map']); r = db_engine.execute(s,name=request.form['name'],container=request.form['container']);
r.close() r.close()
return '{"status":"ok"}' return '{"status":"ok"}'
else: else:
# Modify entry # Modify entry
s = 'update locations ' s = 'update locations '
s += 'set name=:name, map=:map, ' s += 'set name=:name, container_id=:container '
s += 'where id=:locationID;' s += 'where id=:locationID;'
s = text(s) s = text(s)
r = db_engine.execute(s, name=request.form['name'],map=request.form['map'],locationID=locationID); r = db_engine.execute(s, name=request.form['name'],container=request.form['container'],locationID=locationID);
r.close() r.close()
return '{"status":"ok"}' return '{"status":"ok"}'
@ -263,6 +263,15 @@ def delete(partID):
r = db_engine.execute(s, id=partID) r = db_engine.execute(s, id=partID)
return '{"status":"ok"}' return '{"status":"ok"}'
@app.route('/parts/deleteLocation/<locationID>')
# @requires_auth
def deleteLocation(locationID):
if int(locationID) < 0:
abort(400)
s = text('delete from locations where id=:id;')
r = db_engine.execute(s, id=locationID)
return '{"status":"ok"}'
def connect(user, password, db, host='localhost', port=5432): def connect(user, password, db, host='localhost', port=5432):
'''Returns a connection and a metadata object''' '''Returns a connection and a metadata object'''
# We connect with the help of the PostgreSQL URL # We connect with the help of the PostgreSQL URL

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

@ -1,18 +1,18 @@
var rootURL = '/parts/' var rootURL = '/parts/'
function overlay_in() { function overlay_in() {
$('.shadow').css({'display' : 'block'}); $('.shadow').show();
$('.overlay').css({'display' : 'block'}); $('.overlay').show();
$('.shadow').animate({'opacity' : 0.7}); $('.shadow').animate({'opacity' : 0.7});
$('.overlay').animate({'opacity' : 1.0, 'top' : '5%'}); $('.overlay').animate({'opacity' : 1.0, 'top' : '5%'});
} }
function overlay_out() { function overlay_out() {
$('.shadow').animate({'opacity' : 0.0}, function () { $('.shadow').animate({'opacity' : 0.0}, function () {
$('.overlay').css({'display' : 'none'}); $('.shadow').hide();
}); });
$('.overlay').animate({'opacity' : 0.0, 'top' : '0'}, function () { $('.overlay').animate({'opacity' : 0.0, 'top' : '0'}, function () {
$('.shadow').css({'display' : 'none'}); $('.overlay').hide();
}); });
end_edit(); end_edit();
} }

@ -1,27 +1,26 @@
function new_location_entry() { function new_location_entry() {
$('#location-name-input').text('');
$('#location-name-input').show();
$('#mapfile-input').show();
init_Location_edit(-1);
overlay_in();
} }
function init_Location_edit(locationID) { function init_Location_edit(locationID, name, containerID) {
$('#save-button').attr("onclick", "saveLocation(" + locationID + ")");
$('table#details tr#datasheet td input').show(); $('#delete-button').attr("onclick", "deleteLocation(" + locationID + ")");
$('#location-name-input').val(name);
var newButton = '<div class="round-button-left"><a href="#" onclick="saveLocation(' + locationID + ')"><i class="fa fa-check" aria-hidden="true"></i></a></div>'; if(containerID > 0){
$('.round-button-left').replaceWith(newButton); $("#container-input").val(containerID);
update_map();
}
overlay_in();
} }
function update_clickable_map() { function update_map() {
var selected_map_file = $('#mapfile-input').val(); var selected_map_file = $('#container-input').val();
$('#clickablemap').attr('src', 'map/' + selected_map_file); $('#map').attr('src', 'map/' + selected_map_file);
} }
function saveLocation(locationID) { function saveLocation(locationID) {
var map_v = $('#clickablemap').attr('src').substring(4); var container_v = $('#container-input').val();
var name_v = $('#location-name-input').val(); var name_v = $('#location-name-input').val();
if(name_v.length > 100) { if(name_v.length > 100) {
@ -30,7 +29,7 @@ function saveLocation(locationID) {
} }
var data = new FormData(); var data = new FormData();
data.append('map', map_v); data.append('container', container_v);
data.append('name', name_v) data.append('name', name_v)
$.ajax({ $.ajax({
@ -54,7 +53,65 @@ function saveLocation(locationID) {
}); });
} }
function deleteLocation(locationID) {
if (locationID < 0)
alert('Congratulations! You found the secret UI bug easter egg! This button should not be here, yet I left it specifically because I wanted an easter egg and not because of any other reasons! Good for you!')
return;
if (!confirm('Delete the selected location? If there are parts there, this will leave a mess in the database and Marek will be very sad.'))
return;
$.ajax({
url: rootURL + 'deleteLocation/' + locationID,
type: 'GET',
cache: false,
contentType: false,
processData: false,
success: function() {
alert("location removed.");
overlay_out();
location.reload();
},
fail: function() {
console.log('An error occurred while deleting the entry');
},
});
}
function end_edit(){
//intentionally left blank
}
function show_location_info(locationID) {
$.getJSON(rootURL + 'getpartinfo/' + partID, function(data) {
$('table#details tr#location td p').text(text_filter(data.location_descriptor)); // name is the location friendly name
$('#location-dropdown').val(data.location_id);
$('#container-dropdown').val(data.container_id);
$('table#details tr#partno td p').text(text_filter(data.partno));
$('table#details tr#partno td input').val(text_filter(data.partno));
$('table#details tr#description td p').text(text_filter(data.description));
$('table#details tr#description td input').val(text_filter(data.description));
container_onchange();
if (data.datasheet != null) {
$('tr#datasheet-head').html($('<td>DATASHEET: <a href="parts/getfile/' + data.datasheet + '"><i class="fa fa-file-text" aria-hidden="true"></i></a></td>'));
$('#datasheet-input').val(data.datasheet);
}
else
$('tr#datasheet-head td').text('DATASHEET: ');
$('#edit-button').click(function() {
init_edit(partID);
});
$('#delete-button').click(function() {
delete_entry(partID);
});
overlay_in();
}).fail(function() {
console.log( "Fetching part info failed" );
});
}
function placeMarker(locationID){ function placeMarker(locationID){
//temporarily not used
var $img = $('#clickablemap'); var $img = $('#clickablemap');
var currentClickPosX = event.pageX - $img.offset().left; var currentClickPosX = event.pageX - $img.offset().left;
var currentClickPosY = event.pageY - $img.offset().top; var currentClickPosY = event.pageY - $img.offset().top;

@ -2,6 +2,7 @@ html {
background-color: #D7E2E2; background-color: #D7E2E2;
color: #000F0F; color: #000F0F;
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
font-size:large;
} }
body { body {
@ -26,7 +27,7 @@ h3 {
color: #5E9292; color: #5E9292;
text-align: center; text-align: center;
padding: 12pt; padding: 12pt;
font-size: 20pt; font-size: x-large;
opacity: 0; opacity: 0;
} }
@ -40,7 +41,7 @@ a {
input[type=text].search-bar { input[type=text].search-bar {
color: #404040; color: #404040;
font-size: 20pt; font-size: x-large;
padding: 5pt 8pt 5pt 8pt; padding: 5pt 8pt 5pt 8pt;
margin-top: 8pt; margin-top: 8pt;
margin-bottom: 8pt; margin-bottom: 8pt;
@ -162,11 +163,14 @@ div label input {
color: #D7E2E2; color: #D7E2E2;
display: none; display: none;
height: 90%; height: 90%;
left: 20%;
padding: 0; padding: 0;
position: fixed; position: fixed;
margin:auto;
left:0;
right:0;
top:0; top:0;
width: 60%; min-width: 60%;
width:900px;
z-index: 201; z-index: 201;
border-radius: 2pt; border-radius: 2pt;
text-align: center; text-align: center;
@ -289,7 +293,7 @@ table#results {
table#results th { table#results th {
background-color: #226666; background-color: #226666;
color: #D7E2E2; color: #D7E2E2;
padding: 4pt; padding: 5pt;
border-right: 2px solid #D7E2E2; border-right: 2px solid #D7E2E2;
border-left: 2px solid #D7E2E2; border-left: 2px solid #D7E2E2;
} }
@ -322,7 +326,7 @@ table#results #docs {
table#details { table#details {
position: absolute; position: absolute;
left: 0; left: 0;
width: 45%; width: 35%;
margin-top: 4%; margin-top: 4%;
} }
@ -393,10 +397,20 @@ td p {
right: 5%; right: 5%;
/*margin-top: 4%;*/ /*margin-top: 4%;*/
max-height: calc(90% - 42pt); max-height: calc(90% - 42pt);
max-width: 50%; max-width: 60%;
} }
.pinfo-input { .pinfo-input {
display: none; display: none;
width: 90%; width: 90%;
}
.nothidden{
display: initial !important;
}
.results-locations{
max-width: 1000px;
margin-left: auto;
margin-right: auto;
} }

@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>ELAB Part Search Engine</title> <title>ELAB Part Search Engine - Location editor</title>
<script <script
src="https://code.jquery.com/jquery-3.2.1.min.js" src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
@ -14,19 +14,21 @@
<script type="text/javascript" src="{{ url_for('static', filename='locationEditorScript.js') }}"></script> <script type="text/javascript" src="{{ url_for('static', filename='locationEditorScript.js') }}"></script>
</head> </head>
<body> <body>
<h1>ELAB Part Search Engine - LOCATION EDITOR</h1> <h1>LOCATION EDITOR</h1>
<p>Looking for a place to store your obsolete ICs discontinued years ago? Just toss them anywhere and mark that location here!</p> <p>Looking for a place to store your obsolete ICs discontinued years ago? Just toss them anywhere and mark that location here! <a href=".">back to parts</a></p>
<table id="results"> <table id="results" class="results-locations">
<tr> <tr>
<th id="id">Container</th> <th>ID</th>
<th id="location">Location name</th> <th>c.ID</th>
<th id="mapURL">ID</th> <th>Container name</th>
<th>Location name</th>
</tr> </tr>
{% for location in locations %} {% for location in locations %}
<tr> <tr onclick="init_Location_edit({{location['id']}}, '{{location['name']}}', {{location['container_id']}});">
<td>{{location['id']}}</td>
<td>{{location['container_id']}}</td>
<td>{{location['container']}}</td> <td>{{location['container']}}</td>
<td>{{location['name']}}</td> <td>{{location['name']}}</td>
<td>{{location['id']}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
@ -35,26 +37,28 @@
<div class="overlay"> <div class="overlay">
<h2>Part Details</h2> <h2>Part Details</h2>
<table id="details"> <table id="details">
<tr><td>Name</td></tr> <tr><td>Adding a new LOCATION inside a given CONTAINER</td></tr>
<tr><td><p></p><input type="text" name="location-name-input" id="location-name-input" placeholder="Location name" class="pinfo-input"/></td></tr>
<tr><td>MAP</td></tr>
<tr><td> <tr><td>
<select class="pinfo-input" onchange="update_clickable_map()" name="mapfile-input" id="mapfile-input"> <select class="pinfo-input nothidden" onchange="update_map()" name="mapfile-input" id="container-input">
{% for container in containers %} {% for container in containers %}
<option value="{{container['id']}}">{{container['name']}}</option> <option value="{{container['id']}}">{{container['name']}}</option>
{% endfor %} {% endfor %}
</select> </select>
</td></tr> </td></tr>
<tr><td>And click on the map to place the marker</td></tr> <tr><td>Location name (obs! If a drawer has an identification sticker, start the name with it.<br />Example: ".2 - Power resistors"</td></tr>
<tr><td><p></p><input type="text" name="location-name-input" id="location-name-input" placeholder="Location name" class="pinfo-input nothidden"/></td></tr>
<tr><td>Note: adding custom "containers" is currently insupported and unpossible.</td></tr>
</table> </table>
<img src="map/{{defaultMapfile}}" id="clickablemap" class="map" onclick="placeMarker()"/> <img src="map/{{containers[0]['id']}}" id="map" class="map"/>
<div class="round-button-left"><a href="#" id="edit-button"><i class="fa fa-pencil" aria-hidden="true"></i></a></div> <div class="round-button-left"><a href="#" id="save-button"><i class="fa fa-check" aria-hidden="true"></i></a></div>
<div class="round-button"><a href="#" id="delete-button"><i class="fa fa-trash" aria-hidden="true"></i></a></div> <div class="round-button"><a href="#" id="delete-button"><i class="fa fa-trash" aria-hidden="true"></i></a></div>
<div class="small-square-button"><a href="#" onclick="overlay_out()"><i class="fa fa-times" aria-hidden="true"></i></a></div> <div class="small-square-button"><a href="#" onclick="overlay_out()"><i class="fa fa-times" aria-hidden="true"></i></a></div>
</div> </div>
<div class="round-floating-button"><a href="#" onclick="new_location_entry()"><i class="fa fa-plus" aria-hidden="true"></i></a></div> <div class="round-floating-button"><a href="#" onclick="init_Location_edit(-1, '', 0)"><i class="fa fa-plus" aria-hidden="true"></i></a></div>
</body> </body>
</html> </html>

@ -9,6 +9,8 @@
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<link rel="apple-touch-icon-precomposed" href="{{ url_for('static', filename='apple-touch-icon.png') }}">
<script src="https://use.fontawesome.com/2fef7be393.js"></script> <script src="https://use.fontawesome.com/2fef7be393.js"></script>
<script type="text/javascript" src="{{ url_for('static', filename='common.js') }}"></script> <script type="text/javascript" src="{{ url_for('static', filename='common.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='script.js') }}"></script> <script type="text/javascript" src="{{ url_for('static', filename='script.js') }}"></script>
@ -41,6 +43,7 @@
<div class="shadow" onclick="overlay_out()"></div> <div class="shadow" onclick="overlay_out()"></div>
<div class="overlay"> <div class="overlay">
<h2>Part Details</h2> <h2>Part Details</h2>
<div>
<table id="details"> <table id="details">
<tr id="location-head"><td>LOCATION</td></tr> <tr id="location-head"><td>LOCATION</td></tr>
<tr id="location"><td><p></p> <tr id="location"><td><p></p>
@ -61,10 +64,13 @@
<tr id="datasheet"><td><input type="file" accept=".pdf" class="pinfo-input"></td></tr> <tr id="datasheet"><td><input type="file" accept=".pdf" class="pinfo-input"></td></tr>
</table> </table>
<img src="" id="map" class="map"/> <img src="" id="map" class="map"/>
</div>
<div>
<div class="round-button-left"><a href="#" id="edit-button"><i class="fa fa-pencil" aria-hidden="true"></i></a></div> <div class="round-button-left"><a href="#" id="edit-button"><i class="fa fa-pencil" aria-hidden="true"></i></a></div>
<div class="round-button"><a href="#" id="delete-button"><i class="fa fa-trash" aria-hidden="true"></i></a></div> <div class="round-button"><a href="#" id="delete-button"><i class="fa fa-trash" aria-hidden="true"></i></a></div>
<div class="round-button-right"><a href="#" id="duplicate-button" onclick="init_edit(-1)"><i class="fa fa-copy" aria-hidden="true"></i></a></div> <div class="round-button-right"><a href="#" id="duplicate-button" onclick="init_edit(-1)"><i class="fa fa-copy" aria-hidden="true"></i></a></div>
<div class="small-square-button"><a href="#" onclick="overlay_out()"><i class="fa fa-times" aria-hidden="true"></i></a></div> <div class="small-square-button"><a href="#" onclick="overlay_out()"><i class="fa fa-times" aria-hidden="true"></i></a></div>
</div>
</div> </div>
<div class="round-floating-button"><a href="#" onclick="new_entry()"><i class="fa fa-plus" aria-hidden="true"></i></a></div> <div class="round-floating-button"><a href="#" onclick="new_entry()"><i class="fa fa-plus" aria-hidden="true"></i></a></div>
</body> </body>

Loading…
Cancel
Save