diff --git a/parts/server.py b/parts/server.py index 54c43e1..e700fa4 100644 --- a/parts/server.py +++ b/parts/server.py @@ -65,21 +65,22 @@ def serveImage(img): img_io.seek(0) return send_file(img_io, mimetype='image/png') -@app.route('/parts', strict_slashes=True) +@app.route('/', strict_slashes=True) def index(): return render_template('partsearch.html', containers=getContainers()) -@app.route('/parts/getlocationsInContainer/') -def get_locations_in_container(containerID): - s = 'select id, name from locations where container_id = :id order by name;' - r = db_engine.execute(text(s), id=containerID) +@app.route('/getTypes') +def get_locations_in_container(): + s = 'select id, name from containers order by name;' + r = db_engine.execute(text(s)) l={} for row in r: l[row[0]]= row[1]; r.close() + print(json.dumps(l)) return json.dumps(l) -@app.route('/parts/getlocationURL/') +@app.route('/getlocationURL/') def get_locationURL(locationID): s = 'select map from locations where id = :id;' r = db_engine.execute(text(s), id=locationID) @@ -89,7 +90,7 @@ def get_locationURL(locationID): r.close() return l[0][0] -@app.route('/parts/locationEditor') +@app.route('/locationEditor') def locationEditor(): 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)) @@ -99,7 +100,7 @@ def locationEditor(): r.close() return render_template('locationEditor.html', locations=locations, containers=getContainers()) -@app.route('/parts/alterLocation/', methods=['POST']) +@app.route('/alterLocation/', methods=['POST']) @requires_auth def alterLocation(locationID): locationID = int(locationID) @@ -122,9 +123,9 @@ def alterLocation(locationID): r.close() return '{"status":"ok"}' -@app.route('/parts/getpartinfo/') +@app.route('/getpartinfo/') def get_part_info(partID): - s = 'select p.id,partno,description,notes, c.name || l.name as location_descriptor, location_id, container_id, datasheet from parts as p inner join locations as l on p.location_id = l.id inner join containers as c on l.container_id = c.id where p.id = :id;' + s = 'select p.id,partno,description,notes,parameters,c.name as type_descriptor, type_id, datasheet from parts as p inner join containers as c on p.type_id = c.type where p.id = :id;' r = db_engine.execute(text(s), id=partID) l = [] for row in r: @@ -132,7 +133,7 @@ def get_part_info(partID): r.close() return json.dumps(l[0]) -@app.route('/parts/query//') # TODO: maybe change AND to OR or maybe not +@app.route('/query//') # TODO: maybe change AND to OR or maybe not def query(filter_dummy, query): filter = request.args.to_dict() keywords = query.split() # Default splits with spaces @@ -142,12 +143,12 @@ def query(filter_dummy, query): for i in range(len(keywords)): kw_dict["kw" + str(i)] = keywords[i] - s = 'select p.id,partno,description, c.name || l.name as location_descriptor from parts as p inner join locations as l on p.location_id = l.id inner join containers as c on l.container_id = c.id where ' + s = 'select p.id,partno,description,type_id,c.name as type_descriptor from parts as p inner join containers as c on p.type_id = c.type where ' if filter['l'] == 'true': s += '(' for i in range(len(keywords)): - s += 'LOWER(c.name||l.name) like LOWER(:kw'+ str(i) +') AND ' + s += 'LOWER(c.name) like LOWER(:kw'+ str(i) +') AND ' s = s[:-5] s += ') OR ' if filter['p'] == 'true': @@ -171,7 +172,7 @@ def query(filter_dummy, query): r.close() return json.dumps(l) -@app.route('/parts/map/') +@app.route('/map/') def getMap(containerID): s = 'select map, overlay from containers where id = :id;' r = db_engine.execute(text(s), id=containerID) @@ -196,14 +197,14 @@ def getMap(containerID): return serveImage(mapimage) -@app.route('/parts/getfile/') +@app.route('/getfile/') def getfile(filename): if(re.match('^[\w\-_]+.[p|P][d|D][f|F]$', filename) == None): return 'No injections pls.' return send_from_directory('/srv/datasheets/', filename) -@app.route('/parts/alter/', methods=['POST']) +@app.route('/alter/', methods=['POST']) @requires_auth def alter(partID): partID = int(partID) @@ -211,8 +212,8 @@ def alter(partID): r = {} if partID < 0: # New entry - s = 'insert into parts (partno, description, datasheet, location_id, whoadded, notes) ' - s += 'values (:partno, :description, :datasheet, :location_id, :user_id, :notes) returning id;' + s = 'insert into parts (partno, description, datasheet, type_id, whoadded, notes, parameters) ' + s += 'values (:partno, :description, :datasheet, :type_id, :user_id, :notes, :parameters) returning id;' s = text(s) if len(request.files) != 0: datasheet_file = request.files['datasheet-file'] @@ -222,7 +223,7 @@ def alter(partID): datasheet_filename = datasheet_filename[:-4] + str(i) + '.pdf' i += 1 datasheet_file.save('/srv/datasheets/' + datasheet_filename) - datasheet_filename = 'http://elab.kth.se/parts/getfile/' + datasheet_filename + datasheet_filename = 'http://elab.kth.se/getfile/' + datasheet_filename # elif request.form.has_key('datasheet-url'): # datasheet_filename = request.form['datasheet-url'] else: @@ -233,8 +234,9 @@ def alter(partID): r = db_engine.execute(s, partno=request.form['partno'], description=request.form['description'], datasheet=datasheet_filename, - location_id=request.form['location_id'], + type_id=request.form['type_id'], notes=request.form['notes'], + parameters=request.form['parameters'], user_id=session['uid']) else: # Modify entry @@ -244,7 +246,7 @@ def alter(partID): l.append(dict(row)) r.close() s = 'update parts ' - s += 'set partno=:partno, description=:description, datasheet=:datasheet, location_id=:location_id, notes=:notes ' + s += 'set partno=:partno, description=:description, datasheet=:datasheet, type_id=:type_id, notes=:notes, parameters=:parameters ' if len(request.files) != 0: datasheet_file = request.files['datasheet-file'] datasheet_filename = secure_filename(datasheet_file.filename) @@ -253,7 +255,7 @@ def alter(partID): datasheet_filename = datasheet_filename[:-4] + str(i) + '.pdf' i += 1 datasheet_file.save('/srv/datasheets/' + datasheet_filename) - datasheet_filename = 'http://elab.kth.se/parts/getfile/' + datasheet_filename + datasheet_filename = 'http://elab.kth.se/getfile/' + datasheet_filename if l[0]['datasheet'] != None: whole_url = l[0]['datasheet'] actual_filename = whole_url[whole_url.rfind('/') + 1:] @@ -268,15 +270,16 @@ def alter(partID): r = db_engine.execute(s, partno=request.form['partno'], description=request.form['description'], datasheet=datasheet_filename, - location_id=request.form['location_id'], + type_id=request.form['type_id'], id=partID, - notes=request.form['notes']) + notes=request.form['notes'], + parameters=request.form['parameters']) new_id = r.fetchone()[0] r.close() return '{"status":"ok", "part_id" : ' + str(new_id) + '}' -@app.route('/parts/delete/') +@app.route('/delete/') @requires_auth def delete(partID): if int(partID) < 0: @@ -285,7 +288,7 @@ def delete(partID): r = db_engine.execute(s, id=partID) return '{"status":"ok"}' -@app.route('/parts/deleteLocation/') +@app.route('/deleteLocation/') @requires_auth def deleteLocation(locationID): if int(locationID) < 0: @@ -294,7 +297,7 @@ def deleteLocation(locationID): r = db_engine.execute(s, id=locationID) return '{"status":"ok"}' -@app.route('/parts/fetchOctopartSnippet/') +@app.route('/fetchOctopartSnippet/') def fetchOctopartSnippet(searchTerm): if octopartURL == '': return '{"result":"octopart integration not enabled"}' @@ -334,7 +337,7 @@ if __name__ == '__main__': app.config['SESSION_TYPE'] = 'memcached' with open('admin.json') as f: postgres_credentials = json.load(f) - db_engine, db_metadata = connect(postgres_credentials['username'], postgres_credentials['password'], 'parts_v2') + db_engine, db_metadata = connect(postgres_credentials['username'], postgres_credentials['password'], 'estimator') parts = sqlalchemy.Table('parts', db_metadata) try: with open('octopartAPIkey.json') as f: diff --git a/parts/static/common.js b/parts/static/common.js index dad7846..674a9d0 100644 --- a/parts/static/common.js +++ b/parts/static/common.js @@ -1,4 +1,4 @@ -var rootURL = '/parts/' +var rootURL = '/' function overlay_in() { $('.shadow').show(); @@ -15,4 +15,21 @@ function overlay_out() { $('.overlay').hide(); }); end_edit(); -} \ No newline at end of file +} + +function calculateoverlay_in() { + $('.shadow').show(); + $('.calculateoverlay').show(); + $('.shadow').animate({'opacity' : 0.7}); + $('.calculateoverlay').animate({'opacity' : 1.0, 'top' : '5%'}); +} + +function calculateoverlay_out() { + $('.shadow').animate({'opacity' : 0.0}, function () { + $('.shadow').hide(); + }); + $('.calculateoverlay').animate({'opacity' : 0.0, 'top' : '0'}, function () { + $('.calculateoverlay').hide(); + }); + +} diff --git a/parts/static/locationEditorScript.js b/parts/static/locationEditorScript.js index 357213f..e92e22e 100644 --- a/parts/static/locationEditorScript.js +++ b/parts/static/locationEditorScript.js @@ -95,7 +95,7 @@ function show_location_info(locationID) { $('table#details tr#description td input').val(text_filter(data.description)); container_onchange(); if (data.datasheet != null) { - $('tr#datasheet-head').html($('DATASHEET: ')); + $('tr#datasheet-head').html($('DATASHEET: ')); $('#datasheet-input').val(data.datasheet); } else @@ -123,4 +123,4 @@ function placeMarker(locationID){ // $("#mapURL").html("elab.png?x=" + correctX + "&y=" + correctY); $("#clickablemap").attr("src", "map/" + $("#mapfile-input").val() + "?x=" + correctX + "&y=" + correctY); -} \ No newline at end of file +} diff --git a/parts/static/script.js b/parts/static/script.js index d58a40d..36baeba 100644 --- a/parts/static/script.js +++ b/parts/static/script.js @@ -1,13 +1,16 @@ var active_timer = 100; +var calculation = 0; +function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} function init_edit(partID) { - $('table#details tr#location td p').hide(); - $('#location-dropdown').show(); - $('#container-dropdown').show(); + $('table#details tr#type td p').hide(); + $('#type-dropdown').show(); $('table#details tr#partno td p').hide(); $('input[name=partno-input]').show(); - $('#magical_autofill').show(); +// $('#magical_autofill').show(); $('table#details tr#description td p').hide(); $('input[name=description-input]').show(); @@ -23,6 +26,16 @@ function init_edit(partID) { $('input[name=notes-input]').show(); $('table#details tr#notes td p').hide(); + $('input[name=voltage-input]').show(); + $('table#details tr#voltage td p').hide(); + $('input[name=current-input]').show(); + $('table#details tr#current td p').hide(); + $('input[name=sleepcurrent-input]').show(); + $('table#details tr#sleepcurrent td p').hide(); + $('input[name=txrx-input]').show(); + $('input[name=txrx-head]').show(); + $('table#details tr#txrx td p').hide(); + // var newButton = '
'; // $('.round-button-left').replaceWith(newButton); $('#edit-button').html(''); @@ -32,29 +45,32 @@ function init_edit(partID) { } function new_entry() { - $('table#details tr#location td p').text(''); + $('table#details tr#type td p').text(''); $('table#details tr#partno td p').text(''); $('table#details tr#description td p').text(''); $('table#details tr#partno td input').val(''); $('table#details tr#description td input').val(''); $('input[name=datasheet-url-input]').val(''); - // container_onchange(); + container_onchange(); init_edit(-1); overlay_in(); } +function calculate() { + calculateoverlay_in(); +} + function end_edit() { - $('table#details tr#location td p').text($('table#details tr#location td select option:checked').text()); - $('table#details tr#location td p').show(); - $('#location-dropdown').hide(); - $('#container-dropdown').hide(); + $('table#details tr#type td p').text($('table#details tr#type td select option:checked').text()); + $('table#details tr#type td p').show(); + $('#type-dropdown').hide(); $('table#details tr#partno td p').text($('table#details tr#partno td input').val()); $('table#details tr#partno td p').show(); $('table#details tr#partno td input').hide(); - $('#magical_autofill').hide(); +// $('#magical_autofill').hide(); $('table#details tr#description td p').text($('table#details tr#description td input').val()); $('table#details tr#description td p').show(); @@ -73,17 +89,26 @@ function end_edit() { // $('.round-button-left').replaceWith(newButton); } + function save(partID) { - if (!$('#location-dropdown').val()) { - alert('Please select a location.'); + if (!$('#type-dropdown').val()) { + alert('Please select a component type.'); return; } - var location_id_v = $('#location-dropdown').val(); + var type_id_v = $('type-dropdown').val(); var partno_v = $('input[name=partno-input]').val(); var description_v = $('input[name=description-input]').val(); var datasheet = $('table#details tr#datasheet td input')[0].files; var datasheet_url_v = $('input[name=datasheet-url-input]').val(); var notes_v = $('input[name=notes-input]').val(); + var total = []; + var mapped = {}; + $('.parameter-content').find('input').each(function(index,elem){ +//8 console.log(elem.value); + total.push(elem.value); + mapped[elem.name] = elem.value; + }); + console.log(mapped); if(partno_v.length == 0){ alert('Please enter a part number.'); return; @@ -112,9 +137,11 @@ function save(partID) { data.append('datasheet-url', datasheet_url_v); } data.append('partno', partno_v); - data.append('location_id', location_id_v); + data.append('type_id', type_id_v); data.append('description', description_v); data.append('notes', notes_v); + data.append('parameters', mapped); + $.ajax({ // Your server script to process the upload @@ -172,18 +199,48 @@ function delete_entry(partID) { }, }); } +function calculate_entry(partID,parameters) { + if (partID < 0) + return; + if (!confirm('Add selected entry to calculation?')) + return; + console.log(parameters); + if(parameters != null) { + var jsonParameters = JSON.parse(data.parameters); + console.log(jsonParameters); + var count = Object.keys(jsonParameters).length; + console.log(count); +// for(var k = 0; k < count; k++) { + var obj = Object.keys(jsonParameters); + var values = Object.values(jsonParameters); + var voltage = 0; + var currents = []; + console.log(obj); + for (var key in obj) { + var value = obj[key]; + console.log(key+":"+value); + if(value.includes('voltage')) { + voltage = values[key]; + } + else if(value.includes('current')) { + + } + } + } +} function show_part_info(partID) { $.getJSON(rootURL + 'getpartinfo/' + partID, function(data) { - $('table#details tr#location td p').text(text_filter(data.location_descriptor)); // name is the location friendly name - $('#container-dropdown').val(data.container_id); - $('img#map').attr('src', 'parts/map/' + data.container_id); - $('#location-dropdown').empty(); - $.getJSON('parts/getlocationsInContainer/' + data.container_id, function(json) { - $.each(json, function(loc_id, loc_name) { - $('#location-dropdown').append(''); - }); - $('#location-dropdown').val(data.location_id); + $('img#map').attr('src', 'parts/map/' + data.type_id); + $('#type-dropdown').empty(); + $.getJSON('/getTypes', function(json) { + $.each(json, function(type_id, type_name) { + $('#type-dropdown').append(''); + if (data.type_id == type_id) { + $('table#details tr#type td p').text(text_filter(type_name)); // name is the type friendly name + } + }); + $('#type-dropdown').val(data.type_id); }); $('table#details tr#partno td p').text(text_filter(data.partno)); $('table#details tr#partno td input').val(text_filter(data.partno)); @@ -191,6 +248,38 @@ function show_part_info(partID) { $('table#details tr#description td input').val(text_filter(data.description)); $('table#details tr#notes td p').text(text_filter(data.notes)); $('input[name=notes-input]').val(text_filter(data.notes)); + console.log(data.parameters); + if(data.parameters != null) { + var jsonParameters = JSON.parse(data.parameters); + console.log(jsonParameters); + var count = Object.keys(jsonParameters).length; + console.log(count); + +// for(var k = 0; k < count; k++) { + var obj = Object.keys(jsonParameters); + var values = Object.values(jsonParameters); + console.log(obj); + for (var key in obj) { + var value = obj[key]; + console.log(key+":"+value); + console.log($('table#details tr#'+value.substring(0,value.indexOf("-"))).children().length ); + if(value.includes("input") && $('table#details tr#'+value.substring(0,value.indexOf("-"))).children().length == 0 ) { + $('table#details').append('

') + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td p').text(capitalizeFirstLetter(value.substring(0,value.indexOf("-")))); + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td p').show(); + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td input').val(values[key]); + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td input').show(); + + } + else { + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td p').text(capitalizeFirstLetter(value.substring(0,value.indexOf("-")))); + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td p').show(); + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td input').val(values[key]); + $('table#details tr#'+value.substring(0,value.indexOf("-"))+' td input').show(); + } + } + } +// } // Resetting file input. Super dirty hack. Disgusting var $el = $('#datasheet-finput'); $el.wrap('
').closest('form').get(0).reset(); @@ -209,6 +298,15 @@ function show_part_info(partID) { $('#delete-button').off('click').on('click', function() { delete_entry(partID); }); + $('#calculate-add-button').off('click').on('click', function() { + for (var key in obj) { + var value = obj[key]; + console.log(key+":"+value); + jsonParameters[obj[key]]=$('table#details tr#'+value.substring(0,value.indexOf("-"))+' td input').val(); + + } + calculate_entry(partID,jsonParameters); + }); overlay_in(); }).fail(function() { console.log( "Fetching part info failed" ); @@ -221,21 +319,24 @@ function perform_query() { $('#no-results').hide(); var query = $('.search-bar').val(); var data = { - l:$('#location').is(':checked'), + l:$('#type').is(':checked'), p:$('#partno').is(':checked'), d:$('#description').is(':checked') }; + filter = '0'; $("#results").find("tr:not(:first)").remove(); // Delete all table rows - $.getJSON(rootURL + 'query/' + filter + '/' + query, data, function(data) { + var queryPromise = $.getJSON(rootURL + 'query/' + filter + '/' + query, data, function(data) { for(var i = 0; i < data.length; i++) { - var newRow = $(''); - newRow.append($('').text(text_filter(data[i].location_descriptor))); + console.log(data[i]); + var newRow = $(''); + newRow.append($('').text(text_filter(data[i].type_descriptor))); newRow.append($('').text(text_filter(data[i].partno))); newRow.append($('').text(text_filter(data[i].description))); $('#results').append(newRow); } + if(data.length == 0) { $('#no-results').show(); $('#no-results').animate({opacity:1},2000); @@ -245,19 +346,23 @@ function perform_query() { $('#no-results').animate({opacity:1},2000); console.log( "Query failed" ); }); +//}); } function container_onchange() { - var selected_container_id = $('#container-dropdown').val(); - if (selected_container_id > 0) { - $('img#map').attr('src', 'parts/map/' + selected_container_id); - $('#location-dropdown').empty(); - $.getJSON('parts/getlocationsInContainer/' + selected_container_id, function(data) { - $.each(data, function(location_id, location_name) { - $('#location-dropdown').append(''); + var selected_container_id = $('#type-dropdown').val(); +// if (selected_container_id > 0) { + //$('#type-dropdown').empty(); + $.getJSON('/getTypes', function(data) { + $.each(data, function(type_id, type_name) { + $('#type-dropdown').append(''); + if (data.type_id == type_id) { + $('table#details tr#type td p').text(text_filter(type_name)); // name is the type friendly name + } + }); }); - } +// } } function octopartFetch(){ @@ -282,7 +387,7 @@ $(document).ready(function() { active_timer = setTimeout(perform_query, 100); }); $('.checkbox').change( function() { - if ( !$('#location').is(':checked') + if ( !$('#type').is(':checked') && !$('#partno').is(':checked') && !$('#description').is(':checked') && !$('#has-docs').is(':checked')) @@ -296,4 +401,4 @@ $(document).ready(function() { // octopartFetch(); // } // }); -}); \ No newline at end of file +}); diff --git a/parts/static/style.css b/parts/static/style.css index 3bf4502..5aa3b1c 100644 --- a/parts/static/style.css +++ b/parts/static/style.css @@ -81,6 +81,9 @@ input[type=text].search-bar { input[type=checkbox]{ display: none; } +input[type=range] { + +} input[type=checkbox] + label.toggle-btn { padding:10px 0 10px 0; @@ -126,6 +129,24 @@ input[type=checkbox]:checked + label.toggle-btn { opacity: 0.0; } +.calculateoverlay { + background-color: #226666; + color: #D7E2E2; + display: none; + height: 90%; + padding: 0; + position: fixed; + margin:auto; + left:0; + right:0; + top:0; + min-width: 60%; + width:900px; + z-index: 201; + text-align: center; + opacity: 0.0; +} + .round-button { display: flex; align-items: center; @@ -171,7 +192,10 @@ input[type=checkbox]:checked + label.toggle-btn { .round-floating-button a{ color: #D7E2E2; } - +#calculate-button { + right: 76px; + margin-right: 8px +} #datasheet-info p { font-size: 12pt; } @@ -203,7 +227,7 @@ input[type=checkbox]:checked + label.toggle-btn { text-align: left; } -#results #location { +#results #type { width: 18%; } @@ -230,6 +254,9 @@ input[type=checkbox]:checked + label.toggle-btn { #details { width: 100%; } +#results { + width: 100%; +} #magical_autofill{ font-size: small; @@ -249,6 +276,14 @@ a.small_link{ padding-top:6pt; padding-bottom:16pt; } +.results-header { + color: #013A3A; +} + +.results-content td{ + padding-top:6pt; + padding-bottom:16pt; +} td p { margin: 0; @@ -275,4 +310,4 @@ td p { .nothidden{ display: initial !important; -} \ No newline at end of file +} diff --git a/parts/templates/locationEditor.html b/parts/templates/locationEditor.html index a32dfac..518146f 100644 --- a/parts/templates/locationEditor.html +++ b/parts/templates/locationEditor.html @@ -8,10 +8,10 @@ integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"> - + - - + +

LOCATION EDITOR

diff --git a/parts/templates/partsearch.html b/parts/templates/partsearch.html index 618529b..9234435 100644 --- a/parts/templates/partsearch.html +++ b/parts/templates/partsearch.html @@ -3,56 +3,53 @@ - ELAB Part Search Engine + IL2232 Estimator - - - + + + - - + + -

ELAB Part Search Engine

-

Looking for obsolete ICs that were discontinued years ago? Just start typing!

+

IL2232 Smart cities power budget estimator

+

Designing an energy harvesting solution? Search for your components, add them and get a power requirement estimate

SEARCH IN

    -
  • +
- +
LocationComponent type Part Number Description

No results.

-
+

Part Details

- - + @@ -64,17 +61,42 @@ + +
LOCATION

-
TYPE

+ -
PART NUMBER

NOTES

PARAMETERS
+
+ +
+

Calculation results

+
+ + + +
TYPE

+
+
+
+
+
+
+
+
+
+
+
+
+
+