Load, and save the files in the Query Editor.
Also, the changes done by Ashesh to resolved few issue with the file manager in 'Select' mode.pull/3/head
parent
4dc7f84761
commit
1aeab98a2b
File diff suppressed because it is too large
Load Diff
|
@ -1156,3 +1156,12 @@ form[name="change_password_form"] .help-block {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overriding the css for the dropzone */
|
||||||
|
.dropzone .dz-preview .dz-progress {
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-progress .dz-upload {
|
||||||
|
bottom: initial;
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@ body {
|
||||||
<div class="sql-editor" data-trans-id="{{ uniqueId }}">
|
<div class="sql-editor" data-trans-id="{{ uniqueId }}">
|
||||||
<div id="btn-toolbar" class="pg-prop-btn-group" role="toolbar" aria-label="">
|
<div id="btn-toolbar" class="pg-prop-btn-group" role="toolbar" aria-label="">
|
||||||
<div class="btn-group" role="group" aria-label="">
|
<div class="btn-group" role="group" aria-label="">
|
||||||
|
<button id="btn-load-file" type="button" class="btn btn-default btn-load-file" title="{{ _('Open File') }}">
|
||||||
|
<i class="fa fa-folder-open-o" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<button id="btn-save" type="button" class="btn btn-default" title="{{ _('Save') }}" disabled>
|
<button id="btn-save" type="button" class="btn btn-default" title="{{ _('Save') }}" disabled>
|
||||||
<i class="fa fa-floppy-o" aria-hidden="true"></i>
|
<i class="fa fa-floppy-o" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -13,6 +13,7 @@ MODULE_NAME = 'sqleditor'
|
||||||
import json
|
import json
|
||||||
import pickle
|
import pickle
|
||||||
import random
|
import random
|
||||||
|
import os
|
||||||
from flask import Response, url_for, render_template, session, request
|
from flask import Response, url_for, render_template, session, request
|
||||||
from flask.ext.babel import gettext
|
from flask.ext.babel import gettext
|
||||||
from flask.ext.security import login_required
|
from flask.ext.security import login_required
|
||||||
|
@ -21,7 +22,13 @@ from pgadmin.utils.ajax import make_json_response, bad_request, success_return,
|
||||||
from pgadmin.utils.driver import get_driver
|
from pgadmin.utils.driver import get_driver
|
||||||
from config import PG_DEFAULT_DRIVER
|
from config import PG_DEFAULT_DRIVER
|
||||||
from pgadmin.tools.sqleditor.command import QueryToolCommand
|
from pgadmin.tools.sqleditor.command import QueryToolCommand
|
||||||
|
from pgadmin.utils import get_storage_directory
|
||||||
|
|
||||||
|
# import unquote from urlib for python2.x and python3.x
|
||||||
|
try:
|
||||||
|
from urllib import unquote
|
||||||
|
except Exception as e:
|
||||||
|
from urllib.parse import unquote
|
||||||
|
|
||||||
# Async Constants
|
# Async Constants
|
||||||
ASYNC_OK = 1
|
ASYNC_OK = 1
|
||||||
|
@ -44,7 +51,7 @@ class SqlEditorModule(PgAdminModule):
|
||||||
A module class for SQL Grid derived from PgAdminModule.
|
A module class for SQL Grid derived from PgAdminModule.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
LABEL = "SQL Editor"
|
LABEL = gettext("SQL Editor")
|
||||||
|
|
||||||
def get_own_menuitems(self):
|
def get_own_menuitems(self):
|
||||||
return {}
|
return {}
|
||||||
|
@ -949,3 +956,87 @@ def is_begin_required(query):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/load_file/', methods=["PUT", "POST"])
|
||||||
|
@login_required
|
||||||
|
def load_file():
|
||||||
|
"""
|
||||||
|
This function gets name of file from request data
|
||||||
|
reads the data and sends back in reponse
|
||||||
|
"""
|
||||||
|
if request.data:
|
||||||
|
file_data = json.loads(request.data.decode())
|
||||||
|
|
||||||
|
# retrieve storage directory path
|
||||||
|
storage_manager_path = get_storage_directory()
|
||||||
|
|
||||||
|
# generate full path of file
|
||||||
|
file_path = os.path.join(
|
||||||
|
storage_manager_path,
|
||||||
|
unquote(file_data['file_name'])
|
||||||
|
)
|
||||||
|
file_data = None
|
||||||
|
|
||||||
|
# read file
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as myfile:
|
||||||
|
file_data = myfile.read()
|
||||||
|
except IOError as e:
|
||||||
|
# we don't want to expose real path of file
|
||||||
|
# so only show error message.
|
||||||
|
if e.strerror == 'Permission denied':
|
||||||
|
err_msg = "Error: {0}".format(e.strerror)
|
||||||
|
else:
|
||||||
|
err_msg = "Error: {0}".format(e.strerror)
|
||||||
|
return internal_server_error(errormsg=err_msg)
|
||||||
|
except Exception as e:
|
||||||
|
err_msg = "Error: {0}".format(e.strerror)
|
||||||
|
return internal_server_error(errormsg=err_msg)
|
||||||
|
return make_json_response(
|
||||||
|
data={
|
||||||
|
'status': True, 'result': file_data,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/save_file/', methods=["PUT", "POST"])
|
||||||
|
@login_required
|
||||||
|
def save_file():
|
||||||
|
"""
|
||||||
|
This function retrieves file_name and data from request.
|
||||||
|
and then save the data to the file
|
||||||
|
"""
|
||||||
|
if request.data:
|
||||||
|
file_data = json.loads(request.data.decode())
|
||||||
|
|
||||||
|
# retrieve storage directory path
|
||||||
|
storage_manager_path = get_storage_directory()
|
||||||
|
|
||||||
|
# generate full path of file
|
||||||
|
file_path = os.path.join(
|
||||||
|
storage_manager_path,
|
||||||
|
unquote(file_data['file_name'])
|
||||||
|
)
|
||||||
|
file_content = file_data['file_content']
|
||||||
|
file_data = None
|
||||||
|
|
||||||
|
# write to file
|
||||||
|
try:
|
||||||
|
with open(file_path, 'w') as output_file:
|
||||||
|
output_file.write(file_content)
|
||||||
|
except IOError as e:
|
||||||
|
if e.strerror == 'Permission denied':
|
||||||
|
err_msg = "Error: {0}".format(e.strerror)
|
||||||
|
else:
|
||||||
|
err_msg = "Error: {0}".format(e.strerror)
|
||||||
|
return internal_server_error(errormsg=err_msg)
|
||||||
|
except Exception as e:
|
||||||
|
err_msg = "Error: {0}".format(e.strerror)
|
||||||
|
return internal_server_error(errormsg=err_msg)
|
||||||
|
|
||||||
|
return make_json_response(
|
||||||
|
data={
|
||||||
|
'status': True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
@ -3,7 +3,7 @@ define(
|
||||||
'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/selection/active-line',
|
'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/selection/active-line',
|
||||||
'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', 'codemirror/addon/fold/pgadmin-sqlfoldcode',
|
'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', 'codemirror/addon/fold/pgadmin-sqlfoldcode',
|
||||||
'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', 'backgrid.filter',
|
'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', 'backgrid.filter',
|
||||||
'bootstrap', 'pgadmin.browser', 'wcdocker'],
|
'bootstrap', 'pgadmin.browser', 'wcdocker', 'pgadmin.file_manager'],
|
||||||
function($, _, alertify, pgAdmin, Backbone, Backgrid, CodeMirror) {
|
function($, _, alertify, pgAdmin, Backbone, Backgrid, CodeMirror) {
|
||||||
|
|
||||||
// Some scripts do export their object in the window only.
|
// Some scripts do export their object in the window only.
|
||||||
|
@ -143,6 +143,7 @@ define(
|
||||||
|
|
||||||
// Bind all the events
|
// Bind all the events
|
||||||
events: {
|
events: {
|
||||||
|
"click .btn-load-file": "on_file_load",
|
||||||
"click #btn-save": "on_save",
|
"click #btn-save": "on_save",
|
||||||
"click #btn-add-row": "on_add",
|
"click #btn-add-row": "on_add",
|
||||||
"click #btn-filter": "on_show_filter",
|
"click #btn-filter": "on_show_filter",
|
||||||
|
@ -641,7 +642,20 @@ define(
|
||||||
},
|
},
|
||||||
do_not_close_menu: function(ev) {
|
do_not_close_menu: function(ev) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
// callback function for load file button click.
|
||||||
|
on_file_load: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Trigger the save signal to the SqlEditorController class
|
||||||
|
self.handler.trigger(
|
||||||
|
'pgadmin-sqleditor:button:load_file',
|
||||||
|
self,
|
||||||
|
self.handler
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Defining controller class for data grid, which actually
|
/* Defining controller class for data grid, which actually
|
||||||
|
@ -683,11 +697,22 @@ define(
|
||||||
self.transId = self.container.data('transId');
|
self.transId = self.container.data('transId');
|
||||||
|
|
||||||
self.gridView.editor_title = editor_title;
|
self.gridView.editor_title = editor_title;
|
||||||
|
self.gridView.current_file = undefined;
|
||||||
|
|
||||||
// Render the header
|
// Render the header
|
||||||
self.gridView.render();
|
self.gridView.render();
|
||||||
|
|
||||||
|
// Listen to the file manager button events
|
||||||
|
pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:select_file', self._select_file_handler, self);
|
||||||
|
pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:create_file', self._save_file_handler, self);
|
||||||
|
|
||||||
|
// Listen to the codemirror on text change event
|
||||||
|
// only in query editor tool
|
||||||
|
if (self.is_query_tool)
|
||||||
|
self.gridView.query_tool_obj.on('change', self._on_query_change, self);
|
||||||
|
|
||||||
// Listen on events come from SQLEditorView for the button clicked.
|
// Listen on events come from SQLEditorView for the button clicked.
|
||||||
|
self.on('pgadmin-sqleditor:button:load_file', self._load_file, self);
|
||||||
self.on('pgadmin-sqleditor:button:save', self._save, self);
|
self.on('pgadmin-sqleditor:button:save', self._save, self);
|
||||||
self.on('pgadmin-sqleditor:button:addrow', self._add, self);
|
self.on('pgadmin-sqleditor:button:addrow', self._add, self);
|
||||||
self.on('pgadmin-sqleditor:button:show_filter', self._show_filter, self);
|
self.on('pgadmin-sqleditor:button:show_filter', self._show_filter, self);
|
||||||
|
@ -1297,12 +1322,34 @@ define(
|
||||||
|
|
||||||
/* This function will fetch the list of changed models and make
|
/* This function will fetch the list of changed models and make
|
||||||
* the ajax call to save the data into the database server.
|
* the ajax call to save the data into the database server.
|
||||||
|
* and will open save file dialog conditionally.
|
||||||
*/
|
*/
|
||||||
_save: function() {
|
_save: function() {
|
||||||
var self = this,
|
var self = this,
|
||||||
data = [],
|
data = [],
|
||||||
save_data = true;
|
save_data = true;
|
||||||
|
|
||||||
|
// Open save file dialog if query tool
|
||||||
|
if (self.is_query_tool) {
|
||||||
|
|
||||||
|
var current_file = self.gridView.current_file;
|
||||||
|
if (!_.isUndefined(current_file)) {
|
||||||
|
self._save_file_handler(current_file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// provide custom option to save file dialog
|
||||||
|
var params = {
|
||||||
|
'supported_types': ["*", "sql"],
|
||||||
|
'dialog_type': 'create_file',
|
||||||
|
'dialog_title': 'Save File',
|
||||||
|
'btn_primary': 'Save'
|
||||||
|
}
|
||||||
|
pgAdmin.FileManager.init();
|
||||||
|
pgAdmin.FileManager.show_dialog(params);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$("#btn-save").prop('disabled', true);
|
$("#btn-save").prop('disabled', true);
|
||||||
if (self.changedModels.length == 0)
|
if (self.changedModels.length == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -1395,6 +1442,87 @@ define(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// load select file dialog
|
||||||
|
_load_file: function() {
|
||||||
|
var params = {
|
||||||
|
'supported_types': ["sql"], // file types allowed
|
||||||
|
'dialog_type': 'select_file' // open select file dialog
|
||||||
|
}
|
||||||
|
pgAdmin.FileManager.init();
|
||||||
|
pgAdmin.FileManager.show_dialog(params);
|
||||||
|
},
|
||||||
|
|
||||||
|
// read file data and return as response
|
||||||
|
_select_file_handler: function(e) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'file_name': e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make ajax call to load the data from file
|
||||||
|
$.ajax({
|
||||||
|
url: "{{ url_for('sqleditor.index') }}" + "load_file/",
|
||||||
|
method: 'POST',
|
||||||
|
async: false,
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
success: function(res) {
|
||||||
|
if (res.data.status) {
|
||||||
|
self.gridView.query_tool_obj.setValue(res.data.result);
|
||||||
|
self.gridView.current_file = e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(e) {
|
||||||
|
var errmsg = $.parseJSON(e.responseText).errormsg;
|
||||||
|
alertify.error(errmsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// read data from codemirror and write to file
|
||||||
|
_save_file_handler: function(e) {
|
||||||
|
var self = this;
|
||||||
|
data = {
|
||||||
|
'file_name': e,
|
||||||
|
'file_content': self.gridView.query_tool_obj.getValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make ajax call to save the data to file
|
||||||
|
$.ajax({
|
||||||
|
url: "{{ url_for('sqleditor.index') }}" + "save_file/",
|
||||||
|
method: 'POST',
|
||||||
|
async: false,
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
success: function(res) {
|
||||||
|
if (res.data.status) {
|
||||||
|
alertify.success('{{ _('File saved successfully.') }}');
|
||||||
|
self.gridView.current_file = e;
|
||||||
|
|
||||||
|
// disable save button on file save
|
||||||
|
$("#btn-save").prop('disabled', true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(e) {
|
||||||
|
var errmsg = $.parseJSON(e.responseText).errormsg;
|
||||||
|
alertify.error(errmsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// codemirror text change event
|
||||||
|
_on_query_change: function(query_tool_obj) {
|
||||||
|
|
||||||
|
if(query_tool_obj.getValue().length == 0) {
|
||||||
|
$("#btn-save").prop('disabled', true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#btn-save").prop('disabled', false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
// This function will run the SQL query and refresh the data in the backgrid.
|
// This function will run the SQL query and refresh the data in the backgrid.
|
||||||
_refresh: function() {
|
_refresh: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -1696,6 +1824,7 @@ define(
|
||||||
$("#btn-query-dropdown").prop('disabled', disabled);
|
$("#btn-query-dropdown").prop('disabled', disabled);
|
||||||
$("#btn-edit-dropdown").prop('disabled', disabled);
|
$("#btn-edit-dropdown").prop('disabled', disabled);
|
||||||
$("#btn-edit").prop('disabled', disabled);
|
$("#btn-edit").prop('disabled', disabled);
|
||||||
|
$('#btn-load-file').prop('disabled', disabled);
|
||||||
},
|
},
|
||||||
|
|
||||||
// This function will fetch the sql query from the text box
|
// This function will fetch the sql query from the text box
|
||||||
|
|
Loading…
Reference in New Issue