diff --git a/my_flask_app/__pycache__/main.cpython-39.pyc b/my_flask_app/__pycache__/main.cpython-39.pyc index 870e9cbe212add277a10cf6075c2b75ab29566f5..068245242330937a344b5e4907b246345019b383 100644 Binary files a/my_flask_app/__pycache__/main.cpython-39.pyc and b/my_flask_app/__pycache__/main.cpython-39.pyc differ diff --git a/my_flask_app/main.py b/my_flask_app/main.py index 3a3f7ba6ea91600f1a9958e870465fe1e27705a8..b7d9e78e4353b12bb7b390bb2047f2fb074d5c68 100644 --- a/my_flask_app/main.py +++ b/my_flask_app/main.py @@ -3,9 +3,9 @@ import pandas as pd from my_flask_app import app from .models.models import CustomTable, CustomColumn, Theme, CompressedDataType, Observation_Spec, RegType, RegRole from flask_sqlalchemy import SQLAlchemy -from flask import jsonify, redirect, render_template, request, session, url_for, json +from flask import jsonify, make_response, redirect, render_template, request, session, url_for, json, send_file from sqlalchemy import ARRAY, BIGINT, BOOLEAN, DOUBLE_PRECISION, FLOAT, INT, INTEGER, JSON, NUMERIC, SMALLINT, TIMESTAMP, UUID, VARCHAR, MetaData, String, create_engine, text, inspect -import pydot, base64, os, logging +import pydot, base64, os, logging, io from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.dialects.postgresql.base import ischema_names from sqlalchemy.dialects.postgresql import JSONB, TSTZRANGE, INTERVAL, BYTEA, JSON, UUID, DOUBLE_PRECISION, BYTEA, ARRAY, REAL, TSTZRANGE, UUID, BYTEA, JSONB, JSON, ARRAY, FLOAT, INTEGER, TIMESTAMP, TEXT, BOOLEAN, VARCHAR, NUMERIC, REAL @@ -379,6 +379,35 @@ def get_ME_table(): return jsonify({'table_HTML': table_HTML}) +@app.route('/export-to-csv', methods=['POST']) +def export_to_csv(): + + data = request.get_json() # This is the data sent from the frontend + df = pd.DataFrame(data) + + if not data: + raise ValueError("No data provided for export.") + + # Adjust the dataframe to skip the first column and rename the headers + df = df.iloc[:, 1:] # Skip the first column + headers = ['time', 'object', 'type', 'label'] # List your headers here + num_features = len(data[0]) - len(headers) - 1 + headers.extend([f'f_{i+1}' for i in range(num_features)]) + df.columns = headers # Rename the DataFrame headers + + + # Convert the DataFrame to a CSV string + csv_output = io.StringIO() + df.to_csv(csv_output, index=False) + csv_output.seek(0) + + # Create a Flask response + response = make_response(csv_output.getvalue()) + response.headers["Content-Disposition"] = "attachment; filename=exported_data.csv" + response.headers["Content-Type"] = "text/csv" + + return response + def readHeaderHTML(str): soup = BeautifulSoup(str, 'html.parser') tds = soup.find_all('td') diff --git a/my_flask_app/models/__pycache__/models.cpython-39.pyc b/my_flask_app/models/__pycache__/models.cpython-39.pyc index 85c8c24503febc2cee3793115e586cf4f4bf73ef..2e0a8d9d8d7c2f1d91d5104ea76cf387a4a83dbe 100644 Binary files a/my_flask_app/models/__pycache__/models.cpython-39.pyc and b/my_flask_app/models/__pycache__/models.cpython-39.pyc differ diff --git a/my_flask_app/templates/app.html b/my_flask_app/templates/app.html index d22226f200239a8c725e41f6fc2aad23afbf4e7b..2583177162201e466188aa4cd0d036b20e109d33 100644 --- a/my_flask_app/templates/app.html +++ b/my_flask_app/templates/app.html @@ -580,6 +580,8 @@ <div class="mb-3"> <h4 style="display: inline; margin-left: .2em;">Machine Data Table (LIMIT 500)</h4> <button type="submit" class="btn btn-primary uk-button-small headerButton" style="margin-top: -3px;" onclick="resetMachineDataTable()">Reset</button> + <button type="submit" class="btn btn-primary uk-button-small headerButton" style="margin-top: -3px;" onclick="">Add</button> + <button type="submit" class="btn btn-primary uk-button-small headerButton" style="margin-top: -3px;" onclick="exportSelectedRowsToCSV()">Export</button> </div> <div class="uk-overflow-auto" id="machine-data-table" style="flex-grow: 1; overflow-y: auto; max-height: max-content; margin-top: -20px;" > <table id="MD-table" class="uk-table uk-table-hover uk-table-small uk-table-middle uk-table-divider uk-table-striped" style="cursor: pointer;"> @@ -766,75 +768,41 @@ } - - - - - // function select_schema(){ - // document.getElementById('schemaSelect').addEventListener('changed', function() { - // var selectedSchema = this.value; - // console.log(selectedSchema); - // // Iterate over all option elements in the select element - // let options = document.getElementById('schemaSelect').options; - // for (let i = 0; i < options.length; i++) { - // if (options[i].value == selectedSchema) { - // options[i].selected = true; // Set the selected attribute to true - // } else { - // options[i].selected = false; // Ensure other options are not marked as selected - // } - // } - - // fetch('/update-schema', { - // method: 'POST', - // body: JSON.stringify({ schema: selectedSchema }), - // headers: { - // 'Content-Type': 'application/json' - // } - // }) - // .then(response => response.json()) - // .then(data => { - // // Update the tables container with the new tables - // const tablesContainer = document.getElementById('show_tables1'); - // tablesContainer.innerHTML = ''; // Clear existing tables - - // data.tables.forEach(table => { - // // Create new elements for each table and append them to the container - // const divOuter = document.createElement('div'); - // divOuter.className = "uk-margin"; - // divOuter.style = "height: 15px; margin-bottom: -4px;"; - - // const divInner = document.createElement('div'); - // divInner.className = "list-group-item-action uk-card uk-card-default uk-card-body uk-card-small"; - // divInner.style = "height: 15px; padding-top: 5px;"; - // divInner.textContent = table; + function exportSelectedRowsToCSV() { + // Collect all selected rows from the Machine Data Table + var selectedRowsData = []; + document.querySelectorAll('#MD-table input[type="checkbox"]:checked').forEach(function(checkbox) { + var row = checkbox.closest('tr'); + var rowData = {}; + row.querySelectorAll('td').forEach(function(td, index) { + rowData['column' + index] = td.textContent; // or any other logic to get cell data + }); + selectedRowsData.push(rowData); + }); - // divOuter.appendChild(divInner); - // tablesContainer.appendChild(divOuter); - // }); - // showErdCanvas("erdCanvas1", "zoomInBtn1", "zoomOutBtn1", data.image1 ); - // }) - // .catch(error => console.error('Error:', error)); - // }); - // } + // Send the selected rows data to the Flask backend + fetch('/export-to-csv', { + method: 'POST', + body: JSON.stringify(selectedRowsData), + headers: { + 'Content-Type': 'application/json' + } + }) + .then(response => response.blob()) // Get the file blob from the response + .then(blob => { + // Create a link element and click it to download the file + var url = window.URL.createObjectURL(blob); + var a = document.createElement('a'); + a.href = url; + a.download = 'exported_data.csv'; + document.body.appendChild(a); + a.click(); + a.remove(); + }) + .catch(error => console.error('Error:', error)); + } - // function show_all() { - // document.getElementById('showAllClick').addEventListener('change', function() { - // var showAll = this.checked; // The checkbox is currently checked (true) or unchecked (false) - // fetch('/update-show-all', { - // method: 'POST', - // body: JSON.stringify({ show_all: showAll }), - // headers: { - // 'Content-Type': 'application/json' - // } - // }) - // .then(response => response.json()) - // .then(data => { - // showErdCanvas("erdCanvas1", "zoomInBtn1", "zoomOutBtn1", data.image1 ); - // }) - // .catch(error => console.error('Error:', error)); - // }); - // } function click_all_MD_table(element) { var checkboxes = document.querySelectorAll('#MD-table tbody input[type="checkbox"]'); @@ -948,7 +916,6 @@ } - // Select only the specified select elements const time_object_selects = document.querySelectorAll('.time-object-select'); @@ -1049,6 +1016,7 @@ }); } + function selfdefinedObject() { var object = document.getElementById('defined-object').value; var select = document.getElementById('defined_object_values'); @@ -1284,6 +1252,7 @@ document.getElementById('defined-label').value = ''; // Clear the input field } + function toggleSidebar() { var sidebar = document.getElementById("sidebar1"); var content = document.getElementById("content"); @@ -1296,16 +1265,19 @@ } } + function toggleTerminal() { var terminal = document.getElementById('terminal'); terminal.classList.toggle('active'); } + function closeTerminal() { var terminal = document.getElementById('terminal'); terminal.style.height = `0 px`; } + function makeSidebarResizable(sidebarId, handleId, isLeftHandle) { var isResizing = false; var lastDownX = 0; @@ -1346,6 +1318,7 @@ }); } + function showErdCanvas(erdCanvas, zoomInBtn, zoomOutBtn, erdImage) { var canvas = document.getElementById(erdCanvas); var ctx = canvas.getContext("2d"); @@ -1451,6 +1424,7 @@ .catch(error => console.error('Error:', error)); } + function handleLabelColumnClick(label) { fetch('/get-label-column', { method: 'POST', @@ -1482,6 +1456,7 @@ .catch(error => console.error('Error:', error)); } + function makeTerminalResizable() { const terminal = document.getElementById('terminal'); const terminalHeader = document.getElementById('terminal-header'); @@ -1505,6 +1480,7 @@ }); } + function segmentTypeSelected() { console.log('Segment type selected'); if (this.value == 'segment') { @@ -1518,6 +1494,7 @@ } } + document.querySelectorAll('.type-radio').forEach(function(radio) { radio.addEventListener('change', function() { var $ = function(id) { return document.getElementById(id); }; @@ -1615,46 +1592,116 @@ }); - // document.getElementById('resetButton').addEventListener('click', function(event) { - // event.preventDefault(); // Prevent the default form submission - - // // Send a POST request to the server - // fetch('/handle-drop', { - // method: 'POST', - // body: JSON.stringify({'reset': true}), - // headers: { - // 'Content-Type': 'application/json' - // } - // }) - // .then(response => response.json()) - // .then(data => { - // // let tables_list = data['tables']; - // document.getElementById('tables').innerHTML = data.tables; - // // for (let i = 0; i < tables_list.length; i++) { - // // let table = tables_list[i]; - // // let item_inner = document.createElement('div'); - // // item_inner.className = 'ist-group-item-action uk-card uk-card-default uk-card-body uk-card-small'; - // // item_inner.style = "height: 15px; padding-top: 5px;" - // // item_inner.textContent = table; - - // // let item_outer = document.createElement('div'); - // // item_outer.className = 'uk-margin'; - // // item_outer.style = "height: 15px; margin-bottom: -4px;" - // // item_outer.appendChild(item_inner); - - // // document.getElementById('show_tables1').appendChild(item_outer); - // // } - // document.getElementById('dropped_items').innerHTML =data.dropped_items; - // showErdCanvas("erdCanvas2", "zoomInBtn2", "zoomOutBtn2", data.image2); - // showErdCanvas("erdCanvas3", "zoomInBtn3", "zoomOutBtn3", data.image2); - - // }) - // .catch(error => console.error('Error:', error)); - // }); - - // Attach click event listener to each dropped item + + // function select_schema(){ + // document.getElementById('schemaSelect').addEventListener('changed', function() { + // var selectedSchema = this.value; + // console.log(selectedSchema); + // // Iterate over all option elements in the select element + // let options = document.getElementById('schemaSelect').options; + // for (let i = 0; i < options.length; i++) { + // if (options[i].value == selectedSchema) { + // options[i].selected = true; // Set the selected attribute to true + // } else { + // options[i].selected = false; // Ensure other options are not marked as selected + // } + // } + + // fetch('/update-schema', { + // method: 'POST', + // body: JSON.stringify({ schema: selectedSchema }), + // headers: { + // 'Content-Type': 'application/json' + // } + // }) + // .then(response => response.json()) + // .then(data => { + // // Update the tables container with the new tables + // const tablesContainer = document.getElementById('show_tables1'); + // tablesContainer.innerHTML = ''; // Clear existing tables + + // data.tables.forEach(table => { + // // Create new elements for each table and append them to the container + // const divOuter = document.createElement('div'); + // divOuter.className = "uk-margin"; + // divOuter.style = "height: 15px; margin-bottom: -4px;"; + + // const divInner = document.createElement('div'); + // divInner.className = "list-group-item-action uk-card uk-card-default uk-card-body uk-card-small"; + // divInner.style = "height: 15px; padding-top: 5px;"; + // divInner.textContent = table; + + // divOuter.appendChild(divInner); + // tablesContainer.appendChild(divOuter); + // }); + // showErdCanvas("erdCanvas1", "zoomInBtn1", "zoomOutBtn1", data.image1 ); + // }) + // .catch(error => console.error('Error:', error)); + // }); + // } + + + // function show_all() { + // document.getElementById('showAllClick').addEventListener('change', function() { + // var showAll = this.checked; // The checkbox is currently checked (true) or unchecked (false) + // fetch('/update-show-all', { + // method: 'POST', + // body: JSON.stringify({ show_all: showAll }), + // headers: { + // 'Content-Type': 'application/json' + // } + // }) + // .then(response => response.json()) + // .then(data => { + // showErdCanvas("erdCanvas1", "zoomInBtn1", "zoomOutBtn1", data.image1 ); + // }) + // .catch(error => console.error('Error:', error)); + // }); + // } + + + + // document.getElementById('resetButton').addEventListener('click', function(event) { + // event.preventDefault(); // Prevent the default form submission + + // // Send a POST request to the server + // fetch('/handle-drop', { + // method: 'POST', + // body: JSON.stringify({'reset': true}), + // headers: { + // 'Content-Type': 'application/json' + // } + // }) + // .then(response => response.json()) + // .then(data => { + // // let tables_list = data['tables']; + // document.getElementById('tables').innerHTML = data.tables; + // // for (let i = 0; i < tables_list.length; i++) { + // // let table = tables_list[i]; + // // let item_inner = document.createElement('div'); + // // item_inner.className = 'ist-group-item-action uk-card uk-card-default uk-card-body uk-card-small'; + // // item_inner.style = "height: 15px; padding-top: 5px;" + // // item_inner.textContent = table; + + // // let item_outer = document.createElement('div'); + // // item_outer.className = 'uk-margin'; + // // item_outer.style = "height: 15px; margin-bottom: -4px;" + // // item_outer.appendChild(item_inner); + + // // document.getElementById('show_tables1').appendChild(item_outer); + // // } + // document.getElementById('dropped_items').innerHTML =data.dropped_items; + // showErdCanvas("erdCanvas2", "zoomInBtn2", "zoomOutBtn2", data.image2); + // showErdCanvas("erdCanvas3", "zoomInBtn3", "zoomOutBtn3", data.image2); + + // }) + // .catch(error => console.error('Error:', error)); + // }); + + // Attach click event listener to each dropped item }); + </script> </body> </html>