pgweb/static/js/app.js
Dan Sosedoff 6025b7afb2 Remove double click action on cell
This feature was a source of confusion for new pgweb users for quite
some time now. Most people thought by double-clicking the cell it
would allow them to edit the value since the column is replaced
with textarea. The textarea was there to copy the cell's value, not
for editing. Feature is no longer required due to availability of a
cell context menu, which provides a link to copy the value.
2020-02-12 13:14:58 -06:00

1475 lines
38 KiB
JavaScript

var editor = null;
var connected = false;
var bookmarks = {};
var default_rows_limit = 100;
var currentObject = null;
var autocompleteObjects = [];
var filterOptions = {
"equal": "= 'DATA'",
"not_equal": "!= 'DATA'",
"greater": "> 'DATA'" ,
"greater_eq": ">= 'DATA'",
"less": "< 'DATA'",
"less_eq": "<= 'DATA'",
"like": "LIKE 'DATA'",
"ilike": "ILIKE 'DATA'",
"null": "IS NULL",
"not_null": "IS NOT NULL"
};
function getSessionId() {
var id = sessionStorage.getItem("session_id");
if (!id) {
id = guid();
sessionStorage.setItem("session_id", id);
}
return id;
}
function setRowsLimit(num) {
localStorage.setItem("rows_limit", num);
}
function getRowsLimit() {
return parseInt(localStorage.getItem("rows_limit") || default_rows_limit);
}
function getPaginationOffset() {
var page = $(".current-page").data("page");
var limit = getRowsLimit();
return (page - 1) * limit;
}
function getPagesCount(rowsCount) {
var limit = getRowsLimit();
var num = parseInt(rowsCount / limit);
if ((num * limit) < rowsCount) {
num++;
}
return num;
}
function apiCall(method, path, params, cb) {
var timeout = 300000; // 5 mins is enough
$.ajax({
timeout: timeout,
url: "api" + path,
method: method,
cache: false,
data: params,
headers: {
"x-session-id": getSessionId()
},
success: function(data) {
cb(data);
},
error: function(xhr, status, data) {
if (status == "timeout") {
return cb({ error: "Query timeout after " + (timeout / 1000) + "s" });
}
cb(jQuery.parseJSON(xhr.responseText));
}
});
}
function getInfo(cb) { apiCall("get", "/info", {}, cb); }
function getObjects(cb) { apiCall("get", "/objects", {}, cb); }
function getTables(cb) { apiCall("get", "/tables", {}, cb); }
function getTableRows(table, opts, cb) { apiCall("get", "/tables/" + table + "/rows", opts, cb); }
function getTableStructure(table, opts, cb) { apiCall("get", "/tables/" + table, opts, cb); }
function getTableIndexes(table, cb) { apiCall("get", "/tables/" + table + "/indexes", {}, cb); }
function getTableConstraints(table, cb) { apiCall("get", "/tables/" + table + "/constraints", {}, cb); }
function getHistory(cb) { apiCall("get", "/history", {}, cb); }
function getBookmarks(cb) { apiCall("get", "/bookmarks", {}, cb); }
function executeQuery(query, cb) { apiCall("post", "/query", { query: query }, cb); }
function explainQuery(query, cb) { apiCall("post", "/explain", { query: query }, cb); }
function disconnect(cb) { apiCall("post", "/disconnect", {}, cb); }
function encodeQuery(query) {
return Base64.encode(query).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ".");
}
function buildSchemaSection(name, objects) {
var section = "";
var titles = {
"table": "Tables",
"view": "Views",
"materialized_view": "Materialized Views",
"sequence": "Sequences"
};
var icons = {
"table": '<i class="fa fa-table"></i>',
"view": '<i class="fa fa-table"></i>',
"materialized_view": '<i class="fa fa-table"></i>',
"sequence": '<i class="fa fa-circle-o"></i>'
};
var klass = "";
if (name == "public") klass = "expanded";
section += "<div class='schema " + klass + "'>";
section += "<div class='schema-name'><i class='fa fa-folder-o'></i><i class='fa fa-folder-open-o'></i> " + name + "</div>";
section += "<div class='schema-container'>";
["table", "view", "materialized_view", "sequence"].forEach(function(group) {
group_klass = "";
if (name == "public" && group == "table") group_klass = "expanded";
section += "<div class='schema-group " + group_klass + "'>";
section += "<div class='schema-group-title'><i class='fa fa-chevron-right'></i><i class='fa fa-chevron-down'></i> " + titles[group] + " <span class='schema-group-count'>" + objects[group].length + "</span></div>";
section += "<ul data-group='" + group + "'>";
if (objects[group]) {
objects[group].forEach(function(item) {
var id = name + "." + item;
section += "<li class='schema-item schema-" + group + "' data-type='" + group + "' data-id='" + id + "' data-name='" + item + "'>" + icons[group] + "&nbsp;" + item + "</li>";
});
section += "</ul></div>";
}
});
section += "</div></div>";
return section;
}
function loadSchemas() {
$("#objects").html("");
getObjects(function(data) {
if (Object.keys(data).length == 0) {
data["public"] = {
table: [],
view: [],
materialized_view: [],
sequence: []
};
}
for (schema in data) {
$(buildSchemaSection(schema, data[schema])).appendTo("#objects");
}
if (Object.keys(data).length == 1) {
$(".schema").addClass("expanded");
}
// Clear out all autocomplete objects
autocompleteObjects = [];
for (schema in data) {
for (kind in data[schema]) {
if (!(kind == "table" || kind == "view" || kind == "materialized_view")) {
continue
}
for (item in data[schema][kind]) {
autocompleteObjects.push({
caption: data[schema][kind][item],
value: data[schema][kind][item],
meta: kind
});
}
}
}
bindContextMenus();
});
}
function escapeHtml(str) {
if (str != null || str != undefined) {
return jQuery("<div/>").text(str).html();
}
return "<span class='null'>null</span>";
}
function unescapeHtml(str){
var e = document.createElement("div");
e.innerHTML = str;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
function getCurrentObject() {
return currentObject || { name: "", type: "" };
}
function resetTable() {
$("#results").
data("mode", "").
removeClass("empty").
removeClass("no-crop");
$("#results_header").html("");
$("#results_body").html("");
}
function performTableAction(table, action, el) {
if (action == "truncate" || action == "delete") {
var message = "Are you sure you want to " + action + " table " + table + " ?";
if (!confirm(message)) return;
}
switch(action) {
case "truncate":
executeQuery("TRUNCATE TABLE " + table, function(data) {
if (data.error) alert(data.error);
resetTable();
});
break;
case "delete":
executeQuery("DROP TABLE " + table, function(data) {
if (data.error) alert(data.error);
loadSchemas();
resetTable();
});
break;
case "export":
var format = el.data("format");
var db = $("#current_database").text();
var filename = db + "." + table + "." + format;
var query = window.encodeURI("SELECT * FROM " + table);
var url = window.location.href.split("#")[0] + "api/query?format=" + format + "&filename=" + filename + "&query=" + query + "&_session_id=" + getSessionId();
var win = window.open(url, "_blank");
win.focus();
break;
case "dump":
var url = window.location.href.split("#")[0] + "api/export?table=" + table + "&_session_id=" + getSessionId();
var win = window.open(url, "_blank");
win.focus();
break;
case "copy":
copyToClipboard(table.split('.')[1]);
break;
}
}
function performViewAction(view, action, el) {
if (action == "delete") {
var message = "Are you sure you want to " + action + " view " + view + " ?";
if (!confirm(message)) return;
}
switch(action) {
case "delete":
executeQuery("DROP VIEW " + view, function(data) {
if (data.error) alert(data.error);
loadSchemas();
resetTable();
});
break;
case "export":
var format = el.data("format");
var db = $("#current_database").text();
var filename = db + "." + view + "." + format;
var query = window.encodeURI("SELECT * FROM " + view);
var url = window.location.href.split("#")[0] + "api/query?format=" + format + "&filename=" + filename + "&query=" + query + "&_session_id=" + getSessionId();
var win = window.open(url, "_blank");
win.focus();
break;
case "copy":
copyToClipboard(view.split('.')[1]);
break;
}
}
function performRowAction(action, value) {
if (action == "stop_query") {
if (!confirm("Are you sure you want to stop the query?")) return;
executeQuery("SELECT pg_cancel_backend(" + value + ");", function(data) {
if (data.error) alert(data.error);
setTimeout(showActivityPanel, 1000);
});
}
}
function sortArrow(direction) {
switch (direction) {
case "ASC":
return "&#x25B2;";
case "DESC":
return "&#x25BC;";
default:
return "";
}
}
function buildTable(results, sortColumn, sortOrder, options) {
if (!options) options = {};
var action = options.action;
resetTable();
if (results.error) {
$("#results_header").html("");
$("#results_body").html("<tr><td>ERROR: " + results.error + "</tr></tr>");
return;
}
if (results.rows.length == 0) {
$("#results_header").html("");
$("#results_body").html("<tr><td>No records found</td></tr>");
$("#result-rows-count").html("");
$("#results").addClass("empty");
return;
}
var cols = "";
var rows = "";
results.columns.forEach(function(col) {
if (col === sortColumn) {
cols += "<th class='table-header-col active' data-name='" + col + "'" + "data-order=" + sortOrder + ">" + col + "&nbsp;" + sortArrow(sortOrder) + "</th>";
}
else {
cols += "<th class='table-header-col' data-name='" + col + "'>" + col + "</th>";
}
});
// No header to make the column non-sortable
if (action) {
cols += "<th></th>";
// Determine which column contains the data attribute
action.dataColumn = results.columns.indexOf(action.data);
}
results.rows.forEach(function(row) {
var r = "";
// Add all actual row data here
for (i in row) {
r += "<td data-col='" + i + "'><div>" + escapeHtml(row[i]) + "</div></td>";
}
// Add row action button
if (action) {
r += "<td><a class='btn btn-xs btn-" + action.style + " row-action' data-action='" + action.name + "' data-value='" + row[action.dataColumn] + "' href='#'>" + action.title + "</a></td>";
}
rows += "<tr>" + r + "</tr>";
});
$("#results_header").html(cols);
$("#results_body").html(rows);
// Show number of rows rendered on the page
$("#result-rows-count").html(results.rows.length + " rows");
}
function setCurrentTab(id) {
// Pagination should only be visible on rows tab
if (id != "table_content") {
$("#body").removeClass("with-pagination");
}
$("#nav ul li.selected").removeClass("selected");
$("#" + id).addClass("selected");
// Persist tab selection into the session storage
sessionStorage.setItem("tab", id);
}
function showQueryHistory() {
getHistory(function(data) {
var rows = [];
for(i in data) {
rows.unshift([parseInt(i) + 1, data[i].query, data[i].timestamp]);
}
buildTable({ columns: ["id", "query", "timestamp"], rows: rows });
setCurrentTab("table_history");
$("#input").hide();
$("#body").prop("class", "full");
$("#results").addClass("no-crop");
});
}
function showTableIndexes() {
var name = getCurrentObject().name;
if (name.length == 0) {
alert("Please select a table!");
return;
}
getTableIndexes(name, function(data) {
setCurrentTab("table_indexes");
buildTable(data);
$("#input").hide();
$("#body").prop("class", "full");
$("#results").addClass("no-crop");
});
}
function showTableConstraints() {
var name = getCurrentObject().name;
if (name.length == 0) {
alert("Please select a table!");
return;
}
getTableConstraints(name, function(data) {
setCurrentTab("table_constraints");
buildTable(data);
$("#input").hide();
$("#body").prop("class", "full");
$("#results").addClass("no-crop");
});
}
function showTableInfo() {
var name = getCurrentObject().name;
if (name.length == 0) {
alert("Please select a table!");
return;
}
apiCall("get", "/tables/" + name + "/info", {}, function(data) {
$(".table-information .lines").show();
$("#table_total_size").text(data.total_size);
$("#table_data_size").text(data.data_size);
$("#table_index_size").text(data.index_size);
$("#table_rows_count").text(data.rows_count);
$("#table_encoding").text("Unknown");
});
buildTableFilters(name, getCurrentObject().type);
}
function updatePaginator(pagination) {
if (!pagination) {
$(".current-page").data("page", 1).data("pages", 1);
$("button.page").text("1 of 1");
$(".prev-page, .next-page").prop("disabled", "disabled");
return;
}
$(".current-page").
data("page", pagination.page).
data("pages", pagination.pages_count);
if (pagination.page > 1) {
$(".prev-page").prop("disabled", "");
}
else {
$(".prev-page").prop("disabled", "disabled");
}
if (pagination.pages_count > 1 && pagination.page < pagination.pages_count) {
$(".next-page").prop("disabled", "");
}
else {
$(".next-page").prop("disabled", "disabled");
}
$("#total_records").text(pagination.rows_count);
if (pagination.pages_count == 0) pagination.pages_count = 1;
$("button.page").text(pagination.page + " of " + pagination.pages_count);
}
function showTableContent(sortColumn, sortOrder) {
var name = getCurrentObject().name;
if (name.length == 0) {
alert("Please select a table!");
return;
}
var opts = {
limit: getRowsLimit(),
offset: getPaginationOffset(),
sort_column: sortColumn,
sort_order: sortOrder
};
var filter = {
column: $(".filters select.column").val(),
op: $(".filters select.filter").val(),
input: $(".filters input").val()
};
// Apply filtering only if column is selected
if (filter.column && filter.op) {
var where = [
'"' + filter.column + '"',
filterOptions[filter.op].replace("DATA", filter.input)
].join(" ");
opts["where"] = where;
}
getTableRows(name, opts, function(data) {
$("#input").hide();
$("#body").prop("class", "with-pagination");
buildTable(data, sortColumn, sortOrder);
setCurrentTab("table_content");
updatePaginator(data.pagination);
$("#results").data("mode", "browse").data("table", name);
});
}
function showPaginatedTableContent() {
var activeColumn = $("#results th.active");
var sortColumn = null;
var sortOrder = null;
if (activeColumn.length) {
sortColumn = activeColumn.data("name");
sortOrder = activeColumn.data("order");
}
showTableContent(sortColumn, sortOrder);
}
function showTableStructure() {
var name = getCurrentObject().name;
if (name.length == 0) {
alert("Please select a table!");
return;
}
setCurrentTab("table_structure");
$("#input").hide();
$("#body").prop("class", "full");
getTableStructure(name, { type: getCurrentObject().type }, function(data) {
buildTable(data);
$("#results").addClass("no-crop");
});
}
function showQueryPanel() {
if (!$("#table_query").hasClass("selected")) {
resetTable();
}
setCurrentTab("table_query");
editor.focus();
$("#input").show();
$("#body").prop("class", "")
}
function showConnectionPanel() {
setCurrentTab("table_connection");
apiCall("get", "/connection", {}, function(data) {
var rows = [];
for(key in data) {
rows.push([key, data[key]]);
}
buildTable({
columns: ["attribute", "value"],
rows: rows
});
$("#input").hide();
$("#body").addClass("full");
});
}
function showActivityPanel() {
var options = {
action: {
name: "stop_query",
title: "stop",
data: "pid",
style: "danger"
}
}
setCurrentTab("table_activity");
apiCall("get", "/activity", {}, function(data) {
buildTable(data, null, null, options);
$("#input").hide();
$("#body").addClass("full");
});
}
function runQuery() {
setCurrentTab("table_query");
$("#run, #explain, #csv, #json, #xml").prop("disabled", true);
$("#query_progress").show();
var query = $.trim(editor.getSelectedText() || editor.getValue());
if (query.length == 0) {
$("#run, #explain, #csv, #json, #xml").prop("disabled", false);
$("#query_progress").hide();
return;
}
executeQuery(query, function(data) {
buildTable(data);
$("#run, #explain, #csv, #json, #xml").prop("disabled", false);
$("#query_progress").hide();
$("#input").show();
$("#body").removeClass("full");
$("#results").data("mode", "query");
if (query.toLowerCase().indexOf("explain") != -1) {
$("#results").addClass("no-crop");
}
// Reload objects list if anything was created/deleted
if (query.match(/(create|drop)\s/i)) {
loadSchemas();
}
});
}
function runExplain() {
setCurrentTab("table_query");
$("#run, #explain, #csv, #json, #xml").prop("disabled", true);
$("#query_progress").show();
var query = $.trim(editor.getSelectedText() || editor.getValue());
if (query.length == 0) {
$("#run, #explain, #csv, #json, #xml").prop("disabled", false);
$("#query_progress").hide();
return;
}
explainQuery(query, function(data) {
buildTable(data);
$("#run, #explain, #csv, #json, #xml").prop("disabled", false);
$("#query_progress").hide();
$("#input").show();
$("#body").removeClass("full");
$("#results").addClass("no-crop");
});
}
function exportTo(format) {
var query = $.trim(editor.getSelectedText() || editor.getValue());
if (query.length == 0) {
return;
}
var url = window.location.href.split("#")[0] + "api/query?format=" + format + "&query=" + encodeQuery(query) + "&_session_id=" + getSessionId();
var win = window.open(url, '_blank');
setCurrentTab("table_query");
win.focus();
}
// Fetch all unique values for the selected column in the table
function showUniqueColumnsValues(table, column, showCounts) {
var query = 'SELECT DISTINCT "' + column + '" FROM ' + table;
// Display results ordered by counts.
// This could be slow on large sets without an index.
if (showCounts) {
query = 'SELECT DISTINCT "' + column + '", COUNT(1) AS total_count FROM ' + table + ' GROUP BY "' + column + '" ORDER BY total_count DESC';
}
executeQuery(query, function(data) {
$("#input").hide();
$("#body").prop("class", "full");
$("#results").data("mode", "query");
buildTable(data);
});
}
// Show numeric stats on the field
function showFieldNumStats(table, column) {
var query = 'SELECT count(1), min(' + column + '), max(' + column + '), avg(' + column + ') FROM ' + table;
executeQuery(query, function(data) {
$("#input").hide();
$("#body").prop("class", "full");
$("#results").data("mode", "query");
buildTable(data);
});
}
function buildTableFilters(name, type) {
getTableStructure(name, { type: type }, function(data) {
if (data.rows.length == 0) {
$("#pagination .filters").hide();
}
else {
$("#pagination .filters").show();
}
$("#pagination select.column").html("<option value='' selected>Select column</option>");
for (var i = 0; i < data.rows.length; i++) {
var row = data.rows[i];
var el = $("<option/>").attr("value", row[0]).text(row[0]);
$("#pagination select.column").append(el);
}
});
}
var objectAutocompleter = {
getCompletions: function (editor, session, pos, prefix, callback) {
callback(null, autocompleteObjects);
}
}
function initEditor() {
var writeQueryTimeout = null;
editor = ace.edit("custom_query");
editor.setOptions({
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
});
editor.completers.push(objectAutocompleter);
editor.setFontSize(13);
editor.setTheme("ace/theme/tomorrow");
editor.setShowPrintMargin(false);
editor.getSession().setMode("ace/mode/pgsql");
editor.getSession().setTabSize(2);
editor.getSession().setUseSoftTabs(true);
editor.commands.addCommands([{
name: "run_query",
bindKey: {
win: "Ctrl-Enter",
mac: "Command-Enter"
},
exec: function(editor) {
runQuery();
}
}, {
name: "explain_query",
bindKey: {
win: "Ctrl-E",
mac: "Command-E"
},
exec: function(editor) {
runExplain();
}
}]);
editor.on("change", function() {
if (writeQueryTimeout) {
clearTimeout(writeQueryTimeout);
}
writeQueryTimeout = setTimeout(function() {
localStorage.setItem("pgweb_query", editor.getValue());
}, 1000);
});
var query = localStorage.getItem("pgweb_query");
if (query && query.length > 0) {
editor.setValue(query);
editor.clearSelection();
}
}
function addShortcutTooltips() {
if (navigator.userAgent.indexOf("OS X") > 0) {
$("#run").attr("title", "Shortcut: ⌘+Enter");
$("#explain").attr("title", "Shortcut: ⌘+E");
}
else {
$("#run").attr("title", "Shortcut: Ctrl+Enter");
$("#explain").attr("title", "Shortcut: Ctrl+E");
}
}
// Get the latest release from Github API
function getLatestReleaseInfo(current) {
try {
$.get("https://api.github.com/repos/sosedoff/pgweb/releases/latest", function(release) {
if (release.name != current.version) {
var message = "Update available. Check out " + release.tag_name + " on <a target='_blank' href='" + release.html_url + "'>Github</a>";
$(".connection-settings .update").html(message).fadeIn();
}
});
}
catch(error) {
console.log("Cant get last release from github:", error);
}
}
function showConnectionSettings() {
// Fetch server info
getInfo(function(data) {
if (data.error) return;
if (!data.version) return;
// Show the current postgres version
$(".connection-settings .version").text("v" + data.version).show();
// Check for updates if running the actual release from Github
if (data.git_sha == "") {
getLatestReleaseInfo(data);
}
});
getBookmarks(function(data) {
// Do not add any bookmarks if we've got an error
if (data.error) {
return;
}
if (Object.keys(data).length > 0) {
// Set bookmarks in global var
bookmarks = data;
// Remove all existing bookmark options
$("#connection_bookmarks").html("");
// Add blank option
$("<option value=''></option>").appendTo("#connection_bookmarks");
// Add all available bookmarks
for (key in data) {
$("<option value='" + key + "''>" + key + "</option>").appendTo("#connection_bookmarks");
}
$(".bookmarks").show();
}
else {
$(".bookmarks").hide();
}
});
$("#connection_window").show();
}
function getConnectionString() {
var url = $.trim($("#connection_url").val());
var mode = $(".connection-group-switch button.active").attr("data");
var ssl = $("#connection_ssl").val();
if (mode == "standard" || mode == "ssh") {
var host = $("#pg_host").val();
var port = $("#pg_port").val();
var user = $("#pg_user").val();
var pass = encodeURIComponent($("#pg_password").val());
var db = $("#pg_db").val();
if (port.length == 0) {
port = "5432";
}
url = "postgres://" + user + ":" + pass + "@" + host + ":" + port + "/" + db + "?sslmode=" + ssl;
}
else {
var local = url.indexOf("localhost") != -1 || url.indexOf("127.0.0.1") != -1;
if (local && url.indexOf("sslmode") == -1) {
url += "?sslmode=" + ssl;
}
}
return url;
}
// Add a context menu to the results table header columns
function bindTableHeaderMenu() {
$("#results_header").contextmenu({
scopes: "th",
target: "#results_header_menu",
before: function(e, element, target) {
// Enable menu for browsing table rows view only.
if ($("#results").data("mode") != "browse") {
e.preventDefault();
this.closemenu();
return false;
}
},
onItem: function(context, e) {
var menuItem = $(e.target);
switch(menuItem.data("action")) {
case "copy_name":
copyToClipboard($(context).data("name"));
break;
case "unique_values":
showUniqueColumnsValues(
$("#results").data("table"), // table name
$(context).data("name"), // column name
menuItem.data("counts") // display counts
);
break;
case "num_stats":
showFieldNumStats(
$("#results").data("table"), // table name
$(context).data("name") // column name
);
break;
}
}
});
$("#results_body").contextmenu({
scopes: "td",
target: "#results_row_menu",
before: function(e, element, target) {
var isEmpty = $("#results").hasClass("empty");
var isBrowsing = $("#results").data("mode") == "browse";
if (isEmpty || !isBrowsing) {
e.preventDefault();
this.closemenu();
return false;
}
},
onItem: function(context, e) {
var menuItem = $(e.target);
switch(menuItem.data("action")) {
case "copy_value":
copyToClipboard($(context).text());
break;
case "filter_by_value":
var colIdx = $(context).data("col");
var colValue = $(context).text();
var colName = $("#results_header th").eq(colIdx).data("name");
$("select.column").val(colName);
$("select.filter").val("equal");
$("#table_filter_value").val(colValue);
$("#rows_filter").submit();
}
}
});
}
function bindCurrentDatabaseMenu() {
$("#current_database").contextmenu({
target: "#current_database_context_menu",
onItem: function(context, e) {
var menuItem = $(e.target);
switch(menuItem.data("action")) {
case "export":
var url = window.location.href.split("#")[0] + "api/export?_session_id=" + getSessionId();
var win = window.open(url, "_blank");
win.focus();
break;
}
}
});
}
function bindDatabaseObjectsFilter() {
var filterTimeout = null;
$("#filter_database_objects").on("keyup", function (e) {
clearTimeout(filterTimeout);
var val = $(this).val().trim();
// Reset search on ESC
if (e.keyCode == 27 || val == "") {
resetObjectsFilter();
return;
}
$(".clear-objects-filter").show();
$(".schema-group").addClass("expanded");
filterTimeout = setTimeout(function () {
filterObjectsByName(val)
}, 200);
});
$(".clear-objects-filter").on("click", function(e) {
resetObjectsFilter();
});
}
function resetObjectsFilter() {
$("#filter_database_objects").val("");
$("#objects li.schema-item").show();
$(".clear-objects-filter").hide();
}
function filterObjectsByName(query) {
$("#objects li.schema-item").each(function (idx, el) {
var item = $(el);
var name = $(el).data("name");
if (name.indexOf(query) < 0) {
item.hide();
} else {
item.show();
}
});
}
function getQuotedSchemaTableName(table) {
if (typeof table === "string" && table.indexOf(".") > -1) {
var schemaTableComponents = table.split(".");
return ['"', schemaTableComponents[0], '"."', schemaTableComponents[1], '"'].join('');
}
return table;
}
function bindContextMenus() {
bindTableHeaderMenu();
bindCurrentDatabaseMenu();
$(".schema-group ul").each(function(id, el) {
var group = $(el).data("group");
if (group == "table") {
$(el).contextmenu({
target: "#tables_context_menu",
scopes: "li.schema-table",
onItem: function(context, e) {
var el = $(e.target);
var table = getQuotedSchemaTableName($(context[0]).data("id"));
var action = el.data("action");
performTableAction(table, action, el);
}
});
}
if (group == "view") {
$(el).contextmenu({
target: "#view_context_menu",
scopes: "li.schema-view",
onItem: function(context, e) {
var el = $(e.target);
var table = getQuotedSchemaTableName($(context[0]).data("id"));
var action = el.data("action");
performViewAction(table, action, el);
}
});
}
});
}
function toggleDatabaseSearch() {
$("#current_database").toggle();
$("#database_search").toggle();
}
function enableDatabaseSearch(data) {
var input = $("#database_search");
input.typeahead("destroy");
input.typeahead({
source: data,
minLength: 0,
items: "all",
autoSelect: false,
fitToElement: true
});
input.typeahead("lookup").focus();
input.on("focusout", function(e){
toggleDatabaseSearch();
input.off("focusout");
});
}
$(document).ready(function() {
$("#table_content").on("click", function() { showTableContent(); });
$("#table_structure").on("click", function() { showTableStructure(); });
$("#table_indexes").on("click", function() { showTableIndexes(); });
$("#table_constraints").on("click", function() { showTableConstraints(); });
$("#table_history").on("click", function() { showQueryHistory(); });
$("#table_query").on("click", function() { showQueryPanel(); });
$("#table_connection").on("click", function() { showConnectionPanel(); });
$("#table_activity").on("click", function() { showActivityPanel(); });
$("#run").on("click", function() {
runQuery();
});
$("#explain").on("click", function() {
runExplain();
});
$("#csv").on("click", function() {
exportTo("csv");
});
$("#json").on("click", function() {
exportTo("json");
});
$("#xml").on("click", function() {
exportTo("xml");
});
$("#results").on("click", "tr", function(e) {
$("#results tr.selected").removeClass();
$(this).addClass("selected");
});
$("#objects").on("click", ".schema-group-title", function(e) {
$(this).parent().toggleClass("expanded");
});
$("#objects").on("click", ".schema-name", function(e) {
$(this).parent().toggleClass("expanded");
});
$("#objects").on("click", "li", function(e) {
currentObject = {
name: $(this).data("id"),
type: $(this).data("type")
};
$("#objects li").removeClass("active");
$(this).addClass("active");
$(".current-page").data("page", 1);
$(".filters select, .filters input").val("");
showTableInfo();
switch(sessionStorage.getItem("tab")) {
case "table_content":
showTableContent();
break;
case "table_structure":
showTableStructure();
break;
case "table_constraints":
showTableConstraints();
break;
case "table_indexes":
showTableIndexes();
break;
default:
showTableContent();
}
});
$("#results").on("click", "a.row-action", function(e) {
e.preventDefault();
var action = $(this).data("action");
var value = $(this).data("value");
performRowAction(action, value);
})
$("#results").on("click", "th", function(e) {
if (!$("#table_content").hasClass("selected")) return;
var sortColumn = $(this).data("name");
var sortOrder = $(this).data("order") === "ASC" ? "DESC" : "ASC";
$(this).data("order", sortOrder);
showTableContent(sortColumn, sortOrder);
});
$("#refresh_tables").on("click", function() {
loadSchemas();
});
$("#rows_filter").on("submit", function(e) {
e.preventDefault();
$(".current-page").data("page", 1);
var column = $(this).find("select.column").val();
var filter = $(this).find("select.filter").val();
var query = $.trim($(this).find("input").val());
if (filter && filterOptions[filter].indexOf("DATA") > 0 && query == "") {
alert("Please specify filter query");
return
}
showTableContent();
});
$(".change-limit").on("click", function() {
var limit = prompt("Please specify a new rows limit", getRowsLimit());
if (limit && limit >= 1) {
$(".current-page").data("page", 1);
setRowsLimit(limit);
showTableContent();
}
});
$("select.filter").on("change", function(e) {
var val = $(this).val();
if (["null", "not_null"].indexOf(val) >= 0) {
$(".filters input").hide().val("");
}
else {
$(".filters input").show();
}
});
$("button.reset-filters").on("click", function() {
$(".filters select, .filters input").val("");
showTableContent();
});
// Automatically prefill the filter if it's not set yet
$("select.column").on("change", function() {
if ($("select.filter").val() == "") {
$("select.filter").val("equal");
$("#table_filter_value").focus();
}
});
$("#pagination .next-page").on("click", function() {
var current = $(".current-page").data("page");
var total = $(".current-page").data("pages");
if (total > current) {
$(".current-page").data("page", current + 1);
showPaginatedTableContent();
if (current + 1 == total) {
$(this).prop("disabled", "disabled");
}
}
if (current > 1) {
$(".prev-page").prop("disabled", "");
}
});
$("#pagination .prev-page").on("click", function() {
var current = $(".current-page").data("page");
if (current > 1) {
$(".current-page").data("page", current - 1);
$(".next-page").prop("disabled", "");
showPaginatedTableContent();
}
if (current == 1) {
$(this).prop("disabled", "disabled");
}
});
$("#current_database").on("click", function(e) {
apiCall("get", "/databases", {}, function(resp) {
toggleDatabaseSearch();
enableDatabaseSearch(resp);
});
});
$("#database_search").change(function(e) {
var current = $("#database_search").typeahead("getActive");
if (current && current == $("#database_search").val()) {
apiCall("post", "/switchdb", { db: current }, function(resp) {
if (resp.error) {
alert(resp.error);
return;
};
window.location.reload();
});
};
});
$("#edit_connection").on("click", function() {
if (connected) {
$("#close_connection_window").show();
}
showConnectionSettings();
});
$("#close_connection").on("click", function() {
if (!confirm("Are you sure you want to disconnect?")) return;
disconnect(function() {
showConnectionSettings();
resetTable();
$("#close_connection_window").hide();
});
});
$("#close_connection_window").on("click", function() {
$("#connection_window").hide();
});
$("#connection_url").on("change", function() {
if ($(this).val().indexOf("localhost") != -1) {
$("#connection_ssl").val("disable");
}
});
$("#pg_host").on("change", function() {
var value = $(this).val();
if (value.indexOf("localhost") != -1 || value.indexOf("127.0.0.1") != -1) {
$("#connection_ssl").val("disable");
}
});
$(".connection-group-switch button").on("click", function() {
$(".connection-group-switch button").removeClass("active");
$(this).addClass("active");
switch($(this).attr("data")) {
case "scheme":
$(".connection-scheme-group").show();
$(".connection-standard-group").hide();
$(".connection-ssh-group").hide();
return;
case "standard":
$(".connection-scheme-group").hide();
$(".connection-standard-group").show();
$(".connection-ssh-group").hide();
return;
case "ssh":
$(".connection-scheme-group").hide();
$(".connection-standard-group").show();
$(".connection-ssh-group").show();
return;
}
});
$("#connection_bookmarks").on("change", function(e) {
var name = $.trim($(this).val());
if (name == "") return;
var item = bookmarks[name];
// Check if bookmark only has url set
if (item.url && item.url != "") {
$("#connection_url").val(item.url);
$("#connection_scheme").click();
return;
}
// Fill in bookmarked connection settings
$("#pg_host").val(item.host);
$("#pg_port").val(item.port);
$("#pg_user").val(item.user);
$("#pg_password").val(item.password);
$("#pg_db").val(item.database);
$("#connection_ssl").val(item.ssl);
if (item.ssh && Object.keys(item.ssh).length > 0) {
$("#ssh_host").val(item.ssh.host);
$("#ssh_port").val(item.ssh.port);
$("#ssh_user").val(item.ssh.user);
$("#ssh_password").val(item.ssh.password);
$("#ssh_key").val(item.ssh.key);
$("#ssh_key_password").val(item.ssh.keypassword);
$("#connection_ssh").click();
}
else {
$("#ssh_host").val("");
$("#ssh_port").val("");
$("#ssh_user").val("");
$("#ssh_password").val("");
$("#ssh_key").val("");
$("#ssh_key_password").val("");
$(".connection-ssh-group").hide();
$("#connection_standard").click();
}
});
$("#connection_form").on("submit", function(e) {
e.preventDefault();
var button = $(this).find("button.open-connection");
var params = {
url: getConnectionString()
};
if (params.url.length == 0) {
return;
}
if ($(".connection-group-switch button.active").attr("data") == "ssh") {
params["ssh"] = 1
params["ssh_host"] = $("#ssh_host").val();
params["ssh_port"] = $("#ssh_port").val();
params["ssh_user"] = $("#ssh_user").val();
params["ssh_password"] = $("#ssh_password").val();
params["ssh_key"] = $("#ssh_key").val();
params["ssh_key_password"] = $("#ssh_key_password").val()
}
$("#connection_error").hide();
button.prop("disabled", true).text("Please wait...");
apiCall("post", "/connect", params, function(resp) {
button.prop("disabled", false).text("Connect");
if (resp.error) {
connected = false;
$("#connection_error").text(resp.error).show();
}
else {
connected = true;
loadSchemas();
$("#connection_window").hide();
$("#current_database").text(resp.current_database);
$("#main").show();
}
});
});
initEditor();
addShortcutTooltips();
// Set session from the url
var reqUrl = new URL(window.location);
var sessionId = reqUrl.searchParams.get("session");
if (sessionId && sessionId != "") {
sessionStorage.setItem("session_id", sessionId);
window.history.pushState({}, document.title, window.location.pathname);
}
apiCall("get", "/connection", {}, function(resp) {
if (resp.error) {
connected = false;
showConnectionSettings();
$(".connection-actions").show();
}
else {
connected = true;
loadSchemas();
$("#current_database").text(resp.current_database);
$("#main").show();
if (!resp.session_lock) {
$(".connection-actions").show();
}
}
});
bindDatabaseObjectsFilter();
});