datahuborg/datahub

View on GitHub
src/apps/dataq/client_src/js/dq-table-modal.js

Summary

Maintainability
A
1 hr
Test Coverage
/**
 * The modal window that allows the user to select the tables (and columns from these tables) that
 * they want to use in their query.
 *
 * This modal can be used to either ADD a new table (and some of its columns) to the query or to
 * EDIT an existing table (and its columns) that is already in the query.
 *
 * The modal window is a bootstrap modal.
 */
(function() {
  // If the global DataQ object does not exist, create it.
  window.DataQ = window.DataQ || {};

  // The callback to trigger when the modal is closed.
  var cb;

  // The table we have selected.
  var table;

  // The DataQ.Query object being built.
  var query;

  /**
   * Launch the modal.
   *
   * @param q - The DataQ.Query object being built.
   *
   * @param table_name - The name of the table to modify. This must be either null (in which case
   * the "Add Table" modal is displayed), or a table which the current user is associated with.
   *
   * @param callback - The callback that is executed after the user finishes updating selections.
   * It is executed as callback()
   */
  DataQ.TableModal = function(q, table_name, callback) {
    table = table_name;
    cb = callback;
    query = q;

    // If the modal HTML does not exist, add it to the page.
    var modal = $("#dq-table-modal");
    if (modal.length === 0) {
      var html = DataQ.templates['dq-table-modal']({
        "table_name": table
      });
      $('body').append(html);
    }

    // Display the modal (disable Esc and clicking the backdrop to exit modal)
    $('#dq-table-modal').modal({
      keyboard: false
    });

    // Don't allow clicking Done until the user selects a table.
    $(".dq-modal-done-btn").hide();

    // When the modal is shown, populate the columns.
    $("#dq-table-modal").on("shown.bs.modal", function() {
      if (table) {
        populate_column_list(table);
      }
    });

    // Handle modal close when clicking backdrop.
    $(".modal-backdrop").click(function() {
      $("#dq-table-modal").remove();
      $(".modal-backdrop").remove();
      cb();
    })
  };

  // If the user quits, trigger the callback.
  $(document).on('click', '.dq-modal-quit', function() {
    $("#dq-table-modal").remove();
    $(".modal-backdrop").remove();
    cb();
  });


  // If the user clicks the table dropdown, populate the list with the list
  // of available tables.
  $(document).on("click", ".dq-modal-dropdown-btn", function() {
    var dropdown = $(".dq-modal-dropdown");
    dropdown.html("");
    DataQ.API.get_tables(query.repo(), function(data) {
      data.tables.forEach(function(table) {
        var html = DataQ.templates["dq-modal-dropdown-item"]({
          "item_name": table
        });
        dropdown.append(html);
      }); // end foreach
    }) // get_tables
  }); // document on click


  // When a table is selected from the dropdown, create the column list.
  $(document).on("click", ".dq-modal-dropdown-link", function() {
    // Set the content of the dropdown.
    var item_name = $(this).data("item_name");
    table = item_name;
    $('.dq-modal-table-dropdown-text').text(table);
    populate_column_list();
  });

  // Populate the list of columns with the schema of the given table.
  var populate_column_list = function() {
    // Get the schema for the selected tables.
    DataQ.API.get_schema(query.repo(), table, function(data) {
      $(".dq-modal-done-btn").show();

      // Sort the columns by name.
      query.schema(table, data.schema).sort(function(a, b) {return a[0] > b[0]});

      // Create the HTML and add it to the UI.
      var html = DataQ.templates["dq-modal-columns"]({
        "columns": query.schema(table)
      });
      $('.dq-column-list').html(html);

      if (query.selected_columns(table)) {
        // Iterate through the columns for the selected table.
        query.selected_columns(table).forEach(function(column) {
          // Extract the data entries from the element (we find the element by selecting
          // .dq-modal-column[data-columnname="colname"]
          var element = $('.dq-modal-column[data-columnname="'+column.name+'"]');
          element.data("columnname", column.name);
          element.data("columntype", column.type);
          element.data("currentaggregate", column.agg || "none")
          element.find("input[type=checkbox]").prop('checked', true);
          if (column.agg !== "none") {
            element.find("button").text(column.agg + "(" + column.name + ")");
          }
        }); // end forEach
      } // if selected columns
    });
  };

  // Handle column aggregate trigger.
  $(document).on("click", ".dq-modal-column button", function() {
    // Extract the data entries.
    var parent_li = $(this).parent();
    var columnname = parent_li.data("columnname");
    var columntype = parent_li.data("columntype");
    var currentaggregate = parent_li.data("currentaggregate")

    // Compute the next aggregate operator to apply.
    var nextaggregate = DataQ.next_aggregate(columntype, currentaggregate);

    // If an aggregate has already been applied, don't apply another.
    if (query.operated_column() !== table + "." + columnname && query.operated_column() !== null) {
      nextaggregate = "none";
    }

    // If the aggregate has been turned off, turn off the operated column.
    // Else if this is the new operated column, indicate so.
    if (nextaggregate === "none") {
      if (query.operated_column() === table + "." + columnname) {
        query.operated_column(null);
      }
      $(this).text(columnname);
    } else {
      $(this).text(nextaggregate + "(" + columnname + ")");
      query.operated_column(table + "." + columnname);
    }
    parent_li.data("currentaggregate", nextaggregate);
  });

  // When this is clicked, return the selected columns.
  $(document).on("click", ".dq-modal-done-btn", function() {
    // Figure out the selected columns.
    var columns = [];
    var is_op_col_checked = false;

    // Iterate through each of the columns.
    $('.dq-modal-column').each(function() {
      var li = $(this);

      // If the column is checked.
      if (li.find("input").is(":checked")) {

        // Extract the data entries.
        var agg = li.data("currentaggregate");
        var type = li.data("columntype");
        var name = li.data("columnname");

        // If the operated column has been selected, then mark it so.
        if (table + "." + name === query.operated_column()) {
          is_op_col_checked = true;
        }

        if (agg === null || agg === undefined) {
          agg = "none";
        }

        columns.push({
          "name": name,
          "type": type,
          "agg": agg
        });

      }
    });

    // If the operated column should be in this table and has not been selected,
    // set the operated column as null.
    if (query.operated_column() &&
        query.operated_column().split(".")[0] === table &&
        !is_op_col_checked) {
      query.operated_column(null);
    }

    // Mark the selected columns for this table, and recompute the tables.
    query.selected_columns(table, columns);
    query.update_grouping();

    // Remove the modals from the page.
    $("#dq-table-modal").remove();
    $(".modal-backdrop").remove();
    cb();
  });

})();