diff --git a/my_flask_app/__pycache__/main.cpython-39.pyc b/my_flask_app/__pycache__/main.cpython-39.pyc index 3325cd478eea87c234e99721ffb5d80d466b4250..d4b09b0d9746781714fb499d9d6f9e0daa18e49b 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 9538b70d9fc2a14db135d46fe3dabc68f378c70f..4516f28439fc3dab7bface7b8351b81070169c97 100644 --- a/my_flask_app/main.py +++ b/my_flask_app/main.py @@ -1,3 +1,4 @@ +import pandas as pd from my_flask_app import app from .models.models import CustomTable, CustomColumn, Theme, CompressedDataType, RegType, RegRole from flask_sqlalchemy import SQLAlchemy @@ -6,8 +7,8 @@ from sqlalchemy import ARRAY, BIGINT, BOOLEAN, DOUBLE_PRECISION, FLOAT, INTEGER, import pydot, base64, os, logging from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.dialects.postgresql.base import ischema_names -from sqlalchemy.dialects.postgresql import JSONB, TSTZRANGE, INTERVAL, BYTEA - +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 +from sqlalchemy.dialects.sqlite import JSON, FLOAT, INTEGER, TIMESTAMP, TEXT, BOOLEAN, VARCHAR, NUMERIC, REAL # Set up database (call db.engine) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False @@ -106,6 +107,8 @@ def index(): return f"An error occurred: {str(e)}", 400 + + @app.route('/handle-drop', methods=['POST']) def handle_drop(): data = request.json @@ -166,7 +169,19 @@ def get_table_data(): table_columns = [column.name for column in table_instance.columns] sorted_table_columns = sorted(table_columns) - return jsonify({ 'html_table': html_table, 'table_columns': sorted_table_columns }) + + feature_columns = sorted_table_columns + if check_json_column(engine, table_name) != []: + json_column_names = check_json_column(engine, table_name) + for column_name in json_column_names: + feature_columns.remove(column_name) + jsonKeys = handle_json_column(engine, table_name, column_name) #[('line',), ('coarse', 'fine'), ('name',), ('percent',), ('axisID', 'coarse', 'fine')] + for key in jsonKeys: + feature_columns.append( column_name + str(key) ) if len(key) > 1 else feature_columns.append( column_name + str(key).replace(',', '')) + + + + return jsonify({ 'html_table': html_table, 'table_columns': sorted_table_columns, 'feature_columns': feature_columns }) @app.route('/get-label-column', methods=['POST']) @@ -205,6 +220,45 @@ def add_label(): return jsonify({'defined_labels': self_defined_labels}) +def check_json_column(engine, table_name): + insp = inspect(engine) + schema = getTableSchema(table_name) if insp.dialect.name == 'postgresql' else insp.default_schema_name + json_column_names = [] + + columnList = insp.get_columns(table_name, schema) # List of columns + for column in columnList: # column is a dictionary: {'name': 'machine_id', 'type': INTEGER(), 'nullable': False, 'default': None, 'autoincrement': False, 'comment': None} + column_type = column['type'] + if type(column_type) == JSON or type(column_type) == JSONB: + json_column_names.append(column['name']) + print(json_column_names) + return json_column_names + +def handle_json_column(engine, table_name, column_name): + insp = inspect(engine) + + # Create a connection from the engine + with engine.connect() as conn: + # Prepare the SQL query to fetch a sample JSON object from the specified column + if insp.dialect.name == 'postgresql': + schema = getTableSchema(table_name) + query = f"SELECT DISTINCT {column_name} FROM {schema}.{table_name}" + else: + query = f"SELECT DISTINCT {column_name} FROM {table_name}" + + # Execute the query and fetch the result + result = conn.execute(text(query)).fetchall() + # df = pd.read_sql_query(query, engine) + conn.close() + + jsonKeys = [] + for row in result: + name = tuple(sorted(row[0].keys())) + if name not in jsonKeys: + jsonKeys.append(name) + print(jsonKeys) + return jsonKeys + + def database_name_from_uri(engine, database_uri: str): if engine.dialect.name == 'postgresql': return engine.url.database diff --git a/my_flask_app/templates/app.html b/my_flask_app/templates/app.html index 4c70901437df8dbfea6e5373c16f58cd6649dba7..353e6d59dec7e742581a42dc974b593fd6526839 100644 --- a/my_flask_app/templates/app.html +++ b/my_flask_app/templates/app.html @@ -263,14 +263,12 @@ <div id="collapseOne" class="accordion-collapse collapse" data-bs-parent="#accordionExample"> <div class="accordion-body"> <form method="post"> - <!-- <label> --> - <input class="form-check-input" id="flexCheckDefault" style="margin: 2px 2px 2px 5px; border-color: black;" type="checkbox" name="show_all" value="True" onchange="this.form.submit()" {{ 'checked' if show_all else '' }}> - <!-- <span class="uk-label" style="margin: 1px;" >show all</span> --> - <label class="form-check-label" for="flexCheckDefault" style="margin-top: 3px;"> - Primary Tables - </label> - <!-- </label> --> - <select class="form-select" name="schema" onchange='this.form.submit()' style="padding: 0px 1px 2px 1px;"> + <input class="form-check-input" id="showAllClick" style="margin: 2px 2px 2px 5px; border-color: black;" type="checkbox" name="show_all" value="True" onchange="this.form.submit()"> + <!-- <span class="uk-label" style="margin: 1px;" >show all</span> --> + <label class="form-check-label" for="showAllClick" style="margin-top: 3px;"> + Primary Tables + </label> + <select class="form-select" name="schema" id="schemaSelect" onchange="this.form.submit()" style="padding: 0px 1px 2px 1px;"> <option value="">Choose here</option> {% for schema in schemas %} <option value="{{ schema }}" {% if schema == schema_Selected %} selected {% endif %}>{{ schema }}</option> @@ -451,19 +449,20 @@ <div class="mb-3"> <label class="form-label">Feature</label> - <form method="POST" action = "/get_value_column" name = "chart_options" style="width: 100%; border-color: aqua;"> - <select name = "value_column[]" data-placeholder="Value columns" multiple class="chosen-select" tabindex="8"> - <option value="GB">GB</option> - <option value="RU">RU</option> - {% for value_column in value_columns %} - <option value="{{ value_column }}">{{ value_column }}</option> - {% endfor %} - </select> - - <script> $(".chosen-select").chosen(); </script> - - <button type="submit" class="btn btn-primary">Submit</button> - </form> + <select id="select_features" name = "value_column[]" data-placeholder="Value columns" multiple class="chosen-select" tabindex="8"> + <option value="GB">GB</option> + <option value="RU">RU</option> + <option value="RU">Hey</option> + {% for column in columns %} + <option>Column select...</option> + <option value="{{label}}">{{ label }}</option> + {% endfor %} + </select> + + <script> $(".chosen-select").chosen(); </script> + <br> + <!-- <button type="submit" class="btn btn-primary">Submit</button> --> + </div> <!-- <div class="mb-3"> <div class="form-check"> @@ -530,6 +529,72 @@ <div id="resize-handle-left" class="resize-handle-left"></div> </div> <script> + // 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)); + // }); + // } + function addLabel() { const labelValue = document.getElementById('defined-label').value; // Get the value of the input @@ -682,7 +747,6 @@ // Assign data.table_columns to the select element const selectElement = document.getElementById('select_column'); selectElement.innerHTML = ''; - // Create default option const optionElement = document.createElement('option'); optionElement.value = ''; optionElement.textContent = 'Label column select'; @@ -694,6 +758,20 @@ optionElement.textContent = column; selectElement.appendChild(optionElement); }); + + // Assign data.table_columns to the multi-select element + const selectFeatures = document.getElementById('select_features'); + selectFeatures.innerHTML = ''; + // Add the table columns as options + data.feature_columns.forEach(column => { + const optionElement = document.createElement('option'); + optionElement.value = column; + optionElement.textContent = column; + selectFeatures.appendChild(optionElement); + }); + + // Trigger Chosen to update its view + $(".chosen-select").trigger("chosen:updated"); // toggleTerminal(); // Show the terminal }) @@ -777,7 +855,6 @@ document.addEventListener('DOMContentLoaded', function() { - console.log('DOM is ready'); // Show the ERD canvas showErdCanvas("erdCanvas1", "zoomInBtn1", "zoomOutBtn1", '{{ image1 }}'); showErdCanvas("erdCanvas2", "zoomInBtn2", "zoomOutBtn2", '{{ image2 }}');