2019-01-02 04:24:12 -06:00
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
2021-01-04 04:04:45 -06:00
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
2019-01-02 04:24:12 -06:00
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
2021-02-10 01:17:52 -06:00
/* This is used to change publicPath of webpack at runtime for loading chunks */
/* eslint-disable */
_ _webpack _public _path _ _ = window . resourceBasePath ;
/* eslint-enable */
2019-01-02 04:24:12 -06:00
2020-09-11 08:36:56 -05:00
import { launchDataGrid } from 'tools/datagrid/static/js/show_query_tool' ;
2020-09-09 09:02:33 -05:00
2017-07-18 09:13:16 -05:00
define ( 'tools.querytool' , [
2019-10-10 01:35:28 -05:00
'sources/gettext' , 'sources/url_for' , 'jquery' , 'jquery.ui' ,
'jqueryui.position' , 'underscore' , 'pgadmin.alertifyjs' ,
2020-08-10 06:23:32 -05:00
'sources/pgadmin' , 'backbone' , 'bundled_codemirror' , 'sources/utils' ,
2018-01-12 01:29:51 -06:00
'pgadmin.misc.explain' ,
2020-10-01 02:59:00 -05:00
'pgadmin.user_management.current_user' ,
2018-01-12 01:29:51 -06:00
'sources/selection/grid_selector' ,
'sources/selection/active_cell_capture' ,
'sources/selection/clipboard' ,
'sources/selection/copy_data' ,
'sources/selection/range_selection_helper' ,
'sources/slickgrid/event_handlers/handle_query_output_keyboard_event' ,
'sources/selection/xcell_selection_model' ,
'sources/selection/set_staged_rows' ,
'sources/sqleditor_utils' ,
2018-02-09 05:54:42 -06:00
'sources/sqleditor/execute_query' ,
2018-04-04 05:20:36 -05:00
'sources/sqleditor/query_tool_http_error_handler' ,
2018-04-05 10:25:17 -05:00
'sources/sqleditor/filter_dialog' ,
2020-10-01 02:59:00 -05:00
'sources/sqleditor/new_connection_dialog' ,
2018-08-30 07:59:31 -05:00
'sources/sqleditor/geometry_viewer' ,
2019-03-07 04:51:59 -06:00
'sources/sqleditor/history/history_collection.js' ,
'sources/sqleditor/history/query_history' ,
2019-08-16 06:47:12 -05:00
'sources/sqleditor/history/query_sources' ,
2018-01-25 06:27:13 -06:00
'sources/keyboard_shortcuts' ,
2018-01-12 01:29:51 -06:00
'sources/sqleditor/query_tool_actions' ,
2018-05-30 20:58:28 -05:00
'sources/sqleditor/query_tool_notifications' ,
2018-02-01 07:29:18 -06:00
'pgadmin.datagrid' ,
2018-04-03 08:52:13 -05:00
'sources/modify_animation' ,
2018-04-03 08:11:11 -05:00
'sources/sqleditor/calculate_query_run_time' ,
'sources/sqleditor/call_render_after_poll' ,
2018-07-05 05:38:43 -05:00
'sources/sqleditor/query_tool_preferences' ,
2019-11-25 21:34:41 -06:00
'sources/sqleditor/query_txn_status_constants' ,
2019-05-28 00:29:51 -05:00
'sources/csrf' ,
2019-06-24 05:36:03 -05:00
'tools/datagrid/static/js/datagrid_panel_title' ,
2019-09-23 02:25:02 -05:00
'sources/window' ,
2020-09-07 07:40:27 -05:00
'sources/is_native' ,
2020-09-28 04:56:45 -05:00
'sources/sqleditor/macro' ,
2017-08-21 09:27:29 -05:00
'sources/../bundle/slickgrid' ,
2018-01-12 01:29:51 -06:00
'pgadmin.file_manager' ,
'slick.pgadmin.formatters' ,
'slick.pgadmin.editors' ,
2019-02-26 07:44:16 -06:00
'slick.pgadmin.plugins/slick.autocolumnsize' ,
2018-01-12 01:29:51 -06:00
'pgadmin.browser' ,
2018-02-01 07:29:18 -06:00
'pgadmin.tools.user_management' ,
2017-06-07 05:23:02 -05:00
] , function (
2020-08-10 06:23:32 -05:00
gettext , url _for , $ , jqueryui , jqueryui _position , _ , alertify , pgAdmin , Backbone , codemirror , pgadminUtils ,
2020-10-01 02:59:00 -05:00
pgExplain , current _user , GridSelector , ActiveCellCapture , clipboard , copyData , RangeSelectionHelper , handleQueryOutputKeyboardEvent ,
XCellSelectionModel , setStagedRows , SqlEditorUtils , ExecuteQuery , httpErrorHandler , FilterHandler , newConnectionHandler ,
2019-08-16 06:47:12 -05:00
GeometryViewer , historyColl , queryHist , querySources ,
2018-05-30 20:58:28 -05:00
keyboardShortcuts , queryToolActions , queryToolNotifications , Datagrid ,
2019-11-25 21:34:41 -06:00
modifyAnimation , calculateQueryRunTime , callRenderAfterPoll , queryToolPref , queryTxnStatus , csrfToken , panelTitleFunc ,
2020-09-28 04:56:45 -05:00
pgWindow , isNative , MacroHandler ) {
2018-01-12 01:29:51 -06:00
/* Return back, this has been called more than once */
if ( pgAdmin . SqlEditor )
return pgAdmin . SqlEditor ;
// Some scripts do export their object in the window only.
// Generally the one, which do no have AMD support.
var wcDocker = window . wcDocker ,
pgBrowser = pgAdmin . Browser ,
CodeMirror = codemirror . default ,
2019-03-07 04:51:59 -06:00
Slick = window . Slick ,
HistoryCollection = historyColl . default ,
2019-08-16 06:47:12 -05:00
QueryHistory = queryHist . default ,
QuerySources = querySources . QuerySources ;
2017-08-21 09:27:29 -05:00
2019-05-28 00:29:51 -05:00
csrfToken . setPGCSRFToken ( pgAdmin . csrf _token _header , pgAdmin . csrf _token ) ;
2017-08-21 09:27:29 -05:00
var is _query _running = false ;
2020-09-28 07:21:59 -05:00
const EMPTY _DATA _OUTPUT _CONTENT = '<div role="status" class="pg-panel-message">' +
gettext ( 'No data output. Execute a query to get output.' ) +
'</div>' ;
const EMPTY _EXPLAIN _CONTENT = '<div role="status" class="pg-panel-message">' +
gettext ( 'Use Explain/Explain analyze button to generate the plan for a query. Alternatively, you can also execute "EXPLAIN (FORMAT JSON) [QUERY]".' ) +
'</div>' ;
2017-08-21 09:27:29 -05:00
// Defining Backbone view for the sql grid.
var SQLEditorView = Backbone . View . extend ( {
2018-01-12 01:29:51 -06:00
initialize : function ( opts ) {
2017-08-21 09:27:29 -05:00
this . $el = opts . el ;
this . handler = opts . handler ;
this . handler [ 'col_size' ] = { } ;
2019-09-23 02:25:02 -05:00
let browser = pgWindow . default . pgAdmin . Browser ;
2018-07-05 05:38:43 -05:00
this . preferences = browser . get _preferences _for _module ( 'sqleditor' ) ;
2020-11-04 06:15:28 -06:00
this . browser _preferences = browser . get _preferences _for _module ( 'browser' ) ;
2018-07-05 05:38:43 -05:00
this . handler . preferences = this . preferences ;
2020-11-04 06:15:28 -06:00
this . handler . browser _preferences = this . browser _preferences ;
2018-07-05 05:38:43 -05:00
this . connIntervalId = null ;
2019-03-26 10:08:45 -05:00
this . layout = opts . layout ;
2020-01-10 04:09:32 -06:00
this . set _server _version ( opts . server _ver ) ;
this . trigger ( 'pgadmin-sqleditor:view:initialised' ) ;
2020-10-01 02:59:00 -05:00
this . connection _list = [
2020-10-27 00:21:35 -05:00
{ 'server_group' : null , 'server' : null , 'database' : null , 'user' : null , 'role' : null , 'title' : '<' + gettext ( 'New Connection' ) + '>' } ,
2020-10-01 02:59:00 -05:00
] ;
2017-08-21 09:27:29 -05:00
} ,
// Bind all the events
events : {
2020-08-28 03:23:08 -05:00
'click #btn-show-query-tool' : 'on_show_query_tool' ,
2018-01-12 01:29:51 -06:00
'click .btn-load-file' : 'on_file_load' ,
2019-07-17 05:45:20 -05:00
'click #btn-save-file' : 'on_save_file' ,
'click #btn-file-menu-save' : 'on_save_file' ,
2018-01-12 01:29:51 -06:00
'click #btn-file-menu-save-as' : 'on_save_as' ,
'click #btn-find' : 'on_find' ,
'click #btn-find-menu-find' : 'on_find' ,
'click #btn-find-menu-find-next' : 'on_find_next' ,
'click #btn-find-menu-find-previous' : 'on_find_previous' ,
'click #btn-find-menu-replace' : 'on_replace' ,
'click #btn-find-menu-replace-all' : 'on_replace_all' ,
'click #btn-find-menu-find-persistent' : 'on_find_persistent' ,
'click #btn-find-menu-jump' : 'on_jump' ,
'click #btn-delete-row' : 'on_delete' ,
2019-07-17 05:45:20 -05:00
'click #btn-save-data' : 'on_save_data' ,
2018-01-12 01:29:51 -06:00
'click #btn-filter' : 'on_show_filter' ,
'click #btn-filter-menu' : 'on_show_filter' ,
'click #btn-include-filter' : 'on_include_filter' ,
'click #btn-exclude-filter' : 'on_exclude_filter' ,
'click #btn-remove-filter' : 'on_remove_filter' ,
'click #btn-cancel' : 'on_cancel' ,
'click #btn-copy-row' : 'on_copy_row' ,
2019-09-27 01:44:39 -05:00
'click #btn-copy-with-header' : 'on_copy_row_with_header' ,
2018-01-12 01:29:51 -06:00
'click #btn-paste-row' : 'on_paste_row' ,
'click #btn-flash' : 'on_flash' ,
'click #btn-flash-menu' : 'on_flash' ,
'click #btn-cancel-query' : 'on_cancel_query' ,
2020-12-14 00:28:53 -06:00
'click #btn-save-results-to-file' : 'on_download' ,
2018-01-12 01:29:51 -06:00
'click #btn-clear' : 'on_clear' ,
'click #btn-auto-commit' : 'on_auto_commit' ,
'click #btn-auto-rollback' : 'on_auto_rollback' ,
'click #btn-clear-history' : 'on_clear_history' ,
'click .noclose' : 'do_not_close_menu' ,
'click #btn-explain' : 'on_explain' ,
'click #btn-explain-analyze' : 'on_explain_analyze' ,
'click #btn-explain-verbose' : 'on_explain_verbose' ,
'click #btn-explain-costs' : 'on_explain_costs' ,
'click #btn-explain-buffers' : 'on_explain_buffers' ,
'click #btn-explain-timing' : 'on_explain_timing' ,
2019-07-03 07:57:56 -05:00
'click #btn-explain-summary' : 'on_explain_summary' ,
'click #btn-explain-settings' : 'on_explain_settings' ,
2018-01-12 01:29:51 -06:00
'change .limit' : 'on_limit_change' ,
'keydown' : 'keyAction' ,
2017-08-21 09:27:29 -05:00
// Comment options
2018-01-12 01:29:51 -06:00
'click #btn-comment-code' : 'on_toggle_comment_block_code' ,
'click #btn-toggle-comment-block' : 'on_toggle_comment_block_code' ,
'click #btn-comment-line' : 'on_comment_line_code' ,
'click #btn-uncomment-line' : 'on_uncomment_line_code' ,
2017-08-21 09:27:29 -05:00
// Indentation options
2018-01-12 01:29:51 -06:00
'click #btn-indent-code' : 'on_indent_code' ,
'click #btn-unindent-code' : 'on_unindent_code' ,
2020-08-20 02:35:00 -05:00
// Format
'click #btn-format-sql' : 'on_format_sql' ,
// Transaction control
2019-02-22 08:28:05 -06:00
'click #btn-commit' : 'on_commit_transaction' ,
'click #btn-rollback' : 'on_rollback_transaction' ,
2020-09-28 04:56:45 -05:00
// Manage Macros
'click #btn-manage-macros' : 'on_manage_macros' ,
'click .btn-macro' : 'on_execute_macro' ,
2017-08-21 09:27:29 -05:00
} ,
2020-10-01 02:59:00 -05:00
render _connection : function ( data _list ) {
if ( this . handler . is _query _tool ) {
var dropdownElement = document . getElementById ( 'connections-list' ) ;
dropdownElement . innerHTML = '' ;
data _list . forEach ( ( option , index ) => {
2020-10-21 06:44:59 -05:00
var opt = '' ;
if ( 'is_selected' in option && option [ 'is_selected' ] ) {
opt = '<li class="connection-list-item selected-connection" data-index=' + index + '><a class="dropdown-item" href="#" tabindex="0">' + option . title + '</a></li>' ;
} else {
opt = '<li class="connection-list-item" data-index=' + index + '><a class="dropdown-item" href="#" tabindex="0">' + option . title + '</a></li>' ;
}
$ ( '#connections-list' ) . append ( opt ) ;
2020-10-01 02:59:00 -05:00
} ) ;
var self = this ;
$ ( '.connection-list-item' ) . click ( function ( ) {
self . get _connection _data ( this ) ;
} ) ;
} else {
$ ( '.conn-info-dd' ) . hide ( ) ;
2020-10-08 01:08:05 -05:00
$ ( '.connection-data' ) . css ( { pointerEvents : 'none' , cursor : 'arrow' } ) ;
2020-10-01 02:59:00 -05:00
}
} ,
get _connection _data : function ( event ) {
var index = $ ( event ) . attr ( 'data-index' ) ;
var connection _details = this . connection _list [ index ] ;
if ( connection _details . server _group ) {
this . on _change _connection ( connection _details ) ;
} else {
this . on _new _connection ( ) ;
}
} ,
2018-07-05 05:38:43 -05:00
reflectPreferences : function ( ) {
let self = this ,
2020-09-09 09:02:33 -05:00
browser = pgWindow . default . pgAdmin . Browser ,
browser _preferences = browser . get _preferences _for _module ( 'browser' ) ;
2018-07-05 05:38:43 -05:00
2019-09-23 02:25:02 -05:00
/ * p g B r o w s e r i s d i f f e r e n t o b j f r o m p g W i n d o w . d e f a u l t . p g A d m i n . B r o w s e r
2018-07-05 05:38:43 -05:00
* Make sure to get only the latest update . Older versions will be discarded
* if function is called by older events .
* This works for new tab sql editor also as it polls if latest version available
* This is required because sql editor can update preferences directly
* /
if ( pgBrowser . preference _version ( ) < browser . preference _version ( ) ) {
pgBrowser . preference _version ( browser . preference _version ( ) ) ;
self . preferences = browser . get _preferences _for _module ( 'sqleditor' ) ;
2020-09-09 09:02:33 -05:00
self . preferences . show _query _tool = browser _preferences . sub _menu _query _tool ;
2018-07-05 05:38:43 -05:00
self . handler . preferences = self . preferences ;
queryToolPref . updateUIPreferences ( self ) ;
}
} ,
2019-03-26 10:08:45 -05:00
buildDefaultLayout : function ( docker ) {
let sql _panel _obj = docker . addPanel ( 'sql_panel' , wcDocker . DOCK . TOP ) ;
docker . addPanel ( 'scratch' , wcDocker . DOCK . RIGHT , sql _panel _obj ) ;
docker . addPanel ( 'history' , wcDocker . DOCK . STACKED , sql _panel _obj ) ;
let data _output _panel = docker . addPanel ( 'data_output' , wcDocker . DOCK . BOTTOM ) ;
docker . addPanel ( 'explain' , wcDocker . DOCK . STACKED , data _output _panel ) ;
docker . addPanel ( 'messages' , wcDocker . DOCK . STACKED , data _output _panel ) ;
docker . addPanel ( 'notifications' , wcDocker . DOCK . STACKED , data _output _panel ) ;
} ,
2019-07-03 07:57:56 -05:00
set _server _version : function ( server _ver ) {
let self = this ;
self . server _ver = server _ver ;
this . $el . find ( '*[data-min-ver]' ) . map ( function ( ) {
let minVer = 0 ,
ele = $ ( this ) ;
minVer = parseInt ( ele . attr ( 'data-min-ver' ) ) ;
if ( minVer > self . server _ver ) {
ele . addClass ( 'd-none' ) ;
} else {
ele . removeClass ( 'd-none' ) ;
}
} ) ;
} ,
2019-08-23 06:14:20 -05:00
set _editor _title : function ( title ) {
2020-10-12 05:50:33 -05:00
this . $el . find ( '.editor-title' ) . text ( _ . unescape ( title ) ) ;
2020-10-01 02:59:00 -05:00
this . render _connection ( this . connection _list ) ;
2019-08-23 06:14:20 -05:00
} ,
2017-08-21 09:27:29 -05:00
// This function is used to render the template.
2018-01-12 01:29:51 -06:00
render : function ( ) {
2018-04-05 10:25:17 -05:00
var self = this ;
2017-08-21 09:27:29 -05:00
2018-01-12 08:34:39 -06:00
// Updates connection status flag
self . gain _focus = function ( ) {
setTimeout ( function ( ) {
SqlEditorUtils . updateConnectionStatusFlag ( 'visible' ) ;
} , 100 ) ;
} ;
// Updates connection status flag
self . lost _focus = function ( ) {
setTimeout ( function ( ) {
SqlEditorUtils . updateConnectionStatusFlag ( 'hidden' ) ;
} , 100 ) ;
} ;
2017-08-21 09:27:29 -05:00
// Create main wcDocker instance
2019-03-26 10:08:45 -05:00
self . docker = new wcDocker (
2017-08-21 09:27:29 -05:00
'#editor-panel' , {
2019-02-15 09:44:49 -06:00
allowContextMenu : true ,
2016-04-14 09:04:03 -05:00
allowCollapse : false ,
Improvement in the look and feel of the whole application
Changed the SCSS/CSS for the below third party libraries to adopt the
new look 'n' feel:
- wcDocker
- Alertify dialogs, and notifications
- AciTree
- Bootstrap Navbar
- Bootstrap Tabs
- Bootstrap Drop-Down menu
- Backgrid
- Select2
Adopated the new the look 'n' feel for the dialogs, wizard, properties,
tab panels, tabs, fieldset, subnode control, spinner control, HTML
table, and other form controls.
- Font is changed to Roboto
- Using SCSS variables to define the look 'n' feel
- Designer background images for the Login, and Forget password pages in
'web' mode
- Improved the look 'n' feel for the key selection in the preferences
dialog
- Table classes consistency changes across the application
- File Open and Save dialog list view changes
Author(s): Aditya Toshniwal & Khushboo Vashi
2018-12-21 05:44:55 -06:00
loadingClass : 'pg-sp-icon' ,
2018-01-12 01:29:51 -06:00
themePath : url _for ( 'static' , {
'filename' : 'css' ,
} ) ,
theme : 'webcabin.overrides.css' ,
2019-06-10 05:10:49 -05:00
}
) ;
2018-01-25 06:27:13 -06:00
2019-03-26 10:08:45 -05:00
// Create the panels
2017-08-21 09:27:29 -05:00
var sql _panel = new pgAdmin . Browser . Panel ( {
name : 'sql_panel' ,
2018-11-29 09:47:48 -06:00
title : gettext ( 'Query Editor' ) ,
2019-02-15 09:44:49 -06:00
width : '75%' ,
height : '33%' ,
2017-08-21 09:27:29 -05:00
isCloseable : false ,
2018-01-12 01:29:51 -06:00
isPrivate : true ,
2017-08-21 09:27:29 -05:00
} ) ;
var data _output = new pgAdmin . Browser . Panel ( {
name : 'data_output' ,
2018-01-12 01:29:51 -06:00
title : gettext ( 'Data Output' ) ,
2017-08-21 09:27:29 -05:00
width : '100%' ,
height : '100%' ,
isCloseable : false ,
isPrivate : true ,
2019-02-27 04:59:58 -06:00
extraClasses : 'hide-vertical-scrollbar' ,
2020-09-28 07:21:59 -05:00
content : ` <div id ="datagrid" class="sql-editor-grid-container text-12" tabindex="0"> ${ EMPTY _DATA _OUTPUT _CONTENT } </div> ` ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
var explain = new pgAdmin . Browser . Panel ( {
name : 'explain' ,
2018-01-12 01:29:51 -06:00
title : gettext ( 'Explain' ) ,
2017-08-21 09:27:29 -05:00
width : '100%' ,
height : '100%' ,
isCloseable : false ,
isPrivate : true ,
2020-09-28 07:21:59 -05:00
content : ` <div class="sql-editor-explain pg-el-container" tabindex="0"> ${ EMPTY _EXPLAIN _CONTENT } </div> ` ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
var messages = new pgAdmin . Browser . Panel ( {
name : 'messages' ,
2018-01-12 01:29:51 -06:00
title : gettext ( 'Messages' ) ,
2017-08-21 09:27:29 -05:00
width : '100%' ,
height : '100%' ,
isCloseable : false ,
isPrivate : true ,
2020-01-28 00:02:11 -06:00
content : '<div role="status" class="sql-editor-message" tabindex="0"></div>' ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
var history = new pgAdmin . Browser . Panel ( {
name : 'history' ,
2018-01-12 01:29:51 -06:00
title : gettext ( 'Query History' ) ,
2017-08-21 09:27:29 -05:00
width : '100%' ,
2019-03-01 06:49:41 -06:00
height : '33%' ,
2017-08-21 09:27:29 -05:00
isCloseable : false ,
isPrivate : true ,
2019-06-10 05:10:49 -05:00
content : '<div id ="history_grid" class="sql-editor-history-container" tabindex="0"></div>' ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
2019-02-15 09:44:49 -06:00
var scratch = new pgAdmin . Browser . Panel ( {
name : 'scratch' ,
title : gettext ( 'Scratch Pad' ) ,
width : '25%' ,
2019-03-01 06:49:41 -06:00
height : '33%' ,
2019-02-15 09:44:49 -06:00
isCloseable : true ,
isPrivate : false ,
2019-06-10 05:10:49 -05:00
content : '<div class="sql-scratch"><textarea wrap="off" tabindex="0"></textarea></div>' ,
2019-02-15 09:44:49 -06:00
} ) ;
2018-05-30 20:58:28 -05:00
var notifications = new pgAdmin . Browser . Panel ( {
name : 'notifications' ,
title : gettext ( 'Notifications' ) ,
width : '100%' ,
height : '100%' ,
isCloseable : false ,
isPrivate : true ,
2019-06-10 05:10:49 -05:00
content : '<div id ="notification_grid" class="sql-editor-notifications" tabindex="0"></div>' ,
2018-05-30 20:58:28 -05:00
} ) ;
2018-08-30 07:59:31 -05:00
var geometry _viewer = new pgAdmin . Browser . Panel ( {
name : 'geometry_viewer' ,
title : gettext ( 'Geometry Viewer' ) ,
width : '100%' ,
height : '100%' ,
isCloseable : true ,
isPrivate : true ,
2019-05-30 14:15:37 -05:00
isLayoutMember : false ,
2019-06-10 05:10:49 -05:00
content : '<div id ="geometry_viewer_panel" class="sql-editor-geometry-viewer" tabindex="0"></div>' ,
2018-08-30 07:59:31 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
// Load all the created panels
2019-03-26 10:08:45 -05:00
sql _panel . load ( self . docker ) ;
data _output . load ( self . docker ) ;
explain . load ( self . docker ) ;
messages . load ( self . docker ) ;
history . load ( self . docker ) ;
scratch . load ( self . docker ) ;
notifications . load ( self . docker ) ;
geometry _viewer . load ( self . docker ) ;
// restore the layout if present else fallback to buildDefaultLayout
pgBrowser . restore _layout ( self . docker , this . layout , this . buildDefaultLayout . bind ( this ) ) ;
self . docker . on ( wcDocker . EVENT . LAYOUT _CHANGED , function ( ) {
pgBrowser . save _current _layout ( 'SQLEditor/Layout' , self . docker ) ;
} ) ;
self . sql _panel _obj = self . docker . findPanels ( 'sql_panel' ) [ 0 ] ;
self . history _panel = self . docker . findPanels ( 'history' ) [ 0 ] ;
self . data _output _panel = self . docker . findPanels ( 'data_output' ) [ 0 ] ;
self . explain _panel = self . docker . findPanels ( 'explain' ) [ 0 ] ;
self . messages _panel = self . docker . findPanels ( 'messages' ) [ 0 ] ;
self . notifications _panel = self . docker . findPanels ( 'notifications' ) [ 0 ] ;
2020-04-15 05:53:54 -05:00
if ( _ . isUndefined ( self . sql _panel _obj ) || _ . isUndefined ( self . history _panel ) ||
_ . isUndefined ( self . data _output _panel ) || _ . isUndefined ( self . explain _panel ) ||
_ . isUndefined ( self . messages _panel ) || _ . isUndefined ( self . notifications _panel ) ) {
alertify . alert (
gettext ( 'Panel Loading Error' ) ,
gettext ( 'Something went wrong while loading the panels.'
+ ' Please make sure to reset the layout (File > Reset Layout) for the better user experience.' )
) ;
}
2019-03-26 10:08:45 -05:00
// Refresh Code mirror on SQL panel resize to
// display its value properly
self . sql _panel _obj . on ( wcDocker . EVENT . RESIZE _ENDED , function ( ) {
setTimeout ( function ( ) {
if ( self && self . query _tool _obj ) {
self . query _tool _obj . refresh ( ) ;
}
} , 200 ) ;
} ) ;
2017-08-21 09:27:29 -05:00
self . render _history _grid ( ) ;
2019-08-23 06:14:20 -05:00
pgBrowser . Events . on ( 'pgadmin:query_tool:connected:' + self . handler . transId , ( ) => {
self . fetch _query _history ( ) ;
} ) ;
2018-05-30 20:58:28 -05:00
queryToolNotifications . renderNotificationsGrid ( self . notifications _panel ) ;
2017-08-21 09:27:29 -05:00
2019-06-10 05:10:49 -05:00
var text _container = $ ( '<textarea id="sql_query_tool" tabindex="-1"></textarea>' ) ;
2020-09-15 02:33:18 -05:00
var output _container = $ ( '<label for="sql_query_tool" class="sr-only">SQL Editor</label><div id="output-panel" tabindex="0"></div>' ) . append ( text _container ) ;
2019-03-26 10:08:45 -05:00
self . sql _panel _obj . $container . find ( '.pg-panel-content' ) . append ( output _container ) ;
self . query _tool _obj = CodeMirror . fromTextArea ( text _container . get ( 0 ) , {
tabindex : '0' ,
lineNumbers : true ,
styleSelectedText : true ,
mode : self . handler . server _type === 'gpdb' ? 'text/x-gpsql' : 'text/x-pgsql' ,
foldOptions : {
widget : '\u2026' ,
} ,
2019-09-04 09:46:08 -05:00
foldGutter : true ,
2019-03-26 10:08:45 -05:00
gutters : [ 'CodeMirror-linenumbers' , 'CodeMirror-foldgutter' ] ,
extraKeys : pgBrowser . editor _shortcut _keys ,
scrollbarStyle : 'simple' ,
2019-06-27 09:30:05 -05:00
dragDrop : false ,
2020-06-08 01:56:12 -05:00
screenReaderLabel : gettext ( 'SQL editor' ) ,
2019-03-26 10:08:45 -05:00
} ) ;
2019-06-27 09:30:05 -05:00
if ( self . handler . is _query _tool ) {
self . query _tool _obj . setOption ( 'dragDrop' , true ) ;
self . query _tool _obj . on ( 'drop' , ( editor , e ) => {
2019-08-02 05:28:57 -05:00
var dropDetails = null ;
try {
2019-08-12 02:41:56 -05:00
dropDetails = JSON . parse ( e . dataTransfer . getData ( 'text' ) ) ;
2019-08-02 05:28:57 -05:00
/* Stop firefox from redirecting */
if ( e . preventDefault ) {
e . preventDefault ( ) ;
}
if ( e . stopPropagation ) {
e . stopPropagation ( ) ;
}
} catch ( error ) {
/* if parsing fails, it must be the drag internal of codemirror text */
return ;
2019-07-04 08:49:09 -05:00
}
2019-08-02 05:28:57 -05:00
2019-06-27 09:30:05 -05:00
var cursor = editor . coordsChar ( {
left : e . x ,
top : e . y ,
} ) ;
editor . replaceRange ( dropDetails . text , cursor ) ;
editor . focus ( ) ;
editor . setSelection ( {
... cursor ,
ch : cursor . ch + dropDetails . cur . from ,
} , {
... cursor ,
ch : cursor . ch + dropDetails . cur . to ,
} ) ;
} ) ;
}
2019-06-10 05:10:49 -05:00
pgBrowser . Events . on ( 'pgadmin:query_tool:sql_panel:focus' , ( ) => {
self . query _tool _obj . focus ( ) ;
} ) ;
2019-12-31 23:21:45 -06:00
pgBrowser . Events . on ( 'pgadmin:query_tool:explain:focus' , ( ) => {
setTimeout ( function ( ) {
$ ( '.sql-editor-explain .backform-tab .nav-link.active' ) . focus ( ) ;
} , 200 ) ;
} ) ;
2020-11-04 06:15:28 -06:00
var open _new _tab = self . browser _preferences . new _browser _tab _open ;
2020-11-08 07:44:08 -06:00
if ( _ . isNull ( open _new _tab ) || _ . isUndefined ( open _new _tab ) || ! open _new _tab . includes ( 'qt' ) ) {
2017-08-21 09:27:29 -05:00
// Listen on the panel closed event and notify user to save modifications.
2019-09-23 02:25:02 -05:00
_ . each ( pgWindow . default . pgAdmin . Browser . docker . findPanels ( 'frm_datagrid' ) , function ( p ) {
2017-08-21 09:27:29 -05:00
if ( p . isVisible ( ) ) {
2018-07-05 05:38:43 -05:00
p . on ( wcDocker . EVENT . CLOSING , function ( ) {
2019-07-17 05:45:20 -05:00
return self . handler . check _needed _confirmations _before _closing _panel ( true ) ;
2018-07-05 05:38:43 -05:00
} ) ;
2017-11-23 03:20:59 -06:00
2017-08-21 09:27:29 -05:00
// Set focus on query tool of active panel
2018-01-12 01:29:51 -06:00
p . on ( wcDocker . EVENT . GAIN _FOCUS , function ( ) {
2018-01-12 08:34:39 -06:00
var $container = $ ( this . $container ) ,
transId = self . handler . transId ;
if ( ! $container . hasClass ( 'wcPanelTabContentHidden' ) ) {
2018-01-17 01:54:25 -06:00
setTimeout ( function ( ) {
self . handler . gridView . query _tool _obj . focus ( ) ;
} , 200 ) ;
2018-01-12 08:34:39 -06:00
// Trigger an event to update connection status flag
pgBrowser . Events . trigger (
'pgadmin:query_tool:panel:gain_focus:' + transId
) ;
2017-08-21 09:27:29 -05:00
}
} ) ;
2018-01-12 08:34:39 -06:00
// When any query tool panel lost it focus then
p . on ( wcDocker . EVENT . LOST _FOCUS , function ( ) {
var $container = $ ( this . $container ) ,
2018-02-01 07:29:18 -06:00
transId = self . handler . transId ;
2018-01-12 08:34:39 -06:00
// Trigger an event to update connection status flag
if ( $container . hasClass ( 'wcPanelTabContentHidden' ) ) {
pgBrowser . Events . trigger (
'pgadmin:query_tool:panel:lost_focus:' + transId
) ;
2018-01-17 01:54:25 -06:00
}
} ) ;
}
} ) ;
2018-01-12 08:34:39 -06:00
// Code to update connection status polling flag
pgBrowser . Events . on (
'pgadmin:query_tool:panel:gain_focus:' + self . handler . transId ,
self . gain _focus , self
) ;
pgBrowser . Events . on (
'pgadmin:query_tool:panel:lost_focus:' + self . handler . transId ,
self . lost _focus , self
) ;
2017-08-21 09:27:29 -05:00
}
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// set focus on query tool once loaded
2018-01-12 01:29:51 -06:00
setTimeout ( function ( ) {
2017-08-21 09:27:29 -05:00
self . query _tool _obj . focus ( ) ;
} , 500 ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
/ * W e h a v e o v e r r i d e / r e g i s t e r t h e h i n t f u n c t i o n o f C o d e M i r r o r
* to provide our own hint logic .
* /
2018-01-12 01:29:51 -06:00
CodeMirror . registerHelper ( 'hint' , 'sql' , function ( editor ) {
2017-08-21 09:27:29 -05:00
var data = [ ] ,
doc = editor . getDoc ( ) ,
cur = doc . getCursor ( ) ,
// Get the current cursor position
current _cur = cur . ch ,
// function context
ctx = {
editor : editor ,
// URL for auto-complete
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.autocomplete' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
data : data ,
// Get the line number in the cursor position
current _line : cur . line ,
/ *
* Render function for hint to add our own class
* and icon as per the object type .
* /
2020-07-09 08:14:58 -05:00
hint _render : function ( elt , data _arg , cur _arg ) {
2017-08-21 09:27:29 -05:00
var el = document . createElement ( 'span' ) ;
2016-04-14 09:04:03 -05:00
2020-07-09 08:14:58 -05:00
switch ( cur _arg . type ) {
2018-01-12 01:29:51 -06:00
case 'database' :
2020-07-09 08:14:58 -05:00
el . className = 'sqleditor-hint pg-icon-' + cur _arg . type ;
2018-01-12 01:29:51 -06:00
break ;
case 'datatype' :
el . className = 'sqleditor-hint icon-type' ;
break ;
case 'keyword' :
el . className = 'fa fa-key' ;
break ;
case 'table alias' :
el . className = 'fa fa-at' ;
break ;
default :
2020-07-09 08:14:58 -05:00
el . className = 'sqleditor-hint icon-' + cur _arg . type ;
2017-08-21 09:27:29 -05:00
}
2016-04-14 09:04:03 -05:00
2020-07-09 08:14:58 -05:00
el . appendChild ( document . createTextNode ( cur _arg . text ) ) ;
2017-08-21 09:27:29 -05:00
elt . appendChild ( el ) ;
2018-01-12 01:29:51 -06:00
} ,
2017-08-21 09:27:29 -05:00
} ;
2017-06-12 07:25:52 -05:00
2017-08-21 09:27:29 -05:00
data . push ( doc . getValue ( ) ) ;
// Get the text from start to the current cursor position.
data . push (
2018-01-12 01:29:51 -06:00
doc . getRange ( {
line : 0 ,
ch : 0 ,
} , {
line : ctx . current _line ,
ch : current _cur ,
} )
2017-08-21 09:27:29 -05:00
) ;
2016-09-07 10:20:47 -05:00
2017-08-21 09:27:29 -05:00
return {
2018-01-12 01:29:51 -06:00
then : function ( cb ) {
2020-07-09 08:14:58 -05:00
var self _local = this ;
2017-08-21 09:27:29 -05:00
// Make ajax call to find the autocomplete data
$ . ajax ( {
2020-07-09 08:14:58 -05:00
url : self _local . url ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2020-07-09 08:14:58 -05:00
data : JSON . stringify ( self _local . data ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
var result = [ ] ;
_ . each ( res . data . result , function ( obj , key ) {
result . push ( {
text : key ,
type : obj . object _type ,
2020-07-09 08:14:58 -05:00
render : self _local . hint _render ,
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ) ;
2019-03-14 10:11:16 -05:00
// Sort function to sort the suggestion's alphabetically.
result . sort ( function ( a , b ) {
var textA = a . text . toLowerCase ( ) ,
textB = b . text . toLowerCase ( ) ;
if ( textA < textB ) //sort string ascending
return - 1 ;
if ( textA > textB )
return 1 ;
return 0 ; //default return value (no sorting)
} ) ;
2016-09-05 11:18:43 -05:00
2019-03-14 10:11:16 -05:00
/ *
2018-07-09 07:54:00 -05:00
* Below logic find the start and end point
* to replace the selected auto complete suggestion .
* /
2020-07-09 08:14:58 -05:00
var token = self _local . editor . getTokenAt ( cur ) ,
2019-03-14 10:11:16 -05:00
start , end , search ;
if ( token . end > cur . ch ) {
token . end = cur . ch ;
token . string = token . string . slice ( 0 , cur . ch - token . start ) ;
}
2016-09-16 04:18:49 -05:00
2019-03-14 10:11:16 -05:00
if ( token . string . match ( /^[.`\w@]\w*$/ ) ) {
search = token . string ;
start = token . start ;
end = token . end ;
} else {
start = end = cur . ch ;
search = '' ;
}
2016-04-14 09:04:03 -05:00
2019-03-14 10:11:16 -05:00
/ *
2018-07-09 07:54:00 -05:00
* Added 1 in the start position if search string
* started with "." or "`" else auto complete of code mirror
* will remove the "." when user select any suggestion .
* /
2019-03-14 10:11:16 -05:00
if ( search . charAt ( 0 ) == '.' || search . charAt ( 0 ) == '``' )
start += 1 ;
cb ( {
list : result ,
from : {
2020-07-09 08:14:58 -05:00
line : self _local . current _line ,
2019-03-14 10:11:16 -05:00
ch : start ,
} ,
to : {
2020-07-09 08:14:58 -05:00
line : self _local . current _line ,
2019-03-14 10:11:16 -05:00
ch : end ,
} ,
} ) ;
} )
. fail ( function ( e ) {
return httpErrorHandler . handleLoginRequiredAndTransactionRequired (
2020-07-09 08:14:58 -05:00
pgAdmin , self _local , e , null , [ ] , false
2019-03-14 10:11:16 -05:00
) ;
2018-07-09 07:54:00 -05:00
} ) ;
2018-01-12 01:29:51 -06:00
} . bind ( ctx ) ,
2017-08-21 09:27:29 -05:00
} ;
} ) ;
2019-03-14 10:11:16 -05:00
/ * I f t h e s c r e e n w i d t h i s s m a l l a n d w e h o v e r o v e r t h e E x p l a i n O p t i o n s ,
2018-08-21 07:09:36 -05:00
* the submenu goes behind the screen on the right side .
* Below logic will make it appear on the left .
* /
$ ( '.dropdown-submenu' ) . on ( 'mouseenter' , function ( ) {
var menu = $ ( this ) . find ( 'ul.dropdown-menu' ) ;
var menupos = $ ( menu ) . offset ( ) ;
if ( menupos . left + menu . width ( ) > $ ( window ) . width ( ) ) {
var newpos = - $ ( menu ) . width ( ) ;
menu . css ( 'left' , newpos ) ;
}
} ) . on ( 'mouseleave' , function ( ) {
var menu = $ ( this ) . find ( 'ul.dropdown-menu' ) ;
menu . css ( 'left' , '' ) ;
} ) ;
2018-01-12 08:34:39 -06:00
2018-07-05 05:38:43 -05:00
self . reflectPreferences ( ) ;
2019-03-04 04:44:13 -06:00
/* Set Auto-commit and auto-rollback on query editor */
if ( self . preferences . auto _commit ) {
$ ( '.auto-commit' ) . removeClass ( 'visibility-hidden' ) ;
}
else {
$ ( '.auto-commit' ) . addClass ( 'visibility-hidden' ) ;
}
if ( self . preferences . auto _rollback ) {
$ ( '.auto-rollback' ) . removeClass ( 'visibility-hidden' ) ;
}
else {
$ ( '.auto-rollback' ) . addClass ( 'visibility-hidden' ) ;
}
2018-07-05 05:38:43 -05:00
/ * R e g i s t e r f o r p r e f e r e n c e c h a n g e d e v e n t b r o a d c a s t e d i n p a r e n t
* to reload the shorcuts . As sqleditor is in iFrame of wcDocker
* window parent is referred
* /
2019-09-23 02:25:02 -05:00
pgWindow . default . pgAdmin . Browser . onPreferencesChange ( 'sqleditor' , function ( ) {
2018-07-05 05:38:43 -05:00
self . reflectPreferences ( ) ;
} ) ;
/ * I f s q l e d i t o r i s i n a n e w t a b , e v e n t f i r e d i s n o t a v a i l a b l e
* instead , a poller is set up who will check
* /
2020-11-04 06:15:28 -06:00
//var browser_qt_preferences = pgBrowser.get_preferences_for_module('browser');
var open _new _tab _qt = self . browser _preferences . new _browser _tab _open ;
if ( open _new _tab _qt && open _new _tab _qt . includes ( 'qt' ) ) {
2019-06-27 09:37:50 -05:00
pgBrowser . bind _beforeunload ( ) ;
2018-07-05 05:38:43 -05:00
setInterval ( ( ) => {
2019-09-23 02:25:02 -05:00
if ( pgWindow . default . pgAdmin ) {
2018-07-05 05:38:43 -05:00
self . reflectPreferences ( ) ;
}
} , 1000 ) ;
2018-01-12 08:34:39 -06:00
}
2020-01-15 06:37:46 -06:00
/* Register to log the activity */
pgBrowser . register _to _activity _listener ( document , ( ) => {
2020-01-28 07:06:42 -06:00
alertify . alert ( gettext ( 'Timeout' ) , gettext ( 'Your session has timed out due to inactivity. Please close the window and login again.' ) ) ;
2020-01-15 06:37:46 -06:00
} ) ;
2020-10-01 02:59:00 -05:00
self . render _connection ( self . connection _list ) ;
2018-01-12 08:34:39 -06:00
} ,
2017-08-21 09:27:29 -05:00
/ * R e g a r d i n g S l i c k G r i d u s a g e i n r e n d e r _ g r i d f u n c t i o n .
SlickGrid Plugins :
-- -- -- -- -- -- -- -- --
1 ) Slick . AutoTooltips
- This plugin is useful for displaying cell data as tooltip when
user hover mouse on cell if data is large
2 ) Slick . CheckboxSelectColumn
- This plugin is useful for selecting rows using checkbox
3 ) RowSelectionModel
- This plugin is needed by CheckboxSelectColumn plugin to select rows
2018-08-30 07:59:31 -05:00
4 ) Slick . HeaderButtons
- This plugin is useful for add buttons in column header
2017-08-21 09:27:29 -05:00
Grid Options :
-- -- -- -- -- -- -
1 ) editable
- This option allow us to make grid editable
2 ) enableAddRow
- This option allow us to add new rows at the end of grid
3 ) enableCellNavigation
- This option allow us to navigate cells using keyboard
4 ) enableColumnReorder
- This option allow us to record column
5 ) asyncEditorLoading
- This option allow us to open editor async
6 ) autoEdit
- This option allow us to enter in edit mode directly when user clicks on it
otherwise user have to double click or manually press enter on cell to go
in cell edit mode
Handling of data :
-- -- -- -- -- -- -- -- -
We are doing data handling manually , what user adds / updates / deletes etc
we will use ` data_store ` object to store everything user does within grid data
- updated :
This will hold all the data which user updates in grid
- added :
This will hold all the new row ( s ) data which user adds in grid
- staged _rows :
This will hold all the data which user copies / pastes / deletes in grid
- deleted :
This will hold all the data which user deletes in grid
Events handling :
-- -- -- -- -- -- -- --
1 ) onCellChange
- We are using this event to listen to changes on individual cell .
2 ) onAddNewRow
- We are using this event to listen to new row adding functionality .
3 ) onSelectedRangesChanged
- We are using this event to listen when user selects rows for copy / delete operation .
4 ) onBeforeEditCell
- We are using this event to save the data before users modified them
5 ) onKeyDown
- We are using this event for Copy operation on grid
* /
2016-08-29 09:47:01 -05:00
2017-08-21 09:27:29 -05:00
// This function is responsible to create and render the SlickGrid.
2019-08-09 01:15:05 -05:00
render _grid : function ( collection , columns , is _editable , client _primary _key , rows _affected ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2016-04-14 09:04:03 -05:00
2019-07-17 05:45:20 -05:00
self . handler . numberOfModifiedCells = 0 ;
self . handler . reset _data _store ( ) ;
// keep track of newly added rows
self . handler . rows _to _disable = new Array ( ) ;
// Temporarily hold new rows added
self . handler . temp _new _rows = new Array ( ) ;
2016-09-02 10:05:00 -05:00
2017-08-21 09:27:29 -05:00
// To store primary keys before they gets changed
self . handler . primary _keys _data = { } ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
self . client _primary _key = client _primary _key ;
2017-06-27 08:03:04 -05:00
2017-08-21 09:27:29 -05:00
self . client _primary _key _counter = 0 ;
2017-05-15 09:04:16 -05:00
2017-08-21 09:27:29 -05:00
// Remove any existing grid first
if ( self . handler . slickgrid ) {
self . handler . slickgrid . destroy ( ) ;
}
2016-04-14 09:04:03 -05:00
2018-01-12 01:29:51 -06:00
if ( ! _ . isArray ( collection ) || ! _ . size ( collection ) ) {
collection = [ ] ;
}
2016-04-14 09:04:03 -05:00
2018-01-12 01:29:51 -06:00
var grid _columns = [ ] ,
table _name ;
var column _size = self . handler [ 'col_size' ] ,
query = self . handler . query ,
// Extract table name from query
table _list = query . match ( /select.*from\s+\w+\.*(\w+)/i ) ;
2017-08-21 09:27:29 -05:00
if ( ! table _list ) {
table _name = SqlEditorUtils . getHash ( query ) ;
2018-01-12 01:29:51 -06:00
} else {
2017-08-21 09:27:29 -05:00
table _name = table _list [ 1 ] ;
}
self . handler [ 'table_name' ] = table _name ;
column _size [ table _name ] = column _size [ table _name ] || { } ;
2018-01-12 01:29:51 -06:00
_ . each ( columns , function ( c ) {
2019-08-01 07:17:00 -05:00
c . display _name = _ . escape ( c . display _name ) ;
c . column _type = _ . escape ( c . column _type ) ;
2020-09-07 07:40:27 -05:00
// If the keys have name from existing JS keywords then it may
// create problem. eg - contructor, hasOwnProperty.
// nonative_field is field with extra double quotes
2017-08-21 09:27:29 -05:00
var options = {
2020-08-06 02:00:10 -05:00
id : _ . escape ( c . name ) ,
2017-08-21 09:27:29 -05:00
pos : c . pos ,
field : c . name ,
2020-09-07 07:40:27 -05:00
nonative _field : ` " ${ c . name } " ` ,
2017-08-21 09:27:29 -05:00
name : c . label ,
2019-08-01 07:17:00 -05:00
display _name : c . display _name ,
2017-08-21 09:27:29 -05:00
column _type : c . column _type ,
column _type _internal : c . column _type _internal ,
2019-10-25 05:53:39 -05:00
cell : c . cell ,
2017-08-21 09:27:29 -05:00
not _null : c . not _null ,
2017-09-18 01:37:15 -05:00
has _default _val : c . has _default _val ,
2018-01-12 01:29:51 -06:00
is _array : c . is _array ,
2019-08-26 03:47:40 -05:00
can _edit : c . can _edit ,
2017-08-21 09:27:29 -05:00
} ;
// Get the columns width based on longer string among data type or
// column name.
var column _type = c . column _type . trim ( ) ;
2019-06-20 06:21:37 -05:00
var label = c . name . length > column _type . length ? _ . escape ( c . display _name ) : column _type ;
2017-06-08 06:41:56 -05:00
2020-09-07 07:40:27 -05:00
if ( _ . isUndefined ( column _size [ table _name ] [ options . nonative _field ] ) ) {
2017-08-21 09:27:29 -05:00
options [ 'width' ] = SqlEditorUtils . calculateColumnWidth ( label ) ;
2020-09-07 07:40:27 -05:00
column _size [ table _name ] [ c . nonative _field ] = options [ 'width' ] ;
2018-01-12 01:29:51 -06:00
} else {
2020-09-07 07:40:27 -05:00
options [ 'width' ] = column _size [ table _name ] [ options . nonative _field ] ;
2017-06-08 06:41:56 -05:00
}
2017-08-21 09:27:29 -05:00
// If grid is editable then add editor else make it readonly
2019-02-22 10:18:39 -06:00
if ( c . cell == 'oid' && c . name == 'oid' ) {
2017-12-13 04:28:31 -06:00
options [ 'editor' ] = null ;
2018-01-12 01:29:51 -06:00
} else if ( c . cell == 'Json' ) {
2019-08-26 03:47:40 -05:00
options [ 'editor' ] = c . can _edit ? Slick . Editors . JsonText :
2018-01-12 01:29:51 -06:00
Slick . Editors . ReadOnlyJsonText ;
2017-12-13 05:53:27 -06:00
options [ 'formatter' ] = Slick . Formatters . JsonString ;
2019-02-22 10:18:39 -06:00
} else if ( c . cell == 'number' || c . cell == 'oid' ||
$ . inArray ( c . type , [ 'xid' , 'real' ] ) !== - 1
2017-08-21 09:27:29 -05:00
) {
2019-08-26 03:47:40 -05:00
options [ 'editor' ] = c . can _edit ? Slick . Editors . CustomNumber :
2018-01-12 01:29:51 -06:00
Slick . Editors . ReadOnlyText ;
2017-12-13 05:53:27 -06:00
options [ 'formatter' ] = Slick . Formatters . Numbers ;
2017-08-21 09:27:29 -05:00
} else if ( c . cell == 'boolean' ) {
2019-08-26 03:47:40 -05:00
options [ 'editor' ] = c . can _edit ? Slick . Editors . Checkbox :
2018-01-12 01:29:51 -06:00
Slick . Editors . ReadOnlyCheckbox ;
2017-12-13 05:53:27 -06:00
options [ 'formatter' ] = Slick . Formatters . Checkmark ;
2017-09-18 01:37:15 -05:00
} else if ( c . cell == 'binary' ) {
// We do not support editing binary data in SQL editor and data grid.
2018-01-12 01:29:51 -06:00
options [ 'formatter' ] = Slick . Formatters . Binary ;
2018-08-30 07:59:31 -05:00
} else if ( c . cell == 'geometry' || c . cell == 'geography' ) {
// increase width to add 'view' button
options [ 'width' ] += 28 ;
2019-08-26 03:47:40 -05:00
options [ 'can_edit' ] = false ;
2018-01-12 01:29:51 -06:00
} else {
2019-08-26 03:47:40 -05:00
options [ 'editor' ] = c . can _edit ? Slick . Editors . pgText :
2018-01-12 01:29:51 -06:00
Slick . Editors . ReadOnlypgText ;
2017-12-13 05:53:27 -06:00
options [ 'formatter' ] = Slick . Formatters . Text ;
2017-08-21 09:27:29 -05:00
}
2016-09-01 05:50:48 -05:00
2019-08-26 03:47:40 -05:00
if ( ! _ . isUndefined ( c . can _edit ) ) {
// Increase width for editable/read-only icon
options [ 'width' ] += 12 ;
let tooltip = '' ;
if ( c . can _edit )
tooltip = gettext ( 'Editable column' ) ;
else
tooltip = gettext ( 'Read-only column' ) ;
options [ 'toolTip' ] = tooltip ;
}
2018-01-12 01:29:51 -06:00
grid _columns . push ( options ) ;
2017-08-21 09:27:29 -05:00
} ) ;
2017-06-08 06:41:56 -05:00
2017-08-21 09:27:29 -05:00
var gridSelector = new GridSelector ( ) ;
grid _columns = self . grid _columns = gridSelector . getColumnDefinitions ( grid _columns ) ;
2016-12-12 04:13:53 -06:00
2018-08-30 07:59:31 -05:00
_ . each ( grid _columns , function ( c ) {
2019-08-26 03:47:40 -05:00
// Add 'view' button in geometry and geography type column headers
2018-08-30 07:59:31 -05:00
if ( c . column _type _internal == 'geometry' || c . column _type _internal == 'geography' ) {
GeometryViewer . add _header _button ( c ) ;
}
2019-08-26 03:47:40 -05:00
// Add editable/read-only icon to columns
if ( ! _ . isUndefined ( c . can _edit ) ) {
SqlEditorUtils . addEditableIcon ( c , c . can _edit ) ;
}
2018-08-30 07:59:31 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
if ( rows _affected ) {
// calculate with for header row column.
grid _columns [ 0 ] [ 'width' ] = SqlEditorUtils . calculateColumnWidth ( rows _affected ) ;
}
var grid _options = {
2019-08-09 01:15:05 -05:00
editable : true ,
2017-08-21 09:27:29 -05:00
enableAddRow : is _editable ,
enableCellNavigation : true ,
enableColumnReorder : false ,
asyncEditorLoading : false ,
2018-01-12 01:29:51 -06:00
autoEdit : false ,
2017-08-21 09:27:29 -05:00
} ;
2019-01-29 07:18:21 -06:00
var $data _grid = $ ( '#datagrid' ) ;
2017-08-21 09:27:29 -05:00
// Calculate height based on panel size at runtime & set it
2019-03-01 06:49:41 -06:00
var grid _height = $ ( this . data _output _panel . $container . parent ( ) . parent ( ) ) . height ( ) - 35 ;
2017-08-21 09:27:29 -05:00
$data _grid . height ( grid _height ) ;
var dataView = self . dataView = new Slick . Data . DataView ( ) ,
grid = self . grid = new Slick . Grid ( $data _grid , dataView , grid _columns , grid _options ) ;
// Add-on function which allow us to identify the faulty row after insert/update
// and apply css accordingly
2020-07-09 08:14:58 -05:00
dataView . getItemMetadata = function ( rows ) {
2018-01-12 01:29:51 -06:00
var cssClass = '' ,
2017-08-21 09:27:29 -05:00
data _store = self . handler . data _store ;
if ( _ . has ( self . handler , 'data_store' ) ) {
2020-07-09 08:14:58 -05:00
if ( rows in data _store . added _index &&
data _store . added _index [ rows ] in data _store . added ) {
2017-08-21 09:27:29 -05:00
cssClass = 'new_row' ;
2020-07-09 08:14:58 -05:00
if ( data _store . added [ data _store . added _index [ rows ] ] . err ) {
2017-08-21 09:27:29 -05:00
cssClass += ' error' ;
}
2020-07-09 08:14:58 -05:00
} else if ( rows in data _store . updated _index && rows in data _store . updated ) {
2017-08-21 09:27:29 -05:00
cssClass = 'updated_row' ;
2020-07-09 08:14:58 -05:00
if ( data _store . updated [ data _store . updated _index [ rows ] ] . err ) {
2017-08-21 09:27:29 -05:00
cssClass += ' error' ;
2016-08-29 09:47:01 -05:00
}
2017-08-21 09:27:29 -05:00
}
}
2017-11-22 10:38:18 -06:00
2017-08-21 09:27:29 -05:00
// Disable rows having default values
if ( ! _ . isUndefined ( self . handler . rows _to _disable ) &&
2018-01-12 01:29:51 -06:00
self . handler . rows _to _disable . length > 0 &&
2020-07-09 08:14:58 -05:00
_ . indexOf ( self . handler . rows _to _disable , rows ) !== - 1 ) {
2017-08-21 09:27:29 -05:00
cssClass += ' disabled_row' ;
}
2017-11-22 10:38:18 -06:00
2018-01-12 01:29:51 -06:00
return {
'cssClasses' : cssClass ,
} ;
2017-08-21 09:27:29 -05:00
} ;
2018-01-12 01:29:51 -06:00
grid . registerPlugin ( new Slick . AutoTooltips ( {
enableForHeaderCells : false ,
} ) ) ;
2017-08-21 09:27:29 -05:00
grid . registerPlugin ( new ActiveCellCapture ( ) ) ;
grid . setSelectionModel ( new XCellSelectionModel ( ) ) ;
grid . registerPlugin ( gridSelector ) ;
2019-02-26 07:44:16 -06:00
grid . registerPlugin ( new Slick . AutoColumnSize ( ) ) ;
2018-08-30 07:59:31 -05:00
var headerButtonsPlugin = new Slick . Plugins . HeaderButtons ( ) ;
headerButtonsPlugin . onCommand . subscribe ( function ( e , args ) {
let command = args . command ;
if ( command === 'view-geometries' ) {
2020-07-09 08:14:58 -05:00
let cols = args . grid . getColumns ( ) ;
let columnIndex = cols . indexOf ( args . column ) ;
2018-08-30 07:59:31 -05:00
let selectedRows = args . grid . getSelectedRows ( ) ;
if ( selectedRows . length === 0 ) {
// if no rows are selected, load and render all the rows
if ( self . handler . has _more _rows ) {
self . fetch _next _all ( function ( ) {
// trigger onGridSelectAll manually with new event data.
gridSelector . onGridSelectAll . notify ( args , new Slick . EventData ( ) ) ;
let items = args . grid . getData ( ) . getItems ( ) ;
2020-07-09 08:14:58 -05:00
GeometryViewer . render _geometries ( self . handler , items , cols , columnIndex ) ;
2018-08-30 07:59:31 -05:00
} ) ;
} else {
gridSelector . onGridSelectAll . notify ( args , new Slick . EventData ( ) ) ;
let items = args . grid . getData ( ) . getItems ( ) ;
2020-07-09 08:14:58 -05:00
GeometryViewer . render _geometries ( self . handler , items , cols , columnIndex ) ;
2018-08-30 07:59:31 -05:00
}
} else {
// render selected rows
let items = args . grid . getData ( ) . getItems ( ) ;
let selectedItems = _ . map ( selectedRows , function ( row ) {
return items [ row ] ;
} ) ;
2020-07-09 08:14:58 -05:00
GeometryViewer . render _geometries ( self . handler , selectedItems , cols , columnIndex ) ;
2018-08-30 07:59:31 -05:00
}
}
} ) ;
grid . registerPlugin ( headerButtonsPlugin ) ;
2017-08-21 09:27:29 -05:00
var editor _data = {
2017-12-13 04:28:31 -06:00
keys : ( _ . isEmpty ( self . handler . primary _keys ) && self . handler . has _oids ) ? self . handler . oids : self . handler . primary _keys ,
2017-08-21 09:27:29 -05:00
vals : collection ,
columns : columns ,
grid : grid ,
selection : grid . getSelectionModel ( ) ,
editor : self ,
2017-12-13 04:28:31 -06:00
client _primary _key : self . client _primary _key ,
2018-01-12 01:29:51 -06:00
has _oids : self . handler . has _oids ,
2017-08-21 09:27:29 -05:00
} ;
self . handler . slickgrid = grid ;
2021-02-05 02:27:35 -06:00
// Add listener on data-grid table scroll.
self . handler . slickgrid . onScroll . subscribe ( function ( ) {
2021-02-10 06:08:41 -06:00
// Mark selected rows cells as selected.
setTimeout ( ( ) => {
// Can't use setSelectedRows as we are using cellSelectionModel.
var cellSelectionModel = self . handler . gridView . grid . getSelectionModel ( ) ;
var ranges = cellSelectionModel . getSelectedRanges ( ) ;
if ( ranges . length > 1 ) {
// Set selected rows cell as selected.
cellSelectionModel . setSelectedRanges ( ranges ) ;
}
} , 100 ) ;
2021-02-05 02:27:35 -06:00
if ( Object . keys ( self . handler . data _store . deleted ) . length > 0 ) {
setTimeout ( ( ) => {
$ ( self . handler . gridView . grid . getCanvasNode ( ) ) . find ( 'div.selected' ) . removeClass ( 'strikeout' ) ;
$ ( self . handler . gridView . grid . getCanvasNode ( ) ) . find ( 'div.selected' ) . addClass ( 'strikeout' ) ;
} , 100 ) ;
}
} ) ;
2018-07-05 05:38:43 -05:00
self . handler . slickgrid . CSVOptions = {
quoting : self . preferences . results _grid _quoting ,
quote _char : self . preferences . results _grid _quote _char ,
field _separator : self . preferences . results _grid _field _separator ,
} ;
2017-08-21 09:27:29 -05:00
// Listener function to watch selected rows from grid
if ( editor _data . selection ) {
editor _data . selection . onSelectedRangesChanged . subscribe (
setStagedRows . bind ( editor _data ) ) ;
}
2016-09-12 06:39:40 -05:00
2018-01-12 01:29:51 -06:00
grid . onColumnsResized . subscribe ( function ( ) {
2020-07-09 08:14:58 -05:00
var cols = this . getColumns ( ) ;
_ . each ( cols , function ( col ) {
var col _size = self . handler [ 'col_size' ] ;
2020-09-07 07:40:27 -05:00
col _size [ self . handler [ 'table_name' ] ] [ col [ 'nonative_field' ] ] = col [ 'width' ] ;
2016-04-14 09:04:03 -05:00
} ) ;
2019-02-26 07:44:16 -06:00
} . bind ( grid ) ) ;
2017-08-21 09:27:29 -05:00
2018-01-12 01:29:51 -06:00
gridSelector . onBeforeGridSelectAll . subscribe ( function ( e , args ) {
2017-08-21 09:27:29 -05:00
if ( self . handler . has _more _rows ) {
// this will prevent selection un-till we load all data
e . stopImmediatePropagation ( ) ;
2018-01-12 01:29:51 -06:00
self . fetch _next _all ( function ( ) {
2017-08-21 09:27:29 -05:00
// since we've stopped event propagation we need to
// trigger onGridSelectAll manually with new event data.
gridSelector . onGridSelectAll . notify ( args , new Slick . EventData ( ) ) ;
} ) ;
}
} ) ;
2018-01-12 01:29:51 -06:00
gridSelector . onBeforeGridColumnSelectAll . subscribe ( function ( e , args ) {
2017-08-21 09:27:29 -05:00
if ( self . handler . has _more _rows ) {
// this will prevent selection un-till we load all data
e . stopImmediatePropagation ( ) ;
2018-01-12 01:29:51 -06:00
self . fetch _next _all ( function ( ) {
2017-08-21 09:27:29 -05:00
// since we've stopped event propagation we need to
// trigger onGridColumnSelectAll manually with new event data.
gridSelector . onGridColumnSelectAll . notify ( args , new Slick . EventData ( ) ) ;
} ) ;
}
} ) ;
// listen for row count change.
2018-01-12 01:29:51 -06:00
dataView . onRowCountChanged . subscribe ( function ( ) {
2017-08-21 09:27:29 -05:00
grid . updateRowCount ( ) ;
grid . render ( ) ;
} ) ;
// listen for rows change.
2018-01-12 01:29:51 -06:00
dataView . onRowsChanged . subscribe ( function ( e , args ) {
2017-08-21 09:27:29 -05:00
grid . invalidateRows ( args . rows ) ;
grid . render ( ) ;
} ) ;
// Listener function which will be called before user updates existing cell
// This will be used to collect primary key for that row
2018-01-12 01:29:51 -06:00
grid . onBeforeEditCell . subscribe ( function ( e , args ) {
2017-08-21 09:27:29 -05:00
if ( args . column . column _type _internal == 'bytea' ||
args . column . column _type _internal == 'bytea[]' ) {
return false ;
}
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
var before _data = args . item ;
2017-06-27 08:03:04 -05:00
2017-08-21 09:27:29 -05:00
// If newly added row is saved but grid is not refreshed,
// then disable cell editing for that row
if ( self . handler . rows _to _disable &&
_ . contains ( self . handler . rows _to _disable , args . row ) ) {
return false ;
2017-06-27 08:03:04 -05:00
}
2017-04-18 07:28:45 -05:00
2017-08-21 09:27:29 -05:00
if ( self . handler . can _edit && before _data && self . client _primary _key in before _data ) {
var _pk = before _data [ self . client _primary _key ] ,
_keys = self . handler . primary _keys ,
2018-01-12 01:29:51 -06:00
current _pk = { } ;
2016-08-29 09:47:01 -05:00
2017-08-21 09:27:29 -05:00
// If already have primary key data then no need to go ahead
if ( _pk in self . handler . primary _keys _data ) {
return ;
}
2016-06-02 04:12:22 -05:00
2017-08-21 09:27:29 -05:00
// Fetch primary keys for the row before they gets modified
2018-01-12 01:29:51 -06:00
_ . each ( _keys , function ( value , key ) {
2017-08-21 09:27:29 -05:00
current _pk [ key ] = before _data [ key ] ;
} ) ;
// Place it in main variable for later use
2018-01-12 01:29:51 -06:00
self . handler . primary _keys _data [ _pk ] = current _pk ;
2017-08-21 09:27:29 -05:00
}
} ) ;
2018-01-12 01:29:51 -06:00
grid . onKeyDown . subscribe ( function ( event , args ) {
2017-08-21 09:27:29 -05:00
var KEY _A = 65 ;
var modifiedKey = event . keyCode ;
var isModifierDown = event . ctrlKey || event . metaKey ;
// Intercept Ctrl/Cmd + A key board event.
// As we might want to load all rows before selecting all.
if ( isModifierDown && modifiedKey == KEY _A && self . handler . has _more _rows ) {
2018-01-12 01:29:51 -06:00
self . fetch _next _all ( function ( ) {
2017-08-21 09:27:29 -05:00
handleQueryOutputKeyboardEvent ( event , args ) ;
} ) ;
} else {
handleQueryOutputKeyboardEvent ( event , args ) ;
}
} ) ;
2020-07-24 04:00:22 -05:00
// Handles blur event for slick grid cell
$ ( '.slick-viewport' ) . on ( 'blur' , 'input.editor-text' , function ( ) {
window . setTimeout ( function ( ) {
if ( Slick . GlobalEditorLock . isActive ( ) )
Slick . GlobalEditorLock . commitCurrentEdit ( ) ;
} ) ;
} ) ;
2017-08-21 09:27:29 -05:00
// Listener function which will be called when user updates existing rows
2018-01-12 01:29:51 -06:00
grid . onCellChange . subscribe ( function ( e , args ) {
2017-08-21 09:27:29 -05:00
// self.handler.data_store.updated will holds all the updated data
var changed _column = args . grid . getColumns ( ) [ args . cell ] . field ,
2018-01-12 01:29:51 -06:00
updated _data = args . item [ changed _column ] , // New value for current field
_pk = args . item [ self . client _primary _key ] || null , // Unique key to identify row
column _data = { } ;
2017-08-21 09:27:29 -05:00
2019-07-17 05:45:20 -05:00
// Highlight the changed cell
self . handler . numberOfModifiedCells ++ ;
args . grid . addCellCssStyles ( self . handler . numberOfModifiedCells , {
[ args . row ] : {
[ changed _column ] : 'highlighted_grid_cells' ,
} ,
} ) ;
2017-08-21 09:27:29 -05:00
// Access to row/cell value after a cell is changed.
// The purpose is to remove row_id from temp_new_row
// if new row has primary key instead of [default_value]
// so that cell edit is enabled for that row.
2020-07-09 08:14:58 -05:00
var grid _edit = args . grid ,
row _data = grid _edit . getDataItem ( args . row ) ,
2017-11-22 10:38:18 -06:00
is _primary _key = self . primary _keys &&
2018-01-12 01:29:51 -06:00
_ . all (
_ . values (
_ . pick (
row _data , self . primary _keys
)
) ,
function ( val ) {
return val != undefined ;
}
) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// temp_new_rows is available only for view data.
if ( is _primary _key && self . handler . temp _new _rows ) {
var index = self . handler . temp _new _rows . indexOf ( args . row ) ;
if ( index > - 1 ) {
self . handler . temp _new _rows . splice ( index , 1 ) ;
}
}
2017-06-27 08:03:04 -05:00
2017-08-21 09:27:29 -05:00
column _data [ changed _column ] = updated _data ;
2017-05-15 09:04:16 -05:00
2017-12-13 04:28:31 -06:00
2017-08-21 09:27:29 -05:00
if ( _pk ) {
// Check if it is in newly added row by user?
if ( _pk in self . handler . data _store . added ) {
_ . extend (
self . handler . data _store . added [ _pk ] [ 'data' ] ,
column _data ) ;
//Find type for current column
2017-12-13 04:28:31 -06:00
self . handler . data _store . added [ _pk ] [ 'err' ] = false ;
2017-08-21 09:27:29 -05:00
// Check if it is updated data from existing rows?
} else if ( _pk in self . handler . data _store . updated ) {
_ . extend (
self . handler . data _store . updated [ _pk ] [ 'data' ] ,
column _data
) ;
2018-01-12 01:29:51 -06:00
self . handler . data _store . updated [ _pk ] [ 'err' ] = false ;
2017-08-21 09:27:29 -05:00
} else {
// First updated data for this primary key
self . handler . data _store . updated [ _pk ] = {
2018-01-12 01:29:51 -06:00
'err' : false ,
'data' : column _data ,
'primary_keys' : self . handler . primary _keys _data [ _pk ] ,
2017-08-21 09:27:29 -05:00
} ;
self . handler . data _store . updated _index [ args . row ] = _pk ;
2017-05-12 04:53:57 -05:00
}
2017-08-21 09:27:29 -05:00
}
// Enable save button
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-data' ) . prop ( 'disabled' , false ) ;
2017-08-21 09:27:29 -05:00
} . bind ( editor _data ) ) ;
// Listener function which will be called when user adds new rows
2018-01-12 01:29:51 -06:00
grid . onAddNewRow . subscribe ( function ( e , args ) {
2017-08-21 09:27:29 -05:00
// self.handler.data_store.added will holds all the newly added rows/data
var column = args . column ,
2020-07-09 08:14:58 -05:00
item _current = args . item ,
2018-01-12 01:29:51 -06:00
data _length = this . grid . getDataLength ( ) ,
2017-08-21 09:27:29 -05:00
_key = ( self . client _primary _key _counter ++ ) . toString ( ) ,
2020-07-09 08:14:58 -05:00
data _view = this . grid . getData ( ) ;
2017-08-21 09:27:29 -05:00
// Add new row in list to keep track of it
2020-07-09 08:14:58 -05:00
if ( _ . isUndefined ( item _current [ 0 ] ) ) {
2017-08-21 09:27:29 -05:00
self . handler . temp _new _rows . push ( data _length ) ;
}
2016-09-02 10:05:00 -05:00
2017-08-21 09:27:29 -05:00
// If copied item has already primary key, use it.
2020-07-09 08:14:58 -05:00
if ( item _current ) {
item _current [ self . client _primary _key ] = _key ;
2017-08-21 09:27:29 -05:00
}
2016-04-14 09:04:03 -05:00
2020-09-07 07:40:27 -05:00
// When adding new rows, mark all native JS keywords undefined if not already set
_ . each ( args . grid . getColumns ( ) , function ( col ) {
if ( isNative ( item _current [ col . field ] ) ) {
item _current [ col . field ] = undefined ;
}
} ) ;
2020-07-09 08:14:58 -05:00
data _view . addItem ( item _current ) ;
2018-01-12 01:29:51 -06:00
self . handler . data _store . added [ _key ] = {
'err' : false ,
2020-07-09 08:14:58 -05:00
'data' : item _current ,
2018-01-12 01:29:51 -06:00
} ;
2017-08-21 09:27:29 -05:00
self . handler . data _store . added _index [ data _length ] = _key ;
2019-07-17 05:45:20 -05:00
2017-08-21 09:27:29 -05:00
// Fetch data type & add it for the column
var temp = { } ;
2018-01-12 01:29:51 -06:00
temp [ column . name ] = _ . where ( this . columns , {
pos : column . pos ,
} ) [ 0 ] [ 'type' ] ;
2017-08-21 09:27:29 -05:00
grid . updateRowCount ( ) ;
grid . render ( ) ;
2019-07-17 05:45:20 -05:00
// Highlight the first added cell of the new row
2020-07-09 08:14:58 -05:00
var row = data _view . getRowByItem ( item _current ) ;
2019-07-17 05:45:20 -05:00
self . handler . numberOfModifiedCells ++ ;
args . grid . addCellCssStyles ( self . handler . numberOfModifiedCells , {
[ row ] : {
[ column . field ] : 'highlighted_grid_cells' ,
} ,
} ) ;
2017-08-21 09:27:29 -05:00
// Enable save button
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-data' ) . prop ( 'disabled' , false ) ;
2017-08-21 09:27:29 -05:00
} . bind ( editor _data ) ) ;
2020-04-24 00:43:13 -05:00
// Listen grid viewportChanged event to load next chunk of data.
grid . onViewportChanged . subscribe ( function ( e , args ) {
var rendered _range = args . grid . getRenderedRange ( ) ,
data _len = args . grid . getDataLength ( ) ;
// start fetching next batch of records before reaching to bottom.
if ( self . handler . has _more _rows && ! self . handler . fetching _rows && rendered _range . bottom > data _len - 100 ) {
// fetch asynchronous
2017-08-21 09:27:29 -05:00
setTimeout ( self . fetch _next . bind ( self ) ) ;
}
2017-11-23 03:07:46 -06:00
} ) ;
2019-09-12 19:27:38 -05:00
grid . onValidationError . subscribe ( function ( e , args ) {
alertify . error ( args . validationResults . msg ) ;
} ) ;
2017-08-21 09:27:29 -05:00
// Resize SlickGrid when window resize
2018-01-12 01:29:51 -06:00
$ ( window ) . resize ( function ( ) {
2017-08-21 09:27:29 -05:00
// Resize grid only when 'Data Output' panel is visible.
if ( self . data _output _panel . isVisible ( ) ) {
self . grid _resize ( grid ) ;
}
} ) ;
2016-06-16 03:57:44 -05:00
2017-08-21 09:27:29 -05:00
// Resize SlickGrid when output Panel resize
2018-01-12 01:29:51 -06:00
self . data _output _panel . on ( wcDocker . EVENT . RESIZE _ENDED , function ( ) {
2017-08-21 09:27:29 -05:00
// Resize grid only when 'Data Output' panel is visible.
if ( self . data _output _panel . isVisible ( ) ) {
self . grid _resize ( grid ) ;
}
} ) ;
// Resize SlickGrid when output Panel gets focus
2018-01-12 01:29:51 -06:00
self . data _output _panel . on ( wcDocker . EVENT . VISIBILITY _CHANGED , function ( ) {
2017-08-21 09:27:29 -05:00
// Resize grid only if output panel is visible
if ( self . data _output _panel . isVisible ( ) )
self . grid _resize ( grid ) ;
} ) ;
for ( var i = 0 ; i < collection . length ; i ++ ) {
// Convert to dict from 2darray
var item = { } ;
for ( var j = 1 ; j < grid _columns . length ; j ++ ) {
2018-01-12 01:29:51 -06:00
item [ grid _columns [ j ] [ 'field' ] ] = collection [ i ] [ grid _columns [ j ] [ 'pos' ] ] ;
2016-06-16 03:57:44 -05:00
}
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
item [ self . client _primary _key ] = ( self . client _primary _key _counter ++ ) . toString ( ) ;
collection [ i ] = item ;
}
dataView . setItems ( collection , self . client _primary _key ) ;
} ,
2019-07-17 05:45:20 -05:00
2018-01-12 01:29:51 -06:00
fetch _next _all : function ( cb ) {
2017-08-21 09:27:29 -05:00
this . fetch _next ( true , cb ) ;
} ,
2019-07-17 05:45:20 -05:00
2020-04-24 00:43:13 -05:00
fetch _next : function ( fetch _all , cb ) {
2018-01-12 01:29:51 -06:00
var self = this ,
url = '' ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// This will prevent fetch operation if previous fetch operation is
// already in progress.
self . handler . fetching _rows = true ;
2017-06-27 08:03:04 -05:00
2018-01-12 01:29:51 -06:00
$ ( '#btn-flash' ) . prop ( 'disabled' , true ) ;
2020-12-14 00:28:53 -06:00
$ ( '#btn-save-results-to-file' ) . prop ( 'disabled' , true ) ;
2017-08-21 09:27:29 -05:00
if ( fetch _all ) {
self . handler . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
gettext ( 'Fetching all records...' )
) ;
2018-01-12 01:29:51 -06:00
url = url _for ( 'sqleditor.fetch_all' , {
'trans_id' : self . transId ,
'fetch_all' : 1 ,
} ) ;
2017-08-21 09:27:29 -05:00
} else {
2020-04-24 00:43:13 -05:00
url = url _for ( 'sqleditor.fetch' , {
'trans_id' : self . transId ,
} ) ;
2017-08-21 09:27:29 -05:00
}
2020-04-24 00:43:13 -05:00
2017-08-21 09:27:29 -05:00
$ . ajax ( {
url : url ,
method : 'GET' ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
self . handler . has _more _rows = res . data . has _more _rows ;
$ ( '#btn-flash' ) . prop ( 'disabled' , false ) ;
2020-12-14 00:28:53 -06:00
$ ( '#btn-save-results-to-file' ) . prop ( 'disabled' , false ) ;
2019-03-14 10:11:16 -05:00
self . handler . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
2020-04-24 00:43:13 -05:00
self . update _grid _data ( res . data . result ) ;
2019-03-14 10:11:16 -05:00
self . handler . fetching _rows = false ;
if ( typeof cb == 'function' ) {
cb ( ) ;
}
} )
. fail ( function ( e ) {
$ ( '#btn-flash' ) . prop ( 'disabled' , false ) ;
2020-12-14 00:28:53 -06:00
$ ( '#btn-save-results-to-file' ) . prop ( 'disabled' , false ) ;
2019-03-14 10:11:16 -05:00
self . handler . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
self . handler . has _more _rows = false ;
self . handler . fetching _rows = false ;
if ( typeof cb == 'function' ) {
cb ( ) ;
}
2018-02-01 07:29:18 -06:00
2019-03-14 10:11:16 -05:00
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , null , [ ] , false
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
self . update _msg _history ( false , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2017-06-27 08:03:04 -05:00
2018-01-12 01:29:51 -06:00
update _grid _data : function ( data ) {
2017-08-21 09:27:29 -05:00
this . dataView . beginUpdate ( ) ;
2020-04-24 00:43:13 -05:00
for ( var i = 0 ; i < data . length ; i ++ ) {
2017-08-21 09:27:29 -05:00
// Convert 2darray to dict.
var item = { } ;
for ( var j = 1 ; j < this . grid _columns . length ; j ++ ) {
2018-01-12 01:29:51 -06:00
item [ this . grid _columns [ j ] [ 'field' ] ] = data [ i ] [ this . grid _columns [ j ] [ 'pos' ] ] ;
2017-08-21 09:27:29 -05:00
}
2017-06-27 08:03:04 -05:00
2020-04-24 00:43:13 -05:00
item [ this . client _primary _key ] = ( this . client _primary _key _counter ++ ) . toString ( ) ;
this . dataView . addItem ( item ) ;
2017-08-21 09:27:29 -05:00
}
2017-07-20 07:09:47 -05:00
2017-08-21 09:27:29 -05:00
this . dataView . endUpdate ( ) ;
} ,
2017-05-12 04:53:57 -05:00
2017-08-21 09:27:29 -05:00
/* This function is responsible to render output grid */
2018-01-12 01:29:51 -06:00
grid _resize : function ( grid ) {
2017-11-23 03:07:46 -06:00
var prev _height = $ ( '#datagrid' ) . height ( ) ,
2019-03-01 06:49:41 -06:00
h = $ ( this . data _output _panel . $container . parent ( ) . parent ( ) ) . height ( ) - 35 ,
2017-11-23 03:07:46 -06:00
prev _viewport = grid . getViewport ( ) ,
prev _viewport _rows = grid . getRenderedRange ( ) ,
prev _cell = grid . getActiveCell ( ) ;
// Apply css only if necessary, To avoid DOM operation
if ( prev _height != h ) {
2018-01-12 01:29:51 -06:00
$ ( '#datagrid' ) . css ( {
'height' : h + 'px' ,
} ) ;
2017-11-23 03:07:46 -06:00
}
2017-08-21 09:27:29 -05:00
grid . resizeCanvas ( ) ;
2017-11-23 03:07:46 -06:00
/ *
* If there is an active cell from user then we have to go to that cell
* /
2018-01-12 01:29:51 -06:00
if ( prev _cell ) {
2017-11-23 03:07:46 -06:00
grid . scrollCellIntoView ( prev _cell . row , prev _cell . cell ) ;
}
// If already displaying from first row
if ( prev _viewport . top == prev _viewport _rows . top ) {
2018-01-12 01:29:51 -06:00
return ;
2017-11-23 03:07:46 -06:00
}
// if user has scroll to the end/last row
else if ( prev _viewport . bottom - 2 == prev _viewport _rows . bottom ) {
grid . scrollRowIntoView ( prev _viewport . bottom ) ;
} else {
grid . scrollRowIntoView ( prev _viewport . bottom - 2 ) ;
}
2017-08-21 09:27:29 -05:00
} ,
2017-05-12 04:53:57 -05:00
2019-08-23 06:14:20 -05:00
fetch _query _history : function ( ) {
let self = this ;
$ . ajax ( {
url : url _for ( 'sqleditor.get_query_history' , {
'trans_id' : self . handler . transId ,
} ) ,
method : 'GET' ,
contentType : 'application/json' ,
} ) . done ( function ( res ) {
res . data . result . map ( ( entry ) => {
let newEntry = JSON . parse ( entry ) ;
newEntry . start _time = new Date ( newEntry . start _time ) ;
self . history _collection . add ( newEntry ) ;
} ) ;
} ) . fail ( function ( ) {
/* history fetch fail should not affect query tool */
} ) ;
} ,
2019-10-10 01:35:28 -05:00
/* This function is responsible to create and render the the history tab. */
2018-01-12 01:29:51 -06:00
render _history _grid : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2016-06-02 04:12:22 -05:00
2018-07-05 05:38:43 -05:00
/* Should not reset if function called again */
if ( ! self . history _collection ) {
2019-03-07 04:51:59 -06:00
self . history _collection = new HistoryCollection ( [ ] ) ;
2018-07-05 05:38:43 -05:00
}
2016-06-02 04:12:22 -05:00
2019-03-07 04:51:59 -06:00
if ( ! self . historyComponent ) {
self . historyComponent = new QueryHistory ( $ ( '#history_grid' ) , self . history _collection ) ;
2019-03-13 08:37:34 -05:00
/* Copy query to query editor, set the focus to editor and move cursor to end */
self . historyComponent . onCopyToEditorClick ( ( query ) => {
self . query _tool _obj . setValue ( query ) ;
self . sql _panel _obj . focus ( ) ;
setTimeout ( ( ) => {
self . query _tool _obj . focus ( ) ;
self . query _tool _obj . setCursor ( self . query _tool _obj . lineCount ( ) , 0 ) ;
} , 100 ) ;
} ) ;
2019-03-07 04:51:59 -06:00
self . historyComponent . render ( ) ;
2019-03-13 08:37:34 -05:00
self . history _panel . off ( wcDocker . EVENT . VISIBILITY _CHANGED ) ;
self . history _panel . on ( wcDocker . EVENT . VISIBILITY _CHANGED , function ( ) {
if ( self . history _panel . isVisible ( ) ) {
setTimeout ( ( ) => {
self . historyComponent . focus ( ) ;
} , 100 ) ;
}
} ) ;
2019-03-07 04:51:59 -06:00
}
2017-08-21 09:27:29 -05:00
2019-08-16 06:47:12 -05:00
if ( ! self . handler . is _query _tool ) {
2019-03-13 08:37:34 -05:00
self . historyComponent . setEditorPref ( { 'copy_to_editor' : false } ) ;
}
2017-08-21 09:27:29 -05:00
} ,
2019-04-18 01:39:35 -05:00
// Callback function for delete button click.
2018-01-12 01:29:51 -06:00
on _delete : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2019-04-18 01:39:35 -05:00
// Trigger the deleterow signal to the SqlEditorController class
2017-08-21 09:27:29 -05:00
self . handler . trigger (
'pgadmin-sqleditor:button:deleterow' ,
self ,
self . handler
) ;
} ,
2018-01-12 01:29:51 -06:00
_stopEventPropogation : function ( ev ) {
2017-08-21 09:27:29 -05:00
ev = ev || window . event ;
ev . cancelBubble = true ;
ev . stopPropagation ( ) ;
ev . stopImmediatePropagation ( ) ;
ev . preventDefault ( ) ;
} ,
2018-01-12 01:29:51 -06:00
_closeDropDown : function ( ev ) {
2017-08-21 09:27:29 -05:00
var target = ev && ( ev . currentTarget || ev . target ) ;
if ( target ) {
2019-01-22 04:35:02 -06:00
$ ( target ) . closest ( '.editor-toolbar' ) . find ( '.show' ) . removeClass ( 'show' ) ;
2017-08-21 09:27:29 -05:00
}
} ,
// Callback function for Save button click.
2019-07-17 05:45:20 -05:00
on _save _file : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
self . handler . close _on _save = false ;
// Trigger the save signal to the SqlEditorController class
self . handler . trigger (
2019-07-17 05:45:20 -05:00
'pgadmin-sqleditor:button:save_file'
2017-08-21 09:27:29 -05:00
) ;
} ,
// Callback function for Save button click.
2018-01-12 01:29:51 -06:00
on _save _as : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
self . handler . close _on _save = false ;
// Trigger the save signal to the SqlEditorController class
self . handler . trigger (
2019-07-17 05:45:20 -05:00
'pgadmin-sqleditor:button:save_file' ,
2017-08-21 09:27:29 -05:00
self ,
self . handler ,
true
) ;
} ,
// Callback function for the find button click.
2018-01-12 01:29:51 -06:00
on _find : function ( ev ) {
var self = this ;
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
2018-01-12 01:29:51 -06:00
self . query _tool _obj . execCommand ( 'find' ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for the find next button click.
2018-01-12 01:29:51 -06:00
on _find _next : function ( ev ) {
var self = this ;
2018-02-01 07:29:18 -06:00
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
2018-01-12 01:29:51 -06:00
self . query _tool _obj . execCommand ( 'findNext' ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for the find previous button click.
2018-01-12 01:29:51 -06:00
on _find _previous : function ( ev ) {
var self = this ;
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
2018-01-12 01:29:51 -06:00
self . query _tool _obj . execCommand ( 'findPrev' ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for the replace button click.
2018-01-12 01:29:51 -06:00
on _replace : function ( ev ) {
var self = this ;
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
2018-01-12 01:29:51 -06:00
self . query _tool _obj . execCommand ( 'replace' ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for the replace all button click.
2018-01-12 01:29:51 -06:00
on _replace _all : function ( ev ) {
var self = this ;
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
2018-01-12 01:29:51 -06:00
self . query _tool _obj . execCommand ( 'replaceAll' ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for the find persistent button click.
2018-01-12 01:29:51 -06:00
on _find _persistent : function ( ev ) {
var self = this ;
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
2018-01-12 01:29:51 -06:00
self . query _tool _obj . execCommand ( 'findPersistent' ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for the jump button click.
2018-01-12 01:29:51 -06:00
on _jump : function ( ev ) {
var self = this ;
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
2018-01-12 01:29:51 -06:00
self . query _tool _obj . execCommand ( 'jumpToLine' ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for filter button click.
2018-01-12 01:29:51 -06:00
on _show _filter : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
// Trigger the show_filter signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:show_filter' ,
self ,
self . handler
) ;
} ,
2020-10-01 02:59:00 -05:00
on _new _connection : function ( ) {
var self = this ;
// Trigger the show_filter signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:show_new_connection' ,
self ,
self . handler
) ;
} ,
2017-08-21 09:27:29 -05:00
// Callback function for include filter button click.
2018-01-12 01:29:51 -06:00
on _include _filter : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
// Trigger the include_filter signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:include_filter' ,
self ,
self . handler
) ;
} ,
// Callback function for exclude filter button click.
2018-01-12 01:29:51 -06:00
on _exclude _filter : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
// Trigger the exclude_filter signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:exclude_filter' ,
self ,
self . handler
) ;
} ,
// Callback function for remove filter button click.
2018-01-12 01:29:51 -06:00
on _remove _filter : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
// Trigger the remove_filter signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:remove_filter' ,
self ,
self . handler
) ;
} ,
// Callback function for cancel button click.
2018-01-12 01:29:51 -06:00
on _cancel : function ( ) {
2018-10-10 06:43:26 -05:00
$ ( '#filter' ) . addClass ( 'd-none' ) ;
2017-08-21 09:27:29 -05:00
$ ( '#editor-panel' ) . removeClass ( 'sql-editor-busy-fetching' ) ;
} ,
// Callback function for copy button click.
2018-01-12 01:29:51 -06:00
on _copy _row : function ( ) {
2018-07-05 05:38:43 -05:00
var self = this ;
2017-08-21 09:27:29 -05:00
// Trigger the copy signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:copy_row' ,
self ,
self . handler
) ;
2017-11-20 07:50:47 -06:00
2017-08-21 09:27:29 -05:00
} ,
2019-09-27 01:44:39 -05:00
// Callback function for copy with header button click.
on _copy _row _with _header : function ( ev ) {
var self = this ;
this . _stopEventPropogation ( ev ) ;
// Toggle the button
self . handler . trigger (
'pgadmin-sqleditor:button:copy_row_with_header' ,
self ,
self . handler
) ;
} ,
2017-08-21 09:27:29 -05:00
// Callback function for paste button click.
2018-01-12 01:29:51 -06:00
on _paste _row : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
// Trigger the paste signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:paste_row' ,
self ,
self . handler
) ;
} ,
// Callback function for the change event of combo box
2018-01-12 01:29:51 -06:00
on _limit _change : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
// Trigger the limit signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:limit' ,
self ,
self . handler
) ;
} ,
2019-07-17 05:45:20 -05:00
// Callback function for Save Data Changes button click.
on _save _data : function ( ) {
2019-08-16 06:47:12 -05:00
this . handler . history _query _source = QuerySources . SAVE _DATA ;
2019-07-17 05:45:20 -05:00
queryToolActions . saveDataChanges ( this . handler ) ;
} ,
2017-08-21 09:27:29 -05:00
// Callback function for the flash button click.
2018-01-12 01:29:51 -06:00
on _flash : function ( ) {
2019-11-20 01:20:04 -06:00
let data _click _counter = $ ( '#btn-flash' ) . attr ( 'data-click-counter' ) ;
data _click _counter = ( parseInt ( data _click _counter ) + 1 ) % 10 ;
$ ( '#btn-flash' ) . attr ( 'data-click-counter' , data _click _counter ) ;
2019-08-16 06:47:12 -05:00
this . handler . history _query _source = QuerySources . EXECUTE ;
2017-08-21 09:27:29 -05:00
queryToolActions . executeQuery ( this . handler ) ;
} ,
// Callback function for the cancel query button click.
2018-01-12 01:29:51 -06:00
on _cancel _query : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
// Trigger the cancel-query signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:cancel-query' ,
self ,
self . handler
) ;
} ,
// Callback function for the line comment code
2018-01-12 01:29:51 -06:00
on _comment _line _code : function ( ) {
2017-08-21 09:27:29 -05:00
queryToolActions . commentLineCode ( this . handler ) ;
} ,
// Callback function for the line uncomment code
2018-01-12 01:29:51 -06:00
on _uncomment _line _code : function ( ) {
2017-08-21 09:27:29 -05:00
queryToolActions . uncommentLineCode ( this . handler ) ;
} ,
// Callback function for the block comment/uncomment code
2018-01-12 01:29:51 -06:00
on _toggle _comment _block _code : function ( ) {
2017-08-21 09:27:29 -05:00
queryToolActions . commentBlockCode ( this . handler ) ;
} ,
2018-01-12 01:29:51 -06:00
on _indent _code : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
// Trigger the comment signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:indent_selected_code' ,
self ,
self . handler
) ;
} ,
2018-01-12 01:29:51 -06:00
on _unindent _code : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
// Trigger the comment signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:unindent_selected_code' ,
self ,
self . handler
) ;
} ,
2020-08-20 02:35:00 -05:00
on _format _sql : function ( ) {
var self = this ;
// Trigger the format signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:format_sql' ,
self ,
self . handler
) ;
} ,
2017-08-21 09:27:29 -05:00
// Callback function for the clear button click.
2018-01-12 01:29:51 -06:00
on _clear : function ( ev ) {
var self = this ;
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
/ * I f i s _ q u e r y _ c h a n g e d f l a g i s s e t t o f a l s e t h e n n o n e e d t o
* confirm with the user for unsaved changes .
* /
if ( self . handler . is _query _changed ) {
alertify . confirm (
2018-01-12 01:29:51 -06:00
gettext ( 'Unsaved changes' ) ,
gettext ( 'Are you sure you wish to discard the current changes?' ) ,
function ( ) {
2017-08-21 09:27:29 -05:00
// Do nothing as user do not want to save, just continue
self . query _tool _obj . setValue ( '' ) ;
2018-01-29 07:43:35 -06:00
setTimeout ( ( ) => { self . query _tool _obj . focus ( ) ; } , 200 ) ;
2017-08-21 09:27:29 -05:00
} ,
2018-01-12 01:29:51 -06:00
function ( ) {
2017-08-21 09:27:29 -05:00
return true ;
2017-06-27 08:03:04 -05:00
}
2018-01-12 01:29:51 -06:00
) . set ( 'labels' , {
2018-01-25 06:27:13 -06:00
ok : gettext ( 'Yes' ) ,
cancel : gettext ( 'No' ) ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
} else {
self . query _tool _obj . setValue ( '' ) ;
}
} ,
// Callback function for the clear history button click.
2018-01-12 01:29:51 -06:00
on _clear _history : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
// ask for confirmation only if anything to clear
if ( ! self . history _collection . length ( ) ) {
return ;
}
2017-05-27 13:51:02 -05:00
2018-01-12 01:29:51 -06:00
alertify . confirm ( gettext ( 'Clear history' ) ,
2019-03-13 08:37:34 -05:00
gettext ( 'Are you sure you wish to clear the history?' ) + '</br>' +
gettext ( 'This will remove all of your query history from this and other sessions for this database.' ) ,
2018-01-12 01:29:51 -06:00
function ( ) {
2017-08-21 09:27:29 -05:00
if ( self . history _collection ) {
self . history _collection . reset ( ) ;
2017-05-27 13:51:02 -05:00
}
2019-03-13 08:37:34 -05:00
if ( self . handler . is _query _tool ) {
$ . ajax ( {
url : url _for ( 'sqleditor.clear_query_history' , {
'trans_id' : self . handler . transId ,
} ) ,
method : 'DELETE' ,
contentType : 'application/json' ,
} )
2019-03-14 10:11:16 -05:00
. done ( function ( ) { } )
. fail ( function ( ) {
2019-03-13 08:37:34 -05:00
/* history clear fail should not affect query tool */
2019-03-14 10:11:16 -05:00
} ) ;
2019-03-13 08:37:34 -05:00
}
2018-01-29 07:43:35 -06:00
setTimeout ( ( ) => { self . query _tool _obj . focus ( ) ; } , 200 ) ;
2017-08-21 09:27:29 -05:00
} ,
2018-01-12 01:29:51 -06:00
function ( ) {
2017-08-21 09:27:29 -05:00
return true ;
}
2018-01-12 01:29:51 -06:00
) . set ( 'labels' , {
2018-01-25 06:27:13 -06:00
ok : gettext ( 'Yes' ) ,
cancel : gettext ( 'No' ) ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
// Callback function for the auto commit button click.
2018-01-12 01:29:51 -06:00
on _auto _commit : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
// Trigger the auto-commit signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:auto_commit' ,
self ,
self . handler
) ;
} ,
// Callback function for the auto rollback button click.
2018-01-12 01:29:51 -06:00
on _auto _rollback : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
// Trigger the download signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:auto_rollback' ,
self ,
self . handler
) ;
} ,
// Callback function for explain button click.
2018-01-12 01:29:51 -06:00
on _explain : function ( event ) {
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( event ) ;
this . _closeDropDown ( event ) ;
2019-08-16 06:47:12 -05:00
this . handler . history _query _source = QuerySources . EXPLAIN ;
2017-08-21 09:27:29 -05:00
queryToolActions . explain ( this . handler ) ;
} ,
// Callback function for explain analyze button click.
2018-01-12 01:29:51 -06:00
on _explain _analyze : function ( event ) {
2017-08-21 09:27:29 -05:00
this . _stopEventPropogation ( event ) ;
this . _closeDropDown ( event ) ;
2019-08-16 06:47:12 -05:00
this . handler . history _query _source = QuerySources . EXPLAIN _ANALYZE ;
2017-08-21 09:27:29 -05:00
queryToolActions . explainAnalyze ( this . handler ) ;
} ,
// Callback function for explain option "verbose" button click
2018-01-12 01:29:51 -06:00
on _explain _verbose : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
// Trigger the explain "verbose" signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:explain-verbose' ,
self ,
self . handler
) ;
} ,
// Callback function for explain option "costs" button click
2018-01-12 01:29:51 -06:00
on _explain _costs : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
// Trigger the explain "costs" signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:explain-costs' ,
self ,
self . handler
) ;
} ,
// Callback function for explain option "buffers" button click
2018-01-12 01:29:51 -06:00
on _explain _buffers : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
// Trigger the explain "buffers" signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:explain-buffers' ,
self ,
self . handler
) ;
} ,
// Callback function for explain option "timing" button click
2018-01-12 01:29:51 -06:00
on _explain _timing : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
// Trigger the explain "timing" signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:explain-timing' ,
self ,
self . handler
) ;
} ,
2019-07-03 07:57:56 -05:00
on _explain _summary : function ( ev ) {
var self = this ;
this . _stopEventPropogation ( ev ) ;
self . handler . trigger (
'pgadmin-sqleditor:button:explain-summary' ,
self ,
self . handler
) ;
} ,
on _explain _settings : function ( ev ) {
var self = this ;
this . _stopEventPropogation ( ev ) ;
self . handler . trigger (
'pgadmin-sqleditor:button:explain-settings' ,
self ,
self . handler
) ;
} ,
2018-01-12 01:29:51 -06:00
do _not _close _menu : function ( ev ) {
2017-08-21 09:27:29 -05:00
ev . stopPropagation ( ) ;
} ,
2020-08-28 03:23:08 -05:00
// callback function for show query tool click.
on _show _query _tool : function ( ev ) {
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
self . handler . trigger (
'pgadmin-sqleditor:button:show_query_tool' ,
self ,
self . handler
) ;
} ,
2017-08-21 09:27:29 -05:00
// callback function for load file button click.
2018-01-12 01:29:51 -06:00
on _file _load : function ( ev ) {
2017-08-21 09:27:29 -05:00
var self = this ;
this . _stopEventPropogation ( ev ) ;
this . _closeDropDown ( ev ) ;
// Trigger the save signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:load_file' ,
self ,
self . handler
) ;
} ,
2018-01-12 01:29:51 -06:00
on _download : function ( ) {
2017-08-21 09:27:29 -05:00
queryToolActions . download ( this . handler ) ;
} ,
2018-01-12 01:29:51 -06:00
keyAction : function ( event ) {
2019-06-10 05:10:49 -05:00
var panel _type = '' ;
panel _type = keyboardShortcuts . processEventQueryTool (
this . handler , queryToolActions , event , this . docker
2018-01-25 06:27:13 -06:00
) ;
2019-06-10 05:10:49 -05:00
if ( ! _ . isNull ( panel _type ) && ! _ . isUndefined ( panel _type ) && panel _type != '' ) {
setTimeout ( function ( ) {
pgBrowser . Events . trigger ( ` pgadmin:query_tool: ${ panel _type } :focus ` ) ;
} , 100 ) ;
2018-01-25 06:27:13 -06:00
}
2018-01-12 01:29:51 -06:00
} ,
2019-06-10 05:10:49 -05:00
2019-02-22 08:28:05 -06:00
// Callback function for the commit button click.
on _commit _transaction : function ( ) {
2019-07-17 05:45:20 -05:00
this . handler . close _on _idle _transaction = false ;
2019-08-16 06:47:12 -05:00
this . handler . history _query _source = QuerySources . COMMIT ;
2019-02-22 08:28:05 -06:00
queryToolActions . executeCommit ( this . handler ) ;
} ,
// Callback function for the rollback button click.
on _rollback _transaction : function ( ) {
2019-07-17 05:45:20 -05:00
this . handler . close _on _idle _transaction = false ;
2019-08-16 06:47:12 -05:00
this . handler . history _query _source = QuerySources . ROLLBACK ;
2019-02-22 08:28:05 -06:00
queryToolActions . executeRollback ( this . handler ) ;
} ,
2020-09-28 04:56:45 -05:00
// Callback function for manage macros button click.
on _manage _macros : function ( ) {
var self = this ;
// Trigger the show_filter signal to the SqlEditorController class
self . handler . trigger (
'pgadmin-sqleditor:button:manage_macros' ,
self ,
self . handler
) ;
} ,
// Callback function for manage macros button click.
on _execute _macro : function ( e ) {
let macroId = $ ( e . currentTarget ) . data ( 'macro-id' ) ;
this . handler . history _query _source = QuerySources . EXECUTE ;
queryToolActions . executeMacro ( this . handler , macroId ) ;
} ,
2020-10-20 05:11:54 -05:00
set _selected _option : function ( selected _config ) {
this . connection _list . forEach ( option => {
2020-10-28 02:02:22 -05:00
if ( option [ 'server' ] == selected _config [ 'server' ] && option [ 'database' ] == selected _config [ 'database' ] && option [ 'user' ] == selected _config [ 'user' ] && option [ 'role' ] == selected _config [ 'role' ] ) {
2020-10-20 05:11:54 -05:00
selected _config [ 'is_selected' ] = true ;
} else {
option [ 'is_selected' ] = false ;
}
} ) ;
} ,
2020-10-28 02:02:22 -05:00
on _change _connection : function ( connection _details , ref , add _new _connection = true ) {
2020-10-20 05:11:54 -05:00
if ( ! connection _details [ 'is_selected' ] ) {
2020-10-01 02:59:00 -05:00
var self = this ;
2020-10-28 02:02:22 -05:00
if ( add _new _connection ) {
alertify . confirm ( gettext ( 'Change connection' ) ,
gettext ( 'By changing the connection you will lose all your unsaved data for the current connection. <br> Do you want to continue?' ) ,
function ( ) {
self . change _connection ( connection _details , ref , true ) ;
} ,
function ( ) {
var loadingDiv = $ ( '#fetching_data' ) ;
loadingDiv . addClass ( 'd-none' ) ;
alertify . newConnectionDialog ( ) . destroy ( ) ;
return true ;
}
) . set ( 'labels' , {
ok : gettext ( 'Yes' ) ,
cancel : gettext ( 'No' ) ,
} ) ;
} else {
self . change _connection ( connection _details , ref , false ) ;
2020-10-08 01:08:05 -05:00
}
2020-10-28 02:02:22 -05:00
}
} ,
2020-10-08 01:08:05 -05:00
2020-10-28 02:02:22 -05:00
change _connection : function ( connection _details , ref , add _new _connection ) {
var self = this ;
var loadingDiv = null ;
var msgDiv = null ;
if ( ref ) {
loadingDiv = $ ( '#show_filter_progress' ) ;
loadingDiv . removeClass ( 'd-none' ) ;
msgDiv = loadingDiv . find ( '.sql-editor-busy-text' ) ;
msgDiv . text ( 'Connecting to database...' ) ;
} else {
loadingDiv = $ ( '#fetching_data' ) ;
loadingDiv . removeClass ( 'd-none' ) ;
}
self . set _selected _option ( connection _details ) ;
$ . ajax ( {
url : url _for ( 'datagrid.update_query_tool_connection' , {
'trans_id' : self . transId ,
'sgid' : connection _details [ 'server_group' ] ,
'sid' : connection _details [ 'server' ] ,
'did' : connection _details [ 'database' ] ,
} ) ,
method : 'POST' ,
contentType : 'application/json' ,
data : JSON . stringify ( connection _details ) ,
} )
. done ( function ( res ) {
if ( res . success ) {
delete connection _details . password ;
self . transId = res . data . tran _id ;
self . handler . transId = res . data . tran _id ;
self . handler . url _params = {
'did' : connection _details [ 'database' ] ,
'is_query_tool' : self . handler . url _params . is _query _tool ,
'server_type' : self . handler . url _params . server _type ,
'sgid' : connection _details [ 'server_group' ] ,
'sid' : connection _details [ 'server' ] ,
'title' : connection _details [ 'title' ] ,
} ;
self . set _editor _title ( _ . unescape ( self . handler . url _params . title ) ) ;
self . handler . setTitle ( _ . unescape ( self . handler . url _params . title ) ) ;
let success _msg = connection _details [ 'server_name' ] + '/' + connection _details [ 'database_name' ] + '- Database connected' ;
alertify . success ( success _msg ) ;
if ( ref ) {
let connection _data = {
'server_group' : self . handler . url _params . sgid ,
'server' : connection _details [ 'server' ] ,
'database' : connection _details [ 'database' ] ,
'user' : connection _details [ 'user' ] ,
'title' : connection _details [ 'title' ] ,
'role' : connection _details [ 'role' ] ,
'is_allow_new_connection' : true ,
'database_name' : connection _details [ 'database_name' ] ,
'server_name' : connection _details [ 'server_name' ] ,
'is_selected' : true ,
} ;
delete connection _data . password ;
if ( add _new _connection ) {
self . connection _list . unshift ( connection _data ) ;
}
self . render _connection ( self . connection _list ) ;
loadingDiv . addClass ( 'd-none' ) ;
alertify . newConnectionDialog ( ) . destroy ( ) ;
alertify . connectServer ( ) . destroy ( ) ;
} else {
loadingDiv . addClass ( 'd-none' ) ;
alertify . connectServer ( ) . destroy ( ) ;
}
}
return true ;
} )
. fail ( function ( xhr ) {
if ( xhr . status == 428 ) {
var connection _info = connection _details ;
if ( ref ) {
connection _info = { } ;
}
alertify . connectServer ( 'Connect to server' , xhr . responseJSON . result , connection _details [ 'server' ] , false , connection _info ) ;
} else {
alertify . error ( xhr . responseJSON [ 'errormsg' ] ) ;
2020-10-21 06:44:59 -05:00
}
} ) ;
2020-10-01 02:59:00 -05:00
} ,
2017-08-21 09:27:29 -05:00
} ) ;
2017-05-27 13:51:02 -05:00
2020-09-28 04:56:45 -05:00
2017-08-21 09:27:29 -05:00
/ * D e f i n i n g c o n t r o l l e r c l a s s f o r d a t a g r i d , w h i c h a c t u a l l y
* perform the operations like executing the sql query , poll the result ,
* render the data in the grid , Save / Refresh the data etc ...
* /
2018-01-12 01:29:51 -06:00
var SqlEditorController = function ( ) {
2017-08-21 09:27:29 -05:00
this . initialize . apply ( this , arguments ) ;
} ;
2020-08-28 03:23:08 -05:00
/ * T h i s f u n c t i o n i s u s e d t o c h e c k w h e t h e r u s e r h a v e c l o s e d
* the main window when query tool is opened on new tab
* /
var is _main _window _alive = function ( ) {
if ( ( pgWindow . default && pgWindow . default . closed ) ||
pgWindow . default . pgAdmin && pgWindow . default . pgAdmin . Browser
&& pgWindow . default . pgAdmin . Browser . preference _version ( ) <= 0 ) {
alertify . alert ( )
. setting ( {
'title' : gettext ( 'Connection lost' ) ,
'label' : gettext ( 'Close' ) ,
'message' : gettext ( 'The pgAdmin browser window has been closed and the connection to the server is lost. Please close this window and open a new pgAdmin session.' ) ,
'onok' : function ( ) {
//Close the window after connection is lost
window . close ( ) ;
} ,
} ) . show ( ) ;
}
} ;
2017-08-21 09:27:29 -05:00
_ . extend (
SqlEditorController . prototype ,
2018-02-01 07:29:18 -06:00
Backbone . Events ,
{
2018-01-12 01:29:51 -06:00
initialize : function ( container ) {
2018-02-01 07:29:18 -06:00
var self = this ;
2017-08-21 09:27:29 -05:00
this . container = container ;
2018-02-01 07:29:18 -06:00
this . state = { } ;
2019-05-28 00:29:51 -05:00
this . csrf _token = pgAdmin . csrf _token ;
2020-08-28 03:23:08 -05:00
//call to check whether user have closed the parent window and trying to refresh, if yes return error.
is _main _window _alive ( ) ;
2018-04-10 05:09:59 -05:00
// Disable animation first
modifyAnimation . modifyAlertifyAnimation ( ) ;
2018-02-01 07:29:18 -06:00
if ( ! alertify . dlgGetServerPass ) {
alertify . dialog ( 'dlgGetServerPass' , function factory ( ) {
return {
main : function (
title , message
) {
this . set ( 'title' , title ) ;
this . setting ( 'message' , message ) ;
} ,
setup : function ( ) {
return {
buttons : [
{
text : gettext ( 'OK' ) ,
key : 13 ,
className : 'btn btn-primary' ,
} ,
{
text : gettext ( 'Cancel' ) ,
2018-04-24 08:27:31 -05:00
key : 27 ,
2018-02-01 07:29:18 -06:00
className : 'btn btn-danger' ,
} ,
] ,
focus : {
element : '#password' ,
select : true ,
} ,
options : {
modal : 0 ,
resizable : false ,
maximizable : false ,
pinnable : false ,
} ,
} ;
} ,
build : function ( ) { } ,
settings : {
message : null ,
} ,
prepare : function ( ) {
this . setContent ( this . setting ( 'message' ) ) ;
} ,
callback : function ( closeEvent ) {
if ( closeEvent . button . text == gettext ( 'OK' ) ) {
var passdata = $ ( this . elements . content ) . find ( '#frmPassword' ) . serialize ( ) ;
self . init _connection ( false , passdata ) ;
}
} ,
} ;
} ) ;
}
this . on ( 'pgadmin-datagrid:transaction:created' , function ( trans _obj ) {
self . transId = trans _obj . gridTransId ;
self . warn _before _continue ( ) ;
} ) ;
pgBrowser . Events . on ( 'pgadmin:user:logged-in' , function ( ) {
2018-04-04 05:20:36 -05:00
self . initTransaction ( ) ;
2018-02-01 07:29:18 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2018-04-04 05:20:36 -05:00
saveState : function ( fn , args ) {
2018-02-01 07:29:18 -06:00
if ( fn ) {
this . state = {
'fn' : fn ,
'args' : args ,
} ;
} else {
this . state = { } ;
}
} ,
2018-04-04 05:20:36 -05:00
initTransaction : function ( ) {
2019-08-23 06:14:20 -05:00
var self = this , url _endpoint ;
if ( self . is _query _tool ) {
2018-02-01 07:29:18 -06:00
url _endpoint = 'datagrid.initialize_query_tool' ;
2016-08-29 09:47:01 -05:00
2018-02-01 07:29:18 -06:00
// If database not present then use Maintenance database
// We will handle this at server side
2019-08-23 06:14:20 -05:00
if ( self . url _params . did ) {
2018-02-01 07:29:18 -06:00
url _endpoint = 'datagrid.initialize_query_tool_with_did' ;
}
} else {
url _endpoint = 'datagrid.initialize_datagrid' ;
}
2019-08-23 06:14:20 -05:00
var baseUrl = url _for ( url _endpoint , {
... self . url _params ,
'trans_id' : self . transId ,
} ) ;
2018-02-01 07:29:18 -06:00
2019-08-23 06:14:20 -05:00
$ . ajax ( {
url : baseUrl ,
type : 'POST' ,
data : self . is _query _tool ? null : JSON . stringify ( self . url _params . sql _filter ) ,
contentType : 'application/json' ,
} ) . done ( ( res ) => {
pgBrowser . Events . trigger (
'pgadmin:query_tool:connected:' + self . transId , res . data
) ;
} ) . fail ( ( xhr , status , error ) => {
2020-06-03 00:56:26 -05:00
if ( xhr . status === 410 ) {
//checking for Query tool in new window.
2020-11-04 06:15:28 -06:00
var open _new _tab = self . browser _preferences . new _browser _tab _open ;
if ( open _new _tab && open _new _tab . includes ( 'qt' ) ) {
2020-06-03 00:56:26 -05:00
pgBrowser . report _error ( gettext ( 'Error fetching rows - %s.' , xhr . statusText ) , xhr . responseJSON . errormsg , undefined , window . close ) ;
} else {
pgBrowser . report _error ( gettext ( 'Error fetching rows - %s.' , xhr . statusText ) , xhr . responseJSON . errormsg , undefined , self . close . bind ( self ) ) ;
}
} else {
pgBrowser . Events . trigger (
'pgadmin:query_tool:connected_fail:' + self . transId , xhr , error
) ;
}
2019-08-23 06:14:20 -05:00
} ) ;
2018-02-01 07:29:18 -06:00
} ,
handle _connection _lost : function ( create _transaction , xhr ) {
2018-03-21 03:38:18 -05:00
/ * I f r e s p o n s e J S O N i s u n d e f i n e d t h e n i t c o u l d b e o b j e c t o f
* axios ( Promise HTTP ) response , so we should check accordingly .
* /
if ( xhr . responseJSON !== undefined &&
xhr . responseJSON . data && ! xhr . responseJSON . data . conn _id ) {
// if conn_id is null then this is maintenance db.
// so attempt connection connect without prompt.
this . init _connection ( create _transaction ) ;
} else if ( xhr . data !== undefined &&
xhr . data . data && ! xhr . data . data . conn _id ) {
2018-02-01 07:29:18 -06:00
// if conn_id is null then this is maintenance db.
// so attempt connection connect without prompt.
2018-03-21 03:38:18 -05:00
this . init _connection ( create _transaction ) ;
2018-02-01 07:29:18 -06:00
} else {
2018-03-21 03:38:18 -05:00
this . warn _before _continue ( ) ;
2018-02-01 07:29:18 -06:00
}
} ,
2019-05-28 01:30:18 -05:00
handle _cryptkey _missing : function ( ) {
pgBrowser . set _master _password ( '' , ( ) => {
this . warn _before _continue ( ) ;
} ) ;
} ,
2018-02-01 07:29:18 -06:00
warn _before _continue : function ( ) {
var self = this ;
alertify . confirm (
gettext ( 'Connection Warning' ) ,
'<p style="float:left">' +
2019-12-17 01:52:36 -06:00
'<span class="fa fa-exclamation-triangle warn-icon" aria-hidden="true" role="img">' +
2018-02-01 07:29:18 -06:00
'</span>' +
'</p>' +
'<p style="display: inline-block;">' +
'<span class="warn-header">' +
gettext ( 'The application has lost the database connection:' ) +
'</span>' +
'<br>' +
'<span class="warn-body">' +
gettext ( '⁃ If the connection was idle it may have been forcibly disconnected.' ) +
'<br>' +
gettext ( '⁃ The application server or database server may have been restarted.' ) +
'<br>' +
gettext ( '⁃ The user session may have timed out.' ) +
'</span>' +
'<br>' +
'<span class="warn-footer">' +
gettext ( 'Do you want to continue and establish a new session?' ) +
'</span>' +
'</p>' ,
function ( ) {
if ( 'fn' in self . state ) {
var fn = self . state [ 'fn' ] ,
args = self . state [ 'args' ] ;
2018-04-04 05:20:36 -05:00
self . saveState ( ) ;
2018-02-01 07:29:18 -06:00
if ( args . indexOf ( 'connect' ) == - 1 ) {
args . push ( 'connect' ) ;
}
2020-04-15 06:16:03 -05:00
if ( fn in self ) {
self [ fn ] . apply ( self , args ) ;
} else {
console . warn ( 'The callback is not valid for this context' ) ;
}
2018-02-01 07:29:18 -06:00
}
} , function ( ) {
2018-04-04 05:20:36 -05:00
self . saveState ( ) ;
2018-02-01 07:29:18 -06:00
} )
. set ( {
labels : {
ok : gettext ( 'Continue' ) ,
cancel : gettext ( 'Cancel' ) ,
} ,
} ) ;
} ,
init _connection : function ( create _transaction , passdata ) {
var self = this ;
$ . post ( url _for ( 'NODE-server.connect_id' , {
'gid' : this . url _params . sgid ,
'sid' : this . url _params . sid ,
} ) , passdata )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
if ( res . success == 1 ) {
alertify . success ( res . info ) ;
if ( create _transaction ) {
self . initTransaction ( ) ;
} else if ( 'fn' in self . state ) {
var fn = self . state [ 'fn' ] ,
args = self . state [ 'args' ] ;
self . saveState ( ) ;
self [ fn ] . apply ( self , args ) ;
}
2018-02-01 07:29:18 -06:00
}
2019-03-14 10:11:16 -05:00
} )
. fail ( function ( xhr ) {
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , xhr , null , [ ] , false
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . dlgGetServerPass (
gettext ( 'Connect to Server' ) , msg
) ;
2019-03-14 10:11:16 -05:00
} ) ;
2018-02-01 07:29:18 -06:00
} ,
2017-08-21 09:27:29 -05:00
/ * T h i s f u n c t i o n i s u s e d t o c r e a t e i n s t a n c e o f S Q L E d i t o r V i e w ,
2019-10-10 01:35:28 -05:00
* call the render method of the grid view to render the slickgrid
2017-08-21 09:27:29 -05:00
* header and loading icon and start execution of the sql query .
* /
2020-09-28 04:56:45 -05:00
start : function ( transId , url _params , layout , macros ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2017-05-12 10:42:06 -05:00
2019-08-23 06:14:20 -05:00
self . is _query _tool = url _params . is _query _tool === 'true' ? true : false ;
2017-08-21 09:27:29 -05:00
self . rows _affected = 0 ;
self . marked _line _no = 0 ;
self . has _more _rows = false ;
self . fetching _rows = false ;
self . close _on _save = false ;
2019-07-17 05:45:20 -05:00
self . close _on _idle _transaction = false ;
self . last _transaction _status = - 1 ;
2019-08-23 06:14:20 -05:00
self . server _type = url _params . server _type ;
2018-02-01 07:29:18 -06:00
self . url _params = url _params ;
2019-03-29 09:31:33 -05:00
self . is _transaction _buttons _disabled = true ;
2020-12-14 00:28:53 -06:00
self . is _save _results _to _file _disabled = true ;
2017-08-21 09:27:29 -05:00
// We do not allow to call the start multiple times.
if ( self . gridView )
return ;
self . gridView = new SQLEditorView ( {
el : self . container ,
2018-01-12 01:29:51 -06:00
handler : self ,
2019-03-26 10:08:45 -05:00
layout : layout ,
2017-08-21 09:27:29 -05:00
} ) ;
2018-02-01 07:29:18 -06:00
self . transId = self . gridView . transId = transId ;
2020-09-28 04:56:45 -05:00
self . macros = self . gridView . macros = macros ;
2017-05-27 13:51:02 -05:00
2017-08-21 09:27:29 -05:00
self . gridView . current _file = undefined ;
2017-05-27 13:51:02 -05:00
2017-08-21 09:27:29 -05:00
// Render the header
self . gridView . render ( ) ;
2016-08-29 09:47:01 -05:00
2019-08-23 06:14:20 -05:00
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
2020-03-24 00:44:05 -05:00
self . gridView . set _editor _title ( '(' + gettext ( 'Obtaining connection...' ) + ` ${ _ . unescape ( url _params . title ) } ` ) ;
2019-08-23 06:14:20 -05:00
let afterConn = function ( ) {
let enableBtns = [ ] ;
if ( self . is _query _tool ) {
enableBtns = [ '#btn-flash' , '#btn-explain' , '#btn-explain-analyze' ] ;
} else {
enableBtns = [ '#btn-flash' ] ;
}
enableBtns . forEach ( ( selector ) => {
$ ( selector ) . prop ( 'disabled' , false ) ;
} ) ;
$ ( '#btn-conn-status i' ) . removeClass ( 'obtaining-conn' ) ;
2020-10-20 05:11:54 -05:00
var tree _data = pgWindow . default . pgAdmin . Browser . treeMenu . translateTreeNodeIdFromACITree ( pgWindow . default . pgAdmin . Browser . treeMenu . selected ( ) ) ;
var server _data = pgWindow . default . pgAdmin . Browser . treeMenu . findNode ( tree _data . slice ( 0 , 2 ) ) ;
var database _data = pgWindow . default . pgAdmin . Browser . treeMenu . findNode ( tree _data . slice ( 0 , 4 ) ) ;
2019-08-23 06:14:20 -05:00
self . gridView . set _editor _title ( _ . unescape ( url _params . title ) ) ;
2020-10-01 02:59:00 -05:00
let connection _data = {
'server_group' : self . gridView . handler . url _params . sgid ,
'server' : self . gridView . handler . url _params . sid ,
'database' : self . gridView . handler . url _params . did ,
2020-10-21 06:44:59 -05:00
'user' : server _data . data . user . name ,
2020-10-01 02:59:00 -05:00
'role' : null ,
'title' : _ . unescape ( url _params . title ) ,
'is_allow_new_connection' : false ,
2020-10-20 05:11:54 -05:00
'database_name' : _ . unescape ( database _data . data . label ) ,
'server_name' : _ . unescape ( server _data . data . label ) ,
'is_selected' : true ,
2020-10-01 02:59:00 -05:00
} ;
2020-10-28 02:02:22 -05:00
delete connection _data . password ;
2020-10-01 02:59:00 -05:00
self . gridView . connection _list . unshift ( connection _data ) ;
self . gridView . render _connection ( self . gridView . connection _list ) ;
2019-08-23 06:14:20 -05:00
} ;
pgBrowser . Events . on ( 'pgadmin:query_tool:connected:' + transId , afterConn ) ;
pgBrowser . Events . on ( 'pgadmin:query_tool:connected_fail:' + transId , afterConn ) ;
pgBrowser . Events . on ( 'pgadmin:query_tool:connected:' + transId , ( res _data ) => {
self . gridView . set _server _version ( res _data . serverVersion ) ;
} ) ;
pgBrowser . Events . on ( 'pgadmin:query_tool:connected_fail:' + transId , ( xhr , error ) => {
alertify . pgRespErrorNotify ( xhr , error ) ;
} ) ;
self . initTransaction ( ) ;
2019-06-10 05:10:49 -05:00
/ * w c D o c k e r f o c u s e s o n w i n d o w a l w a y s , a n d a l l o u r s h o r t c u t s a r e
* bind to editor - panel . So when we use wcDocker focus , editor - panel
* loses focus and events don ' t work .
* /
$ ( window ) . on ( 'keydown' , ( e ) => {
2019-11-08 06:56:46 -06:00
if ( ( $ ( '.sql-editor' ) . find ( e . target ) . length !== 0 || e . target == $ ( 'body.wcDesktop' ) [ 0 ] ) && self . gridView . keyAction ) {
2019-06-10 05:10:49 -05:00
self . gridView . keyAction ( e ) ;
}
} ) ;
2020-04-07 03:24:16 -05:00
self . init _events ( ) ;
2018-02-01 07:29:18 -06:00
if ( self . is _query _tool ) {
// Fetch the SQL for Scripts (eg: CREATE/UPDATE/DELETE/SELECT)
// Call AJAX only if script type url is present
2019-08-23 06:14:20 -05:00
if ( url _params . query _url ) {
2018-02-01 07:29:18 -06:00
$ . ajax ( {
2019-08-23 06:14:20 -05:00
url : url _params . query _url ,
2018-02-01 07:29:18 -06:00
type : 'GET' ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
self . gridView . query _tool _obj . refresh ( ) ;
2020-06-18 00:44:56 -05:00
if ( res ) {
2019-03-14 10:11:16 -05:00
self . gridView . query _tool _obj . setValue ( res ) ;
}
} )
. fail ( function ( jqx ) {
let msg = '' ;
msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , jqx , null , [ ] , false
) ;
2020-06-03 00:56:26 -05:00
if ( msg ) {
2020-11-04 06:15:28 -06:00
var open _new _tab = self . browser _preferences . new _browser _tab _open ;
if ( open _new _tab && open _new _tab . includes ( 'qt' ) ) {
2020-06-03 00:56:26 -05:00
pgBrowser . report _error ( gettext ( 'Error fetching SQL for script - %s.' , jqx . statusText ) , jqx . responseJSON . errormsg , undefined , window . close ) ;
} else {
pgBrowser . report _error ( gettext ( 'Error fetching SQL for script - %s.' , jqx . statusText ) , jqx . responseJSON . errormsg , undefined , self . close . bind ( self ) ) ;
}
}
2019-03-14 10:11:16 -05:00
} ) ;
2021-01-16 05:36:50 -06:00
} else if ( url _params . sql _id ) {
let sqlValue = localStorage . getItem ( url _params . sql _id ) ;
localStorage . removeItem ( url _params . sql _id ) ;
if ( sqlValue ) {
self . gridView . query _tool _obj . setValue ( sqlValue ) ;
}
2018-02-01 07:29:18 -06:00
}
}
else {
2018-03-02 07:46:06 -06:00
// Disable codemirror by setting readOnly option to true, background to dark, and cursor, hidden.
self . gridView . query _tool _obj . setOption ( 'readOnly' , true ) ;
2018-02-01 07:29:18 -06:00
var cm = self . gridView . query _tool _obj . getWrapperElement ( ) ;
if ( cm ) {
2018-09-04 05:24:51 -05:00
cm . className += ' bg-gray-lighter opacity-5 hide-cursor-workaround' ;
2018-02-01 07:29:18 -06:00
}
self . disable _tool _buttons ( true ) ;
2019-08-23 06:14:20 -05:00
pgBrowser . Events . on ( 'pgadmin:query_tool:connected:' + transId , ( ) => {
2019-08-23 10:15:43 -05:00
self . check _data _changes _to _execute _query ( ) ;
2019-08-23 06:14:20 -05:00
} ) ;
2018-02-01 07:29:18 -06:00
}
} ,
2020-01-10 04:09:32 -06:00
set _value _to _editor : function ( query ) {
2021-01-16 05:36:50 -06:00
if ( this . gridView && this . gridView . query _tool _obj && ! _ . isUndefined ( query ) && query != '' ) {
2020-01-10 04:09:32 -06:00
this . gridView . query _tool _obj . setValue ( query ) ;
}
} ,
2018-02-01 07:29:18 -06:00
init _events : function ( ) {
var self = this ;
2017-08-21 09:27:29 -05:00
// 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 ) ;
2016-08-29 09:47:01 -05:00
2017-08-21 09:27:29 -05:00
// 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 . bind ( self ) ) ;
}
2017-06-27 08:03:04 -05:00
2017-08-21 09:27:29 -05:00
// Listen on events come from SQLEditorView for the button clicked.
self . on ( 'pgadmin-sqleditor:button:load_file' , self . _load _file , self ) ;
2019-07-17 05:45:20 -05:00
self . on ( 'pgadmin-sqleditor:button:save_file' , self . _save _file , self ) ;
2017-08-21 09:27:29 -05:00
self . on ( 'pgadmin-sqleditor:button:deleterow' , self . _delete , self ) ;
self . on ( 'pgadmin-sqleditor:button:show_filter' , self . _show _filter , self ) ;
2020-10-01 02:59:00 -05:00
self . on ( 'pgadmin-sqleditor:button:show_new_connection' , self . _show _new _connection , self ) ;
2017-08-21 09:27:29 -05:00
self . on ( 'pgadmin-sqleditor:button:include_filter' , self . _include _filter , self ) ;
self . on ( 'pgadmin-sqleditor:button:exclude_filter' , self . _exclude _filter , self ) ;
self . on ( 'pgadmin-sqleditor:button:remove_filter' , self . _remove _filter , self ) ;
self . on ( 'pgadmin-sqleditor:button:copy_row' , self . _copy _row , self ) ;
2019-09-27 01:44:39 -05:00
self . on ( 'pgadmin-sqleditor:button:copy_row_with_header' , self . _copy _row _with _header , self ) ;
2017-08-21 09:27:29 -05:00
self . on ( 'pgadmin-sqleditor:button:paste_row' , self . _paste _row , self ) ;
self . on ( 'pgadmin-sqleditor:button:limit' , self . _set _limit , self ) ;
self . on ( 'pgadmin-sqleditor:button:cancel-query' , self . _cancel _query , self ) ;
self . on ( 'pgadmin-sqleditor:button:auto_rollback' , self . _auto _rollback , self ) ;
self . on ( 'pgadmin-sqleditor:button:auto_commit' , self . _auto _commit , self ) ;
self . on ( 'pgadmin-sqleditor:button:explain-verbose' , self . _explain _verbose , self ) ;
self . on ( 'pgadmin-sqleditor:button:explain-costs' , self . _explain _costs , self ) ;
self . on ( 'pgadmin-sqleditor:button:explain-buffers' , self . _explain _buffers , self ) ;
self . on ( 'pgadmin-sqleditor:button:explain-timing' , self . _explain _timing , self ) ;
2019-07-03 07:57:56 -05:00
self . on ( 'pgadmin-sqleditor:button:explain-summary' , self . _explain _summary , self ) ;
self . on ( 'pgadmin-sqleditor:button:explain-settings' , self . _explain _settings , self ) ;
2020-08-28 03:23:08 -05:00
self . on ( 'pgadmin-sqleditor:button:show_query_tool' , self . _show _query _tool , self ) ;
2017-08-21 09:27:29 -05:00
// Indentation related
self . on ( 'pgadmin-sqleditor:indent_selected_code' , self . _indent _selected _code , self ) ;
self . on ( 'pgadmin-sqleditor:unindent_selected_code' , self . _unindent _selected _code , self ) ;
2020-08-20 02:35:00 -05:00
// Format
self . on ( 'pgadmin-sqleditor:format_sql' , self . _format _sql , self ) ;
2020-09-28 04:56:45 -05:00
self . on ( 'pgadmin-sqleditor:button:manage_macros' , self . _manage _macros , self ) ;
self . on ( 'pgadmin-sqleditor:button:execute_macro' , self . _execute _macro , self ) ;
2020-04-16 04:55:39 -05:00
window . parent . $ ( window . parent . document ) . on ( 'pgadmin-sqleditor:rows-copied' , self . _copied _in _other _session ) ;
2017-06-27 08:03:04 -05:00
} ,
2019-08-23 10:15:43 -05:00
// Checks if there is any dirty data in the grid before executing a query
2020-09-28 04:56:45 -05:00
check _data _changes _to _execute _query : function ( explain _prefix = null , shouldReconnect = false , macroId = undefined ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2017-06-27 08:03:04 -05:00
2017-08-21 09:27:29 -05:00
// Check if the data grid has any changes before running query
if ( _ . has ( self , 'data_store' ) &&
2018-01-12 01:29:51 -06:00
( _ . size ( self . data _store . added ) ||
_ . size ( self . data _store . updated ) ||
_ . size ( self . data _store . deleted ) )
2017-08-21 09:27:29 -05:00
) {
2018-01-12 01:29:51 -06:00
alertify . confirm ( gettext ( 'Unsaved changes' ) ,
gettext ( 'The data has been modified, but not saved. Are you sure you wish to discard the changes?' ) ,
function ( ) {
2019-08-23 10:15:43 -05:00
// The user does not want to save, just continue
2020-09-28 04:56:45 -05:00
if ( macroId !== undefined ) {
self . _execute _macro _query ( explain _prefix , shouldReconnect , macroId ) ;
}
else if ( self . is _query _tool ) {
2019-08-23 10:15:43 -05:00
self . _execute _sql _query ( explain _prefix , shouldReconnect ) ;
}
else {
self . _execute _view _data _query ( ) ;
}
2017-08-21 09:27:29 -05:00
} ,
2018-01-12 01:29:51 -06:00
function ( ) {
2017-08-21 09:27:29 -05:00
// Stop, User wants to save
return true ;
}
2018-01-12 01:29:51 -06:00
) . set ( 'labels' , {
2018-01-25 06:27:13 -06:00
ok : gettext ( 'Yes' ) ,
cancel : gettext ( 'No' ) ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-06-27 08:03:04 -05:00
} else {
2020-09-28 04:56:45 -05:00
if ( macroId !== undefined ) {
self . _execute _macro _query ( explain _prefix , shouldReconnect , macroId ) ;
}
else if ( self . is _query _tool ) {
2019-08-23 10:15:43 -05:00
self . _execute _sql _query ( explain _prefix , shouldReconnect ) ;
}
else {
self . _execute _view _data _query ( ) ;
}
2017-06-27 08:03:04 -05:00
}
2017-08-21 09:27:29 -05:00
} ,
2017-06-27 08:03:04 -05:00
2019-08-23 10:15:43 -05:00
// Makes the ajax call to execute the sql query in View Data mode
_execute _view _data _query : function ( ) {
2018-02-01 07:29:18 -06:00
var self = this ,
url = url _for ( 'sqleditor.view_data_start' , {
'trans_id' : self . transId ,
} ) ;
2017-08-21 09:27:29 -05:00
self . query _start _time = new Date ( ) ;
self . rows _affected = 0 ;
self . _init _polling _flags ( ) ;
2019-08-02 04:39:19 -05:00
self . has _more _rows = false ;
self . fetching _rows = false ;
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2019-01-03 09:24:47 -06:00
gettext ( 'Running query...' )
2017-08-21 09:27:29 -05:00
) ;
2018-01-12 01:29:51 -06:00
$ ( '#btn-flash' ) . prop ( 'disabled' , true ) ;
2020-12-14 00:28:53 -06:00
self . enable _disable _download _btn ( true ) ;
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:message' ,
2019-01-03 09:24:47 -06:00
gettext ( 'Waiting for the query to complete...' )
2017-08-21 09:27:29 -05:00
) ;
2018-02-01 07:29:18 -06:00
if ( arguments . length > 0 &&
arguments [ arguments . length - 1 ] == 'connect' ) {
url += '?connect=1' ;
}
2017-08-21 09:27:29 -05:00
$ . ajax ( {
2018-02-01 07:29:18 -06:00
url : url ,
2017-08-21 09:27:29 -05:00
method : 'GET' ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
if ( res . data . status ) {
self . can _edit = res . data . can _edit ;
self . can _filter = res . data . can _filter ;
self . info _notifier _timeout = res . data . info _notifier _timeout ;
2017-08-21 09:27:29 -05:00
2019-03-14 10:11:16 -05:00
// Set the sql query to the SQL panel
self . gridView . query _tool _obj . setValue ( res . data . sql ) ;
self . query = res . data . sql ;
2017-08-21 09:27:29 -05:00
2019-03-14 10:11:16 -05:00
/ * I f f i l t e r i s a p p l i e d t h e n r e m o v e c l a s s ' b t n - s e c o n d a r y '
2019-01-02 03:35:15 -06:00
* and add 'btn-primary' to change the colour of the button .
2018-07-09 07:54:00 -05:00
* /
2019-03-14 10:11:16 -05:00
if ( self . can _filter && res . data . filter _applied ) {
$ ( '#btn-filter' ) . removeClass ( 'btn-secondary' ) ;
$ ( '#btn-filter-dropdown' ) . removeClass ( 'btn-secondary' ) ;
$ ( '#btn-filter' ) . addClass ( 'btn-primary' ) ;
$ ( '#btn-filter-dropdown' ) . addClass ( 'btn-primary' ) ;
} else {
$ ( '#btn-filter' ) . removeClass ( 'btn-primary' ) ;
$ ( '#btn-filter-dropdown' ) . removeClass ( 'btn-primary' ) ;
$ ( '#btn-filter' ) . addClass ( 'btn-secondary' ) ;
$ ( '#btn-filter-dropdown' ) . addClass ( 'btn-secondary' ) ;
}
2019-07-17 05:45:20 -05:00
2019-03-14 10:11:16 -05:00
$ ( '#btn-copy-row' ) . prop ( 'disabled' , true ) ;
$ ( '#btn-paste-row' ) . prop ( 'disabled' , true ) ;
2018-07-09 07:54:00 -05:00
2019-03-14 10:11:16 -05:00
// Set the combo box value
$ ( '.limit' ) . val ( res . data . limit ) ;
2018-07-09 07:54:00 -05:00
2019-03-14 10:11:16 -05:00
// If status is True then poll the result.
self . _poll ( ) ;
} else {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
self . update _msg _history ( false , res . data . result ) ;
}
} )
. fail ( function ( e ) {
2017-08-21 09:27:29 -05:00
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
2019-03-14 10:11:16 -05:00
let msg = httpErrorHandler . handleQueryToolAjaxError (
2019-08-23 10:15:43 -05:00
pgAdmin , self , e , '_execute_view_data_query' , [ ] , true
2019-03-14 10:11:16 -05:00
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
self . update _msg _history ( false , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-06-27 08:03:04 -05:00
} ,
2020-09-28 04:56:45 -05:00
// Executes sql query for macroin the editor in Query Tool mode
_execute _macro _query : function ( explain _prefix , shouldReconnect , macroId ) {
var self = this ;
self . has _more _rows = false ;
self . fetching _rows = false ;
$ . ajax ( {
url : url _for ( 'sqleditor.get_macro' , { 'macro_id' : macroId , 'trans_id' : self . transId } ) ,
method : 'GET' ,
contentType : 'application/json' ,
dataType : 'json' ,
} )
. done ( function ( res ) {
if ( res ) {
// Replace the place holder
2020-10-15 05:29:53 -05:00
const regex = /\$SELECTION\$/gi ;
let query = res . sql . replace ( regex , self . gridView . query _tool _obj . getSelection ( ) ) ;
2020-09-28 04:56:45 -05:00
const executeQuery = new ExecuteQuery . ExecuteQuery ( self , pgAdmin . Browser . UserManagement ) ;
executeQuery . poll = pgBrowser . override _activity _event _decorator ( executeQuery . poll ) . bind ( executeQuery ) ;
executeQuery . execute ( query , explain _prefix , shouldReconnect ) ;
} else {
// Let it be for now
}
} )
. fail ( function ( ) {
/* failure should not be ignored */
} ) ;
} ,
2019-08-23 10:15:43 -05:00
// Executes sql query in the editor in Query Tool mode
_execute _sql _query : function ( explain _prefix , shouldReconnect ) {
var self = this , sql = '' ;
self . has _more _rows = false ;
self . fetching _rows = false ;
if ( ! _ . isUndefined ( self . special _sql ) ) {
sql = self . special _sql ;
} else {
/ * I f c o d e i s s e l e c t e d i n t h e c o d e m i r r o r t h e n e x e c u t e
* the selected part else execute the complete code .
* /
var selected _code = self . gridView . query _tool _obj . getSelection ( ) ;
if ( selected _code . length > 0 )
sql = selected _code ;
else
sql = self . gridView . query _tool _obj . getValue ( ) ;
}
const executeQuery = new ExecuteQuery . ExecuteQuery ( this , pgAdmin . Browser . UserManagement ) ;
2020-01-15 06:37:46 -06:00
executeQuery . poll = pgBrowser . override _activity _event _decorator ( executeQuery . poll ) . bind ( executeQuery ) ;
2019-08-23 10:15:43 -05:00
executeQuery . execute ( sql , explain _prefix , shouldReconnect ) ;
} ,
2017-08-21 09:27:29 -05:00
// This is a wrapper to call_render function
// We need this because we have separated columns route & result route
// We need to combine both result here in wrapper before rendering grid
2018-04-03 08:11:11 -05:00
call _render _after _poll : function ( queryResult ) {
callRenderAfterPoll . callRenderAfterPoll ( this , alertify , queryResult ) ;
2016-08-29 09:47:01 -05:00
} ,
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
/ * T h i s f u n c t i o n m a k e s t h e a j a x c a l l t o p o l l t h e r e s u l t ,
* if status is Busy then recursively call the poll function
* till the status is 'Success' or 'NotConnected' . If status is
* 'Success' then call the render method to render the data .
2016-04-14 09:04:03 -05:00
* /
2018-01-12 01:29:51 -06:00
_poll : function ( ) {
2018-02-09 05:54:42 -06:00
const executeQuery = new ExecuteQuery . ExecuteQuery ( this , pgAdmin . Browser . UserManagement ) ;
executeQuery . delayedPoll ( this ) ;
2016-06-02 02:45:24 -05:00
} ,
2019-10-10 01:35:28 -05:00
/ * T h i s f u n c t i o n i s u s e d t o c r e a t e t h e s l i c k g r i d c o l u m n s
* and render the data in the slickgrid .
2017-08-21 09:27:29 -05:00
* /
2018-01-12 01:29:51 -06:00
_render : function ( data ) {
2016-04-14 09:04:03 -05:00
var self = this ;
2019-07-22 08:12:48 -05:00
self . colinfo = data . colinfo ;
2018-01-12 01:29:51 -06:00
self . primary _keys = ( _ . isEmpty ( data . primary _keys ) && data . has _oids ) ? data . oids : data . primary _keys ;
2017-08-21 09:27:29 -05:00
self . client _primary _key = data . client _primary _key ;
self . cell _selected = false ;
self . selected _model = null ;
self . changedModels = [ ] ;
2017-12-13 04:28:31 -06:00
self . has _oids = data . has _oids ;
self . oids = data . oids ;
2020-09-28 07:21:59 -05:00
$ ( '.sql-editor-explain' ) . html ( EMPTY _EXPLAIN _CONTENT ) ;
2019-07-22 08:12:48 -05:00
self . explain _plan = false ;
2017-08-21 09:27:29 -05:00
/ * I f o b j e c t d o n ' t h a v e p r i m a r y k e y s t h e n s e t t h e
* can _edit flag to false .
* /
2018-01-12 01:29:51 -06:00
if ( ( self . primary _keys === null || self . primary _keys === undefined ||
_ . size ( self . primary _keys ) === 0 ) && self . has _oids == false )
2017-08-21 09:27:29 -05:00
self . can _edit = false ;
else
self . can _edit = true ;
/ * I f u s e r c a n f i l t e r t h e d a t a t h e n w e s h o u l d e n a b l e d
* Filter and Limit buttons .
* /
if ( self . can _filter ) {
2018-01-12 01:29:51 -06:00
$ ( '.limit' ) . prop ( 'disabled' , false ) ;
$ ( '.limit' ) . addClass ( 'limit-enabled' ) ;
$ ( '#btn-filter' ) . prop ( 'disabled' , false ) ;
$ ( '#btn-filter-dropdown' ) . prop ( 'disabled' , false ) ;
2017-08-21 09:27:29 -05:00
}
2016-04-14 09:04:03 -05:00
2019-07-17 05:45:20 -05:00
// No data to save initially
$ ( '#btn-save-data' ) . prop ( 'disabled' , true ) ;
2017-08-21 09:27:29 -05:00
// Initial settings for delete row, copy row and paste row buttons.
2018-01-12 01:29:51 -06:00
$ ( '#btn-delete-row' ) . prop ( 'disabled' , true ) ;
2019-07-17 05:45:20 -05:00
2017-08-21 09:27:29 -05:00
if ( ! self . can _edit ) {
2018-01-12 01:29:51 -06:00
$ ( '#btn-delete-row' ) . prop ( 'disabled' , true ) ;
$ ( '#btn-copy-row' ) . prop ( 'disabled' , true ) ;
$ ( '#btn-paste-row' ) . prop ( 'disabled' , true ) ;
2017-08-21 09:27:29 -05:00
}
2016-06-02 02:45:24 -05:00
2017-08-21 09:27:29 -05:00
// Fetch the columns metadata
self . _fetch _column _metadata . call (
2018-01-12 01:29:51 -06:00
self , data ,
function ( ) {
2020-07-09 08:14:58 -05:00
var self _col = this ;
2016-04-14 09:04:03 -05:00
2020-07-09 08:14:58 -05:00
self _col . trigger (
2017-08-21 09:27:29 -05:00
'pgadmin-sqleditor:loading-icon:message' ,
2018-01-12 01:29:51 -06:00
gettext ( 'Loading data from the database server and rendering...' ) ,
2020-07-09 08:14:58 -05:00
self _col
2017-08-21 09:27:29 -05:00
) ;
2016-07-21 07:44:42 -05:00
2017-08-21 09:27:29 -05:00
// Show message in message and history tab in case of query tool
2020-07-09 08:14:58 -05:00
self _col . total _time = calculateQueryRunTime . calculateQueryRunTime (
self _col . query _start _time ,
self _col . query _end _time
2018-04-03 08:11:11 -05:00
) ;
2020-07-09 08:14:58 -05:00
var msg1 = gettext ( 'Successfully run. Total query runtime: %s.' , self _col . total _time ) ;
var msg2 = gettext ( '%s rows affected.' , self _col . rows _affected ) ;
2016-07-21 07:44:42 -05:00
2018-01-12 01:29:51 -06:00
// Display the notifier if the timeout is set to >= 0
2020-07-09 08:14:58 -05:00
if ( self _col . info _notifier _timeout >= 0 ) {
alertify . success ( msg1 + ' ' + msg2 , self _col . info _notifier _timeout ) ;
2018-01-12 01:29:51 -06:00
}
2016-07-21 07:44:42 -05:00
2017-08-21 09:27:29 -05:00
var _msg = msg1 + '\n' + msg2 ;
2016-11-24 09:38:30 -06:00
2018-01-12 01:29:51 -06:00
// If there is additional messages from server then add it to message
if ( ! _ . isNull ( data . additional _messages ) &&
! _ . isUndefined ( data . additional _messages ) ) {
_msg = data . additional _messages + '\n' + _msg ;
}
2016-11-24 09:38:30 -06:00
2020-07-09 08:14:58 -05:00
self _col . update _msg _history ( true , _msg , false ) ;
2016-11-24 09:38:30 -06:00
2017-08-21 09:27:29 -05:00
/ * A d d t h e d a t a t o t h e c o l l e c t i o n a n d r e n d e r t h e g r i d .
* In case of Explain draw the graph on explain panel
* and add json formatted data to collection and render .
* /
2019-03-01 06:38:57 -06:00
var explain _data _array = [ ] ,
explain _data _json = null ;
2020-07-09 08:14:58 -05:00
if ( data . result && ! _ . isEmpty ( self _col . colinfo )
&& self _col . colinfo [ 0 ] . name == 'QUERY PLAN' && ! _ . isEmpty ( data . types )
2019-07-22 08:12:48 -05:00
&& data . types [ 0 ] && data . types [ 0 ] . typname === 'json' ) {
2019-03-01 06:38:57 -06:00
/* json is sent as text, parse it */
2019-05-23 02:53:29 -05:00
explain _data _json = JSON . parse ( data . result [ 0 ] [ 0 ] ) ;
2019-03-28 07:12:09 -05:00
}
2019-03-01 06:38:57 -06:00
2019-03-28 07:12:09 -05:00
if ( explain _data _json && explain _data _json [ 0 ] &&
explain _data _json [ 0 ] . hasOwnProperty ( 'Plan' ) &&
_ . isObject ( explain _data _json [ 0 ] [ 'Plan' ] )
) {
var explain _data = [ JSON . stringify ( explain _data _json , null , 2 ) ] ;
explain _data _array . push ( explain _data ) ;
// Make sure - the 'Data Output' panel is visible, before - we
// start rendering the grid.
2020-07-09 08:14:58 -05:00
self _col . gridView . data _output _panel . focus ( ) ;
2019-03-28 07:12:09 -05:00
setTimeout (
function ( ) {
2020-07-09 08:14:58 -05:00
self _col . gridView . render _grid (
explain _data _array , self _col . columns , self _col . can _edit ,
self _col . client _primary _key , 0
2019-03-28 07:12:09 -05:00
) ;
// Make sure - the 'Explain' panel is visible, before - we
// start rendering the grid.
2020-07-09 08:14:58 -05:00
self _col . gridView . explain _panel . focus ( ) ;
2019-03-28 07:12:09 -05:00
pgExplain . DrawJSONPlan (
$ ( '.sql-editor-explain' ) , explain _data _json
) ;
} , 10
) ;
2017-08-21 09:27:29 -05:00
} else {
// Make sure - the 'Data Output' panel is visible, before - we
// start rendering the grid.
2020-07-09 08:14:58 -05:00
self _col . gridView . data _output _panel . focus ( ) ;
2017-08-21 09:27:29 -05:00
setTimeout (
2018-01-12 01:29:51 -06:00
function ( ) {
2020-07-09 08:14:58 -05:00
self _col . gridView . render _grid ( data . result , self _col . columns ,
self _col . can _edit , self _col . client _primary _key , data . rows _affected ) ;
2017-08-21 09:27:29 -05:00
} , 10
) ;
}
2016-11-24 09:38:30 -06:00
2017-08-21 09:27:29 -05:00
// Hide the loading icon
2020-07-09 08:14:58 -05:00
self _col . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
2018-01-12 01:29:51 -06:00
$ ( '#btn-flash' ) . prop ( 'disabled' , false ) ;
2020-12-14 00:28:53 -06:00
if ( ! _ . isUndefined ( data ) && Array . isArray ( data . result ) && data . result . length > 0 ) {
self . enable _disable _download _btn ( false ) ;
}
else {
self . enable _disable _download _btn ( true ) ;
}
2017-08-21 09:27:29 -05:00
} . bind ( self )
) ;
2016-11-24 09:38:30 -06:00
} ,
2017-08-21 09:27:29 -05:00
// This function creates the columns as required by the backgrid
2018-01-12 01:29:51 -06:00
_fetch _column _metadata : function ( data , cb ) {
2017-08-21 09:27:29 -05:00
var colinfo = data . colinfo ,
primary _keys = data . primary _keys ,
columns = [ ] ,
self = this ;
// Store pg_types in an array
var pg _types = new Array ( ) ;
2018-01-12 01:29:51 -06:00
_ . each ( data . types , function ( r ) {
2017-08-21 09:27:29 -05:00
pg _types [ r . oid ] = [ r . typname ] ;
} ) ;
2016-11-24 09:38:30 -06:00
2017-08-21 09:27:29 -05:00
// Create columns required by slick grid to render
2018-01-12 01:29:51 -06:00
_ . each ( colinfo , function ( c ) {
2019-08-26 03:47:40 -05:00
var is _primary _key = false ,
is _editable = self . can _edit && ( ! self . is _query _tool || c . is _editable ) ;
2016-11-24 09:38:30 -06:00
2019-08-26 03:47:40 -05:00
// Check whether this column is a primary key
if ( is _editable && _ . size ( primary _keys ) > 0 ) {
2018-01-12 01:29:51 -06:00
_ . each ( primary _keys , function ( value , key ) {
2017-08-21 09:27:29 -05:00
if ( key === c . name )
is _primary _key = true ;
} ) ;
}
2016-11-24 09:38:30 -06:00
2017-08-21 09:27:29 -05:00
// To show column label and data type in multiline,
// The elements should be put inside the div.
// Create column label and type.
var col _type = '' ,
column _label = '' ,
col _cell ;
var type = pg _types [ c . type _code ] ?
pg _types [ c . type _code ] [ 0 ] :
// This is the case where user might
// have use casting so we will use type
// returned by cast function
pg _types [ pg _types . length - 1 ] [ 0 ] ?
2019-03-14 10:11:16 -05:00
pg _types [ pg _types . length - 1 ] [ 0 ] : 'unknown' ;
2017-08-21 09:27:29 -05:00
if ( ! is _primary _key )
col _type += type ;
else
col _type += '[PK] ' + type ;
2016-11-24 09:38:30 -06:00
2017-08-21 09:27:29 -05:00
if ( c . precision && c . precision >= 0 && c . precision != 65535 ) {
col _type += ' (' + c . precision ;
col _type += c . scale && c . scale != 65535 ?
',' + c . scale + ')' :
')' ;
}
// Identify cell type of column.
switch ( type ) {
2018-01-12 01:29:51 -06:00
case 'oid' :
col _cell = 'oid' ;
break ;
case 'json' :
case 'json[]' :
case 'jsonb' :
case 'jsonb[]' :
col _cell = 'Json' ;
break ;
case 'smallint' :
case 'smallint[]' :
case 'integer' :
case 'integer[]' :
case 'bigint' :
case 'bigint[]' :
case 'decimal' :
case 'decimal[]' :
case 'numeric' :
case 'numeric[]' :
case 'real' :
case 'real[]' :
case 'double precision' :
case 'double precision[]' :
col _cell = 'number' ;
break ;
case 'boolean' :
col _cell = 'boolean' ;
break ;
case 'character' :
case 'character[]' :
case '"char"' :
case '"char"[]' :
case 'character varying' :
case 'character varying[]' :
if ( c . internal _size && c . internal _size >= 0 && c . internal _size != 65535 ) {
2019-03-14 10:11:16 -05:00
// Update column type to display length on column header
2018-01-12 01:29:51 -06:00
col _type += ' (' + c . internal _size + ')' ;
}
col _cell = 'string' ;
break ;
case 'bytea' :
case 'bytea[]' :
col _cell = 'binary' ;
break ;
2018-08-30 07:59:31 -05:00
case 'geometry' :
// PostGIS geometry type
col _cell = 'geometry' ;
break ;
case 'geography' :
// PostGIS geography type
col _cell = 'geography' ;
break ;
2018-01-12 01:29:51 -06:00
default :
col _cell = 'string' ;
2017-08-21 09:27:29 -05:00
}
2016-11-24 09:38:30 -06:00
2017-08-21 09:27:29 -05:00
column _label = c . display _name + '<br>' + col _type ;
2017-09-18 01:37:15 -05:00
var array _type _bracket _index = type . lastIndexOf ( '[]' ) ,
col = {
'name' : c . name ,
'display_name' : c . display _name ,
'column_type' : col _type ,
'column_type_internal' : type ,
'pos' : c . pos ,
'label' : column _label ,
'cell' : col _cell ,
2019-08-26 03:47:40 -05:00
'can_edit' : ( c . name == 'oid' ) ? false : is _editable ,
2017-09-18 01:37:15 -05:00
'type' : type ,
'not_null' : c . not _null ,
'has_default_val' : c . has _default _val ,
2018-01-12 01:29:51 -06:00
'is_array' : array _type _bracket _index > - 1 && array _type _bracket _index + 2 == type . length ,
2017-09-18 01:37:15 -05:00
} ;
2017-08-21 09:27:29 -05:00
columns . push ( col ) ;
} ) ;
2016-11-24 09:38:30 -06:00
2017-08-21 09:27:29 -05:00
self . columns = columns ;
if ( cb && typeof ( cb ) == 'function' ) {
cb ( ) ;
}
2016-11-24 09:38:30 -06:00
} ,
2018-01-12 01:29:51 -06:00
resetQueryHistoryObject : function ( history ) {
2017-08-21 09:27:29 -05:00
history . total _time = '-' ;
2016-04-14 09:04:03 -05:00
} ,
2019-03-29 09:31:33 -05:00
set _sql _message ( msg , append = false ) {
if ( append ) {
$ ( '.sql-editor-message' ) . append ( msg ) ;
} else {
$ ( '.sql-editor-message' ) . text ( msg ) ;
}
// Scroll automatically when msgs appends to element
setTimeout ( function ( ) {
$ ( '.sql-editor-message' ) . scrollTop ( $ ( '.sql-editor-message' ) [ 0 ] . scrollHeight ) ;
} , 10 ) ;
} ,
2017-08-21 09:27:29 -05:00
// This function is used to raise appropriate message.
2018-01-12 01:29:51 -06:00
update _msg _history : function ( status , msg , clear _grid ) {
2016-04-14 09:04:03 -05:00
var self = this ;
2017-08-21 09:27:29 -05:00
if ( clear _grid === undefined )
clear _grid = true ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
self . gridView . messages _panel . focus ( ) ;
2016-06-02 02:45:24 -05:00
2017-08-21 09:27:29 -05:00
if ( clear _grid ) {
// Delete grid
if ( self . gridView . handler . slickgrid ) {
self . gridView . handler . slickgrid . destroy ( ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
}
// Misc cleaning
self . columns = undefined ;
self . collection = undefined ;
2016-04-14 09:04:03 -05:00
2019-03-29 09:31:33 -05:00
self . set _sql _message ( msg ) ;
2017-08-21 09:27:29 -05:00
} else {
2019-03-29 09:31:33 -05:00
self . set _sql _message ( _ . escape ( msg ) , true ) ;
2017-08-21 09:27:29 -05:00
}
2016-06-02 02:45:24 -05:00
2017-08-21 09:27:29 -05:00
if ( status != 'Busy' ) {
2018-01-12 01:29:51 -06:00
$ ( '#btn-flash' ) . prop ( 'disabled' , false ) ;
2017-08-21 09:27:29 -05:00
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
2019-03-07 04:51:59 -06:00
if ( ! self . total _time ) {
self . total _time = calculateQueryRunTime . calculateQueryRunTime (
self . query _start _time ,
new Date ( ) ) ;
}
2019-03-13 08:37:34 -05:00
2019-08-16 06:47:12 -05:00
if ( _ . isUndefined ( self . history _query _source ) ) {
self . history _query _source = QuerySources . VIEW _DATA ;
}
let history _entry = {
2017-08-21 09:27:29 -05:00
'status' : status ,
'start_time' : self . query _start _time ,
'query' : self . query ,
'row_affected' : self . rows _affected ,
'total_time' : self . total _time ,
'message' : msg ,
2019-08-16 06:47:12 -05:00
'query_source' : self . history _query _source ,
'is_pgadmin_query' : ! self . is _query _tool ,
2019-03-13 08:37:34 -05:00
} ;
2019-08-16 06:47:12 -05:00
if ( ! self . is _query _tool ) {
var info _msg = gettext ( 'This query was generated by pgAdmin as part of a "View/Edit Data" operation' ) ;
history _entry . info = info _msg ;
2019-03-13 08:37:34 -05:00
}
2019-08-16 06:47:12 -05:00
self . add _to _history ( history _entry ) ;
2017-08-21 09:27:29 -05:00
}
2016-04-14 09:04:03 -05:00
} ,
2019-08-16 06:47:12 -05:00
/* Make ajax call to save the history data */
add _to _history : function ( history _entry ) {
var self = this ;
$ . ajax ( {
url : url _for ( 'sqleditor.add_query_history' , {
'trans_id' : self . transId ,
} ) ,
method : 'POST' ,
contentType : 'application/json' ,
data : JSON . stringify ( history _entry ) ,
} )
. done ( function ( ) { } )
. fail ( function ( ) { } ) ;
self . gridView . history _collection . add ( history _entry ) ;
} ,
2017-08-21 09:27:29 -05:00
/ * T h i s f u n c t i o n i s u s e d t o c h e c k w h e t h e r c e l l
* is editable or not depending on primary keys
* and staged _rows flag
* /
2018-01-12 01:29:51 -06:00
is _editable : function ( obj ) {
2016-04-14 09:04:03 -05:00
var self = this ;
2017-08-21 09:27:29 -05:00
if ( obj instanceof Backbone . Collection )
return false ;
return ( self . get ( 'can_edit' ) ) ;
2016-04-14 09:04:03 -05:00
} ,
2020-12-14 00:28:53 -06:00
enable _disable _download _btn : function ( is _save _results _to _file _disabled ) {
var self = this ;
self . is _save _results _to _file _disabled = is _save _results _to _file _disabled ;
$ ( '#btn-save-results-to-file' ) . prop ( 'disabled' , is _save _results _to _file _disabled ) ;
} ,
2018-01-12 01:29:51 -06:00
rows _to _delete : function ( data ) {
2019-08-19 01:42:28 -05:00
let self = this ;
let tmp _keys = self . primary _keys ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// re-calculate rows with no primary keys
self . temp _new _rows = [ ] ;
2018-01-12 01:29:51 -06:00
data . forEach ( function ( d , idx ) {
2019-08-19 01:42:28 -05:00
let p _keys _list = _ . pick ( d , _ . keys ( tmp _keys ) ) ;
let is _primary _key = Object . keys ( p _keys _list ) . length > 0 ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
if ( ! is _primary _key ) {
self . temp _new _rows . push ( idx ) ;
}
} ) ;
self . rows _to _disable = _ . clone ( self . temp _new _rows ) ;
2016-04-14 09:04:03 -05:00
} ,
2017-08-21 09:27:29 -05:00
// This function will delete selected row.
2018-01-12 01:29:51 -06:00
_delete : function ( ) {
var self = this ,
deleted _keys = [ ] ,
2017-08-21 09:27:29 -05:00
is _added = _ . size ( self . data _store . added ) ,
is _updated = _ . size ( self . data _store . updated ) ;
// Remove newly added rows from staged rows as we don't want to send them on server
if ( is _added ) {
2018-01-12 01:29:51 -06:00
_ . each ( self . data _store . added , function ( val , key ) {
2017-08-21 09:27:29 -05:00
if ( key in self . data _store . staged _rows ) {
// Remove the row from data store so that we do not send it on server
deleted _keys . push ( key ) ;
}
} ) ;
}
// If only newly rows to delete and no data is there to send on server
// then just re-render the grid
2019-04-18 01:39:35 -05:00
if ( _ . size ( self . data _store . staged _rows ) > 0 && ( _ . size ( self . data _store . staged _rows ) === _ . size ( deleted _keys ) ) ) {
2017-08-21 09:27:29 -05:00
var grid = self . slickgrid ,
2018-01-12 01:29:51 -06:00
dataView = grid . getData ( ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
grid . resetActiveCell ( ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
dataView . beginUpdate ( ) ;
for ( var i = 0 ; i < deleted _keys . length ; i ++ ) {
2019-04-18 01:39:35 -05:00
delete self . data _store . staged _rows [ deleted _keys [ i ] ] ;
delete self . data _store . added [ deleted _keys [ i ] ] ;
delete self . data _store . added _index [ deleted _keys [ i ] ] ;
2017-08-21 09:27:29 -05:00
dataView . deleteItem ( deleted _keys [ i ] ) ;
}
dataView . endUpdate ( ) ;
self . rows _to _delete . apply ( self , [ dataView . getItems ( ) ] ) ;
grid . resetActiveCell ( ) ;
grid . setSelectedRows ( [ ] ) ;
grid . invalidate ( ) ;
2016-04-14 09:04:03 -05:00
2018-01-12 01:29:51 -06:00
// Nothing to copy or delete here
$ ( '#btn-delete-row' ) . prop ( 'disabled' , true ) ;
$ ( '#btn-copy-row' ) . prop ( 'disabled' , true ) ;
if ( _ . size ( self . data _store . added ) || is _updated ) {
// Do not disable save button if there are
// any other changes present in grid data
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-data' ) . prop ( 'disabled' , false ) ;
2017-08-21 09:27:29 -05:00
} else {
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-data' ) . prop ( 'disabled' , true ) ;
2017-08-21 09:27:29 -05:00
}
2018-01-12 01:29:51 -06:00
alertify . success ( gettext ( 'Row(s) deleted.' ) ) ;
} else {
2019-04-18 01:39:35 -05:00
let strikeout = true ;
_ . each ( _ . keys ( self . data _store . staged _rows ) , function ( key ) {
if ( key in self . data _store . deleted ) {
strikeout = false ;
return ;
2018-01-12 01:29:51 -06:00
}
} ) ;
2019-04-18 01:39:35 -05:00
if ( ! strikeout ) {
$ ( self . gridView . grid . getCanvasNode ( ) ) . find ( 'div.selected' ) . removeClass ( 'strikeout' ) ;
_ . each ( _ . keys ( self . data _store . staged _rows ) , function ( key ) {
if ( key in self . data _store . deleted ) {
delete self . data _store . deleted [ key ] ;
}
} ) ;
} else {
// Strike out the rows to be deleted
self . data _store . deleted = Object . assign ( { } , self . data _store . deleted , self . data _store . staged _rows ) ;
$ ( self . gridView . grid . getCanvasNode ( ) ) . find ( 'div.selected' ) . addClass ( 'strikeout' ) ;
}
if ( _ . size ( self . data _store . added ) || is _updated || _ . size ( self . data _store . deleted ) ) {
// Do not disable save button if there are
// any other changes present in grid data
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-data' ) . prop ( 'disabled' , false ) ;
2019-04-18 01:39:35 -05:00
} else {
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-data' ) . prop ( 'disabled' , true ) ;
2019-04-18 01:39:35 -05:00
}
2018-01-12 01:29:51 -06:00
}
} ,
2016-04-14 09:04:03 -05:00
2019-07-17 05:45:20 -05:00
// This function will open save file dialog conditionally.
_save _file : function ( save _as = false ) {
var self = this ;
var current _file = self . gridView . current _file ;
if ( ! _ . isUndefined ( current _file ) && ! save _as ) {
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 ) ;
}
} ,
2017-08-21 09:27:29 -05:00
/ * T h i s f u n c t i o n w i l l f e t c h t h e l i s t o f c h a n g e d m o d e l s a n d m a k e
* the ajax call to save the data into the database server .
* /
2019-07-17 05:45:20 -05:00
save _data : function ( ) {
var self = this ;
2017-08-21 09:27:29 -05:00
2019-07-17 05:45:20 -05:00
if ( ! self . can _edit )
2017-08-21 09:27:29 -05:00
return ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
var is _added = _ . size ( self . data _store . added ) ,
is _updated = _ . size ( self . data _store . updated ) ,
2018-01-12 01:29:51 -06:00
is _deleted = _ . size ( self . data _store . deleted ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
if ( ! is _added && ! is _updated && ! is _deleted ) {
2018-01-12 01:29:51 -06:00
return ; // Nothing to save here
2017-08-21 09:27:29 -05:00
}
2016-04-14 09:04:03 -05:00
2019-07-17 05:45:20 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
gettext ( 'Saving the updated data...' )
) ;
// Disable query tool buttons and cancel button only if query tool
if ( self . is _query _tool )
self . disable _tool _buttons ( true , true ) ;
2017-07-19 05:43:45 -05:00
2019-07-17 05:45:20 -05:00
// Add the columns to the data so the server can remap the data
var req _data = self . data _store , view = self . gridView ;
req _data . columns = view ? view . handler . columns : self . columns ;
2017-07-19 05:43:45 -05:00
2019-08-16 06:47:12 -05:00
var save _successful = false , save _start _time = new Date ( ) ;
2017-08-21 09:27:29 -05:00
2019-07-17 05:45:20 -05:00
// Make ajax call to save the data
$ . ajax ( {
url : url _for ( 'sqleditor.save' , {
'trans_id' : self . transId ,
} ) ,
method : 'POST' ,
contentType : 'application/json' ,
data : JSON . stringify ( req _data ) ,
} )
. done ( function ( res ) {
var grid = self . slickgrid ,
dataView = grid . getData ( ) ,
data _length = dataView . getLength ( ) ,
data = [ ] ;
var transaction _status = res . data . transaction _status ;
// Update last transaction status
self . last _transaction _status = transaction _status ;
var is _commit _required = transaction _status > 0 ; // 0 is idle
// Enable/Disable commit and rollback button.
if ( is _commit _required ) {
self . disable _transaction _buttons ( false ) ;
} else {
self . disable _transaction _buttons ( true ) ;
}
// Enable query tool buttons and cancel button only if query tool
if ( self . is _query _tool )
self . disable _tool _buttons ( false ) ;
if ( res . data . status ) {
// Disable Save Data Changes button
$ ( '#btn-save-data' ) . prop ( 'disabled' , true ) ;
save _successful = true ;
// Remove highlighted cells styling
for ( let i = 1 ; i <= self . numberOfModifiedCells ; i ++ )
grid . removeCellCssStyles ( i ) ;
self . numberOfModifiedCells = 0 ;
if ( is _added ) {
// Update the rows in a grid after addition
dataView . beginUpdate ( ) ;
2019-08-16 06:47:12 -05:00
_ . each ( res . data . query _results , function ( r ) {
2019-07-17 05:45:20 -05:00
if ( ! _ . isNull ( r . row _added ) ) {
// Fetch temp_id returned by server after addition
var row _id = Object . keys ( r . row _added ) [ 0 ] ;
_ . each ( req _data . added _index , function ( v , k ) {
if ( v == row _id ) {
// Fetch item data through row index
2020-07-09 08:14:58 -05:00
var item _fetched = grid . getDataItem ( k ) ;
_ . extend ( item _fetched , r . row _added [ row _id ] ) ;
2019-07-17 05:45:20 -05:00
}
} ) ;
2017-08-21 09:27:29 -05:00
}
} ) ;
2019-07-17 05:45:20 -05:00
dataView . endUpdate ( ) ;
}
// Remove flag is_row_copied from copied rows
_ . each ( data , function ( row ) {
if ( row . is _row _copied ) {
delete row . is _row _copied ;
2019-03-14 10:11:16 -05:00
}
2019-07-17 05:45:20 -05:00
} ) ;
2018-07-09 07:54:00 -05:00
2019-07-17 05:45:20 -05:00
// Remove 2d copied_rows array
if ( grid . copied _rows ) {
delete grid . copied _rows ;
}
// Remove deleted rows from client as well
if ( is _deleted ) {
var rows = _ . keys ( self . data _store . deleted ) ;
if ( data _length == rows . length ) {
// This means all the rows are selected, clear all data
data = [ ] ;
dataView . setItems ( data , self . client _primary _key ) ;
} else {
dataView . beginUpdate ( ) ;
2020-07-09 08:14:58 -05:00
for ( var j = 0 ; j < rows . length ; j ++ ) {
2021-01-20 01:09:12 -06:00
var item = grid . getData ( ) . getItemById ( rows [ j ] ) ;
2019-07-17 05:45:20 -05:00
data . push ( item ) ;
dataView . deleteItem ( item [ self . client _primary _key ] ) ;
2017-08-21 09:27:29 -05:00
}
2019-07-17 05:45:20 -05:00
dataView . endUpdate ( ) ;
2017-08-21 09:27:29 -05:00
}
2019-07-17 05:45:20 -05:00
self . rows _to _delete . apply ( self , [ data ] ) ;
}
2017-08-21 09:27:29 -05:00
2019-07-17 05:45:20 -05:00
grid . setSelectedRows ( [ ] ) ;
2017-08-21 09:27:29 -05:00
2019-07-17 05:45:20 -05:00
// Reset data store
self . reset _data _store ( ) ;
2017-11-30 01:23:12 -06:00
2019-07-17 05:45:20 -05:00
// Reset old primary key data now
self . primary _keys _data = { } ;
2018-07-09 07:54:00 -05:00
2019-07-17 05:45:20 -05:00
// Clear msgs after successful save
self . set _sql _message ( '' ) ;
alertify . success ( gettext ( 'Data saved successfully.' ) ) ;
if ( is _commit _required )
alertify . info ( gettext ( 'Auto-commit is off. You still need to commit changes to the database.' ) ) ;
} else {
// Something went wrong while saving data on the db server
self . set _sql _message ( res . data . result ) ;
2019-10-10 01:35:28 -05:00
var err _msg = gettext ( '%s.' , res . data . result ) ;
2019-07-17 05:45:20 -05:00
alertify . error ( err _msg , 20 ) ;
// If the transaction is not idle, notify the user that previous queries are not rolled back,
// only the failed save queries.
if ( transaction _status != 0 )
alertify . info ( gettext ( 'Saving data changes was rolled back but the current transaction is ' +
'still active; previous queries are unaffected.' ) ) ;
grid . setSelectedRows ( [ ] ) ;
// To highlight the row at fault
if ( _ . has ( res . data , '_rowid' ) &&
( ! _ . isUndefined ( res . data . _rowid ) || ! _ . isNull ( res . data . _rowid ) ) ) {
var _row _index = self . _find _rowindex ( res . data . _rowid ) ;
if ( _row _index in self . data _store . added _index ) {
// Remove new row index from temp_list if save operation
// fails
var index = self . handler . temp _new _rows . indexOf ( res . data . _rowid ) ;
if ( index > - 1 ) {
self . handler . temp _new _rows . splice ( index , 1 ) ;
2017-08-21 09:27:29 -05:00
}
2019-07-17 05:45:20 -05:00
self . data _store . added [ self . data _store . added _index [ _row _index ] ] . err = true ;
} else if ( _row _index in self . data _store . updated _index ) {
self . data _store . updated [ self . data _store . updated _index [ _row _index ] ] . err = true ;
2018-01-12 01:29:51 -06:00
}
2017-11-30 01:23:12 -06:00
}
2019-07-17 05:45:20 -05:00
grid . gotoCell ( _row _index , 1 ) ;
}
2017-08-21 09:27:29 -05:00
2019-08-16 06:47:12 -05:00
var query _history _info _msg = gettext ( 'This query was generated by pgAdmin as part of a "Save Data" operation' ) ;
_ . each ( res . data . query _results , function ( r ) {
var history _entry = {
'status' : r . status ,
'start_time' : save _start _time ,
'query' : r . sql ,
'row_affected' : r . rows _affected ,
'total_time' : null ,
'message' : r . result ,
'query_source' : QuerySources . SAVE _DATA ,
'is_pgadmin_query' : true ,
'info' : query _history _info _msg ,
} ;
self . add _to _history ( history _entry ) ;
} ) ;
2019-07-17 05:45:20 -05:00
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
2017-08-21 09:27:29 -05:00
2019-07-17 05:45:20 -05:00
grid . invalidate ( ) ;
if ( self . close _on _save ) {
if ( save _successful ) {
// Check for any other needed confirmations before closing
self . check _needed _confirmations _before _closing _panel ( ) ;
2019-03-14 10:11:16 -05:00
}
2019-07-17 05:45:20 -05:00
else {
self . close _on _save = false ;
}
}
} )
. fail ( function ( e ) {
let stateParams = [ view ] ;
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , 'save_data' , stateParams , true
) ;
// Enable query tool buttons and cancel button only if query tool
if ( self . is _query _tool )
self . disable _tool _buttons ( false ) ;
2020-04-15 06:16:03 -05:00
if ( msg )
self . update _msg _history ( false , msg ) ;
2019-07-17 05:45:20 -05:00
} ) ;
} ,
reset _data _store : function ( ) {
var self = this ;
// This holds all the inserted/updated/deleted data from grid
self . data _store = {
updated : { } ,
added : { } ,
staged _rows : { } ,
deleted : { } ,
updated _index : { } ,
added _index : { } ,
} ;
2017-07-19 05:43:45 -05:00
} ,
2017-08-21 09:27:29 -05:00
// Find index of row at fault from grid data
2018-01-12 01:29:51 -06:00
_find _rowindex : function ( rowid ) {
2017-08-21 09:27:29 -05:00
var self = this ,
grid = self . slickgrid ,
dataView = grid . getData ( ) ,
data = dataView . getItems ( ) ,
_rowid ,
count = 0 ,
_idx = - 1 ;
// If _rowid is object then it's update/delete operation
if ( _ . isObject ( rowid ) ) {
_rowid = rowid ;
} else if ( _ . isString ( rowid ) ) { // Insert operation
2018-01-12 01:29:51 -06:00
rowid = { } ;
2017-08-21 09:27:29 -05:00
rowid [ self . client _primary _key ] = rowid ;
_rowid = rowid ;
} else {
// Something is wrong with unique id
return _idx ;
}
2018-01-12 01:29:51 -06:00
_ . find ( data , function ( d ) {
2017-08-21 09:27:29 -05:00
// search for unique id in row data if found than its the row
// which error out on server side
2018-01-12 01:29:51 -06:00
var tmp = [ ] ; //_.findWhere needs array of object to work
2017-08-21 09:27:29 -05:00
tmp . push ( d ) ;
if ( _ . findWhere ( tmp , _rowid ) ) {
_idx = count ;
// Now exit the loop by returning true
return true ;
}
count ++ ;
} ) ;
// Not able to find in grid Data
return _idx ;
} ,
// Save as
2018-01-12 01:29:51 -06:00
_save _as : function ( ) {
2019-07-17 05:45:20 -05:00
return this . _save _file ( true ) ;
2017-07-19 05:43:45 -05:00
} ,
2017-08-21 09:27:29 -05:00
// Set panel title.
2020-11-30 23:58:10 -06:00
setTitle : function ( title , is _file , is _dirty _editor = false ) {
2017-07-19 05:43:45 -05:00
var self = this ;
2020-11-04 06:15:28 -06:00
var open _new _tab = self . browser _preferences . new _browser _tab _open ;
if ( open _new _tab && open _new _tab . includes ( 'qt' ) ) {
2017-08-21 09:27:29 -05:00
window . document . title = title ;
} else {
2019-09-23 02:25:02 -05:00
_ . each ( pgWindow . default . pgAdmin . Browser . docker . findPanels ( 'frm_datagrid' ) , function ( p ) {
2017-08-21 09:27:29 -05:00
if ( p . isVisible ( ) ) {
2020-11-30 23:58:10 -06:00
if ( is _dirty _editor ) {
p . is _dirty _editor = true ;
}
2019-06-24 05:36:03 -05:00
panelTitleFunc . setQueryToolDockerTitle ( p , self . is _query _tool , title , is _file ) ;
2017-08-21 09:27:29 -05:00
}
} ) ;
}
2017-07-19 05:43:45 -05:00
} ,
2017-08-21 09:27:29 -05:00
// load select file dialog
2018-01-12 01:29:51 -06:00
_load _file : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2016-06-02 02:45:24 -05:00
2017-01-07 21:35:01 -06:00
/ * I f i s _ q u e r y _ c h a n g e d f l a g i s s e t t o f a l s e t h e n n o n e e d t o
* confirm with the user for unsaved changes .
* /
2017-08-21 09:27:29 -05:00
if ( self . is _query _changed ) {
2018-01-12 01:29:51 -06:00
alertify . confirm ( gettext ( 'Unsaved changes' ) ,
gettext ( 'Are you sure you wish to discard the current changes?' ) ,
function ( ) {
2017-08-21 09:27:29 -05:00
// User do not want to save, just continue
self . _open _select _file _manager ( ) ;
2017-01-07 21:35:01 -06:00
} ,
2018-01-12 01:29:51 -06:00
function ( ) {
2017-01-07 21:35:01 -06:00
return true ;
}
2018-01-12 01:29:51 -06:00
) . set ( 'labels' , {
2020-04-10 04:22:41 -05:00
ok : gettext ( 'Yes' ) ,
cancel : gettext ( 'No' ) ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-01-07 21:35:01 -06:00
} else {
2017-08-21 09:27:29 -05:00
self . _open _select _file _manager ( ) ;
2017-01-07 21:35:01 -06:00
}
2016-04-14 09:04:03 -05:00
} ,
2017-08-21 09:27:29 -05:00
// Open FileManager
2018-01-12 01:29:51 -06:00
_open _select _file _manager : function ( ) {
2017-08-21 09:27:29 -05:00
var params = {
2018-01-12 01:29:51 -06:00
'supported_types' : [ 'sql' ] , // file types allowed
'dialog_type' : 'select_file' , // open select file dialog
} ;
2017-08-21 09:27:29 -05:00
pgAdmin . FileManager . init ( ) ;
pgAdmin . FileManager . show _dialog ( params ) ;
} ,
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// read file data and return as response
2018-01-12 01:29:51 -06:00
_select _file _handler : function ( e ) {
2017-08-21 09:27:29 -05:00
var self = this ,
2018-02-01 07:29:18 -06:00
_e = e ,
2017-08-21 09:27:29 -05:00
data = {
2018-01-12 01:29:51 -06:00
'file_name' : decodeURI ( e ) ,
2017-08-21 09:27:29 -05:00
} ;
2016-06-02 02:45:24 -05:00
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2018-01-12 01:29:51 -06:00
gettext ( 'Loading the file...' )
2016-04-14 09:04:03 -05:00
) ;
2017-08-21 09:27:29 -05:00
// set cursor to progress before file load
var $busy _icon _div = $ ( '.sql-editor-busy-fetching' ) ;
$busy _icon _div . addClass ( 'show_progress' ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// Make ajax call to load the data from file
$ . ajax ( {
url : url _for ( 'sqleditor.load_file' ) ,
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2017-08-21 09:27:29 -05:00
data : JSON . stringify ( data ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
self . gridView . query _tool _obj . setValue ( res ) ;
self . gridView . current _file = e ;
2020-12-14 00:32:02 -06:00
self . gridView . query _tool _obj . file _data = res ;
2019-03-14 10:11:16 -05:00
self . setTitle ( self . gridView . current _file . split ( '\\' ) . pop ( ) . split ( '/' ) . pop ( ) , true ) ;
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
// hide cursor
$busy _icon _div . removeClass ( 'show_progress' ) ;
2016-04-14 09:04:03 -05:00
2019-03-14 10:11:16 -05:00
// disable save button on file save
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-file' ) . prop ( 'disabled' , true ) ;
2019-03-14 10:11:16 -05:00
$ ( '#btn-file-menu-save' ) . css ( 'display' , 'none' ) ;
2016-06-02 02:45:24 -05:00
2019-03-14 10:11:16 -05:00
// Update the flag as new content is just loaded.
self . is _query _changed = false ;
setTimeout ( ( ) => { self . gridView . query _tool _obj . focus ( ) ; } , 200 ) ;
} )
2020-07-09 08:14:58 -05:00
. fail ( function ( er ) {
2019-03-14 10:11:16 -05:00
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
let stateParams = [ _e ] ;
let msg = httpErrorHandler . handleQueryToolAjaxError (
2020-07-09 08:14:58 -05:00
pgAdmin , self , er , '_select_file_handler' , stateParams , false
2019-03-14 10:11:16 -05:00
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . error ( msg ) ;
2019-03-14 10:11:16 -05:00
// hide cursor
$busy _icon _div . removeClass ( 'show_progress' ) ;
} ) ;
2018-01-12 01:29:51 -06:00
} ,
2016-05-15 14:37:52 -05:00
2017-08-21 09:27:29 -05:00
// read data from codemirror and write to file
2018-01-12 01:29:51 -06:00
_save _file _handler : function ( e ) {
2017-08-21 09:27:29 -05:00
var self = this ,
2018-02-01 07:29:18 -06:00
_e = e ,
2017-08-21 09:27:29 -05:00
data = {
'file_name' : decodeURI ( e ) ,
2018-01-12 01:29:51 -06:00
'file_content' : self . gridView . query _tool _obj . getValue ( ) ,
2017-08-21 09:27:29 -05:00
} ;
2020-12-14 00:32:02 -06:00
var file _data = self . gridView . query _tool _obj . getValue ( ) ;
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2018-01-12 01:29:51 -06:00
gettext ( 'Saving the queries in the file...' )
2017-08-21 09:27:29 -05:00
) ;
2016-05-15 14:37:52 -05:00
2018-01-12 01:29:51 -06:00
// Make ajax call to save the data to file
$ . ajax ( {
url : url _for ( 'sqleditor.save_file' ) ,
method : 'POST' ,
contentType : 'application/json' ,
data : JSON . stringify ( data ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
if ( res . data . status ) {
alertify . success ( gettext ( 'File saved successfully.' ) ) ;
self . gridView . current _file = e ;
self . setTitle ( self . gridView . current _file . replace ( /^.*[\\\/]/g , '' ) , true ) ;
2020-12-14 00:32:02 -06:00
self . gridView . query _tool _obj . file _data = file _data ;
2019-03-14 10:11:16 -05:00
// disable save button on file save
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-file' ) . prop ( 'disabled' , true ) ;
2019-03-14 10:11:16 -05:00
$ ( '#btn-file-menu-save' ) . css ( 'display' , 'none' ) ;
// Update the flag as query is already saved.
self . is _query _changed = false ;
setTimeout ( ( ) => { self . gridView . query _tool _obj . focus ( ) ; } , 200 ) ;
}
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
if ( self . close _on _save ) {
2019-07-17 05:45:20 -05:00
// Check for any other needed confirmations before closing
self . check _needed _confirmations _before _closing _panel ( ) ;
2019-03-14 10:11:16 -05:00
}
} )
2020-07-09 08:14:58 -05:00
. fail ( function ( er ) {
2019-03-14 10:11:16 -05:00
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
let stateParams = [ _e ] ;
let msg = httpErrorHandler . handleQueryToolAjaxError (
2020-07-09 08:14:58 -05:00
pgAdmin , self , er , '_save_file_handler' , stateParams , false
2019-03-14 10:11:16 -05:00
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . error ( msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2018-01-12 01:29:51 -06:00
} ,
2016-05-15 14:37:52 -05:00
2017-08-21 09:27:29 -05:00
// codemirror text change event
2018-01-12 01:29:51 -06:00
_on _query _change : function ( ) {
2016-05-15 14:37:52 -05:00
var self = this ;
2017-08-21 09:27:29 -05:00
if ( ! self . is _query _changed ) {
// Update the flag as query is going to changed.
self . is _query _changed = true ;
2016-06-02 02:45:24 -05:00
2017-08-21 09:27:29 -05:00
if ( self . gridView . current _file ) {
2018-01-12 01:29:51 -06:00
var title = self . gridView . current _file . replace ( /^.*[\\\/]/g , '' ) + ' *' ;
2018-03-19 05:58:12 -05:00
self . setTitle ( title , true ) ;
2017-08-21 09:27:29 -05:00
} else {
2020-11-04 06:15:28 -06:00
var open _new _tab = self . browser _preferences . new _browser _tab _open ;
2020-11-30 23:58:10 -06:00
var is _dirty _editor = false ;
2020-11-04 06:15:28 -06:00
if ( open _new _tab && open _new _tab . includes ( 'qt' ) ) {
2017-08-21 09:27:29 -05:00
title = window . document . title + ' *' ;
} else {
// Find the title of the visible panel
2019-09-23 02:25:02 -05:00
_ . each ( pgWindow . default . pgAdmin . Browser . docker . findPanels ( 'frm_datagrid' ) , function ( p ) {
2017-08-21 09:27:29 -05:00
if ( p . isVisible ( ) ) {
2019-08-28 00:16:28 -05:00
self . gridView . panel _title = $ ( p . _title ) . text ( ) ;
2017-08-21 09:27:29 -05:00
}
} ) ;
2016-05-15 14:37:52 -05:00
2017-08-21 09:27:29 -05:00
title = self . gridView . panel _title + ' *' ;
2020-11-30 23:58:10 -06:00
is _dirty _editor = true ;
2017-08-21 09:27:29 -05:00
}
2020-11-30 23:58:10 -06:00
self . setTitle ( title , false , is _dirty _editor ) ;
2017-08-21 09:27:29 -05:00
}
2016-06-02 02:45:24 -05:00
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-file' ) . prop ( 'disabled' , false ) ;
2018-01-12 01:29:51 -06:00
$ ( '#btn-file-menu-save' ) . css ( 'display' , 'block' ) ;
$ ( '#btn-file-menu-dropdown' ) . prop ( 'disabled' , false ) ;
2020-12-14 00:32:02 -06:00
} else {
if ( self . gridView . current _file ) {
if ( self . gridView . query _tool _obj . file _data == self . gridView . query _tool _obj . getValue ( ) ) {
title = self . gridView . current _file . replace ( /^.*[\\\/]/g , '' ) ;
is _dirty _editor = false ;
} else {
title = self . gridView . current _file . replace ( /^.*[\\\/]/g , '' ) + ' *' ;
is _dirty _editor = true ;
}
self . setTitle ( title , true , is _dirty _editor ) ;
}
2017-08-21 09:27:29 -05:00
}
2016-05-15 14:37:52 -05:00
} ,
2017-08-21 09:27:29 -05:00
// This function will set the required flag for polling response data
2018-01-12 01:29:51 -06:00
_init _polling _flags : function ( ) {
2016-05-15 14:37:52 -05:00
var self = this ;
2017-08-21 09:27:29 -05:00
// To get a timeout for polling fallback timer in seconds in
// regards to elapsed time
2018-01-12 01:29:51 -06:00
self . POLL _FALLBACK _TIME = function ( ) {
2017-08-21 09:27:29 -05:00
var seconds = parseInt ( ( Date . now ( ) - self . query _start _time . getTime ( ) ) / 1000 ) ;
// calculate & return fall back polling timeout
if ( seconds >= 10 && seconds < 30 ) {
return 500 ;
2018-01-12 01:29:51 -06:00
} else if ( seconds >= 30 && seconds < 60 ) {
2017-08-21 09:27:29 -05:00
return 1000 ;
2018-01-12 01:29:51 -06:00
} else if ( seconds >= 60 && seconds < 90 ) {
2017-08-21 09:27:29 -05:00
return 2000 ;
2018-01-12 01:29:51 -06:00
} else if ( seconds >= 90 ) {
2017-08-21 09:27:29 -05:00
return 5000 ;
2020-06-26 02:42:07 -05:00
} else {
2017-08-21 09:27:29 -05:00
return 1 ;
2020-06-26 02:42:07 -05:00
}
2018-01-12 01:29:51 -06:00
} ;
2016-05-15 14:37:52 -05:00
} ,
2017-08-21 09:27:29 -05:00
// This function will show the filter in the text area.
2018-01-12 01:29:51 -06:00
_show _filter : function ( ) {
2018-08-22 06:08:31 -05:00
let self = this ,
reconnect = false ;
/ * W h e n s e r v e r i s d i s c o n n e c t e d a n d c o n n e c t e d , c o n n e c t i o n i s l o s t ,
* To reconnect pass true
* /
if ( arguments . length > 0 &&
arguments [ arguments . length - 1 ] == 'connect' ) {
reconnect = true ;
}
FilterHandler . dialog ( self , reconnect ) ;
2016-05-14 04:59:03 -05:00
} ,
2020-10-01 02:59:00 -05:00
// This function will show the new connection.
_show _new _connection : function ( ) {
let self = this ,
reconnect = false ;
2016-05-14 04:59:03 -05:00
2020-10-01 02:59:00 -05:00
/ * W h e n s e r v e r i s d i s c o n n e c t e d a n d c o n n e c t e d , c o n n e c t i o n i s l o s t ,
* To reconnect pass true
* /
if ( arguments . length > 0 && arguments [ arguments . length - 1 ] == 'connect' ) {
reconnect = true ;
}
2020-11-04 06:15:28 -06:00
newConnectionHandler . dialog ( self , reconnect , self . browser _preferences ) ;
2020-10-01 02:59:00 -05:00
} ,
2017-08-21 09:27:29 -05:00
// This function will include the filter by selection.
2018-01-12 01:29:51 -06:00
_include _filter : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ,
2018-01-12 01:29:51 -06:00
data = { } ,
grid , active _column , column _info , _values ;
2016-05-14 04:59:03 -05:00
2017-08-21 09:27:29 -05:00
grid = self . slickgrid ;
active _column = grid . getActiveCell ( ) ;
2016-06-02 02:45:24 -05:00
2017-08-21 09:27:29 -05:00
// If no cell is selected then return from the function
if ( _ . isNull ( active _column ) || _ . isUndefined ( active _column ) )
return ;
2016-06-20 07:03:46 -05:00
2018-01-12 01:29:51 -06:00
column _info = grid . getColumns ( ) [ active _column . cell ] ;
2017-07-20 16:22:25 -05:00
2017-08-21 09:27:29 -05:00
// Fetch current row data from grid
2018-01-12 01:29:51 -06:00
_values = grid . getDataItem ( active _column . row , active _column . cell ) ;
2017-08-21 09:27:29 -05:00
if ( _ . isNull ( _values ) || _ . isUndefined ( _values ) )
return ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// Add column position and it's value to data
data [ column _info . field ] = _values [ column _info . field ] || '' ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2018-01-12 01:29:51 -06:00
gettext ( 'Applying the new filter...' )
2017-08-21 09:27:29 -05:00
) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// Make ajax call to include the filter by selection
$ . ajax ( {
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.inclusive_filter' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2017-08-21 09:27:29 -05:00
data : JSON . stringify ( data ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
setTimeout (
function ( ) {
if ( res . data . status ) {
2018-07-09 07:54:00 -05:00
// Refresh the sql grid
2019-03-14 10:11:16 -05:00
queryToolActions . executeQuery ( self ) ;
} else {
alertify . alert ( gettext ( 'Filter By Selection Error' ) , res . data . result ) ;
}
2017-08-21 09:27:29 -05:00
}
2019-03-14 10:11:16 -05:00
) ;
} )
. fail ( function ( e ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , '_include_filter' , [ ] , true
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . alert ( gettext ( 'Filter By Selection Error' ) , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// This function will exclude the filter by selection.
2018-01-12 01:29:51 -06:00
_exclude _filter : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ,
2018-01-12 01:29:51 -06:00
data = { } ,
grid , active _column , column _info , _values ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
grid = self . slickgrid ;
active _column = grid . getActiveCell ( ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// If no cell is selected then return from the function
if ( _ . isNull ( active _column ) || _ . isUndefined ( active _column ) )
return ;
2016-05-14 04:59:03 -05:00
2018-01-12 01:29:51 -06:00
column _info = grid . getColumns ( ) [ active _column . cell ] ;
2016-05-14 04:59:03 -05:00
2017-08-21 09:27:29 -05:00
// Fetch current row data from grid
2018-01-12 01:29:51 -06:00
_values = grid . getDataItem ( active _column . row , active _column . cell ) ;
2017-08-21 09:27:29 -05:00
if ( _ . isNull ( _values ) || _ . isUndefined ( _values ) )
return ;
2016-09-01 05:50:48 -05:00
2017-08-21 09:27:29 -05:00
// Add column position and it's value to data
data [ column _info . field ] = _values [ column _info . field ] || '' ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2018-01-12 01:29:51 -06:00
gettext ( 'Applying the new filter...' )
2017-08-21 09:27:29 -05:00
) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// Make ajax call to exclude the filter by selection.
$ . ajax ( {
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.exclusive_filter' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2017-08-21 09:27:29 -05:00
data : JSON . stringify ( data ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
setTimeout (
function ( ) {
if ( res . data . status ) {
2018-07-09 07:54:00 -05:00
// Refresh the sql grid
2019-03-14 10:11:16 -05:00
queryToolActions . executeQuery ( self ) ;
} else {
alertify . alert ( gettext ( 'Filter Exclude Selection Error' ) , res . data . result ) ;
}
} , 10
) ;
} )
. fail ( function ( e ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , '_exclude_filter' , [ ] , true
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . alert ( gettext ( 'Filter Exclude Selection Error' ) , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// This function will remove the filter.
2018-01-12 01:29:51 -06:00
_remove _filter : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2018-01-12 01:29:51 -06:00
gettext ( 'Removing the filter...' )
2017-08-21 09:27:29 -05:00
) ;
2016-05-15 14:37:52 -05:00
2017-08-21 09:27:29 -05:00
// Make ajax call to exclude the filter by selection.
$ . ajax ( {
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.remove_filter' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
setTimeout (
function ( ) {
if ( res . data . status ) {
2018-07-09 07:54:00 -05:00
// Refresh the sql grid
2019-03-14 10:11:16 -05:00
queryToolActions . executeQuery ( self ) ;
} else {
alertify . alert ( gettext ( 'Remove Filter Error' ) , res . data . result ) ;
}
2017-08-21 09:27:29 -05:00
}
2019-03-14 10:11:16 -05:00
) ;
} )
. fail ( function ( e ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , '_remove_filter' , [ ] , true
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . alert ( gettext ( 'Remove Filter Error' ) , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
// This function will copy the selected row.
_copy _row : copyData ,
2019-09-27 01:44:39 -05:00
_copy _row _with _header : function ( ) {
$ ( '.copy-with-header' ) . toggleClass ( 'visibility-hidden' ) ;
} ,
2020-04-16 04:55:39 -05:00
// This function will enable Paste button if data is copied in some other active session
_copied _in _other _session : function ( e , copiedWithHeaders ) {
pgAdmin . SqlEditor . copiedInOtherSessionWithHeaders = copiedWithHeaders ;
$ ( '#btn-paste-row' ) . prop ( 'disabled' , false ) ;
} ,
2017-08-21 09:27:29 -05:00
// This function will paste the selected row.
2018-01-12 01:29:51 -06:00
_paste _row : function ( ) {
2020-04-16 04:55:39 -05:00
var self = this ;
let rowsText = clipboard . getTextFromClipboard ( ) ;
2020-08-10 06:23:32 -05:00
let copied _rows = pgadminUtils . CSVToArray ( rowsText , self . preferences . results _grid _field _separator , self . preferences . results _grid _quote _char ) ;
2020-04-16 04:55:39 -05:00
// Do not parse row if rows are copied with headers
if ( pgAdmin . SqlEditor . copiedInOtherSessionWithHeaders ) {
copied _rows = copied _rows . slice ( 1 ) ;
2017-09-18 01:37:15 -05:00
}
2020-08-10 06:23:32 -05:00
copied _rows = copied _rows . reduce ( ( partial , values ) => {
2020-04-16 04:55:39 -05:00
// split each row with field separator character
let row = { } ;
2020-07-09 08:14:58 -05:00
for ( let col in self . columns ) {
2020-08-10 06:23:32 -05:00
let v = values [ col ] ;
2020-04-22 01:38:52 -05:00
// set value to default or null depending on column metadata
if ( v === '' ) {
2020-07-09 08:14:58 -05:00
if ( self . columns [ col ] . has _default _val ) {
2020-04-22 01:38:52 -05:00
v = undefined ;
} else {
v = null ;
}
}
2020-07-09 08:14:58 -05:00
row [ self . columns [ col ] . name ] = v ;
2020-04-16 04:55:39 -05:00
}
partial . push ( row ) ;
return partial ;
} , [ ] ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// If there are rows to paste?
if ( copied _rows . length > 0 ) {
// Enable save button so that user can
// save newly pasted rows on server
2019-07-17 05:45:20 -05:00
$ ( '#btn-save-data' ) . prop ( 'disabled' , false ) ;
2016-04-14 09:04:03 -05:00
2020-04-16 04:55:39 -05:00
var grid = self . slickgrid ,
dataView = grid . getData ( ) ,
count = dataView . getLength ( ) ,
array _types = [ ] ;
// for quick look up create list of array data types
for ( var k in self . columns ) {
if ( self . columns [ k ] . is _array ) {
array _types . push ( self . columns [ k ] . name ) ;
}
}
var arr _to _object = function ( arr ) {
2018-01-12 01:29:51 -06:00
var obj = { } ;
2016-04-14 09:04:03 -05:00
2020-04-16 04:55:39 -05:00
_ . each ( arr , function ( val , i ) {
2017-08-21 09:27:29 -05:00
if ( arr [ i ] !== undefined ) {
2017-09-18 01:37:15 -05:00
// Do not stringify array types.
if ( _ . isObject ( arr [ i ] ) && array _types . indexOf ( i ) == - 1 ) {
2017-08-21 09:27:29 -05:00
obj [ String ( i ) ] = JSON . stringify ( arr [ i ] ) ;
} else {
obj [ String ( i ) ] = arr [ i ] ;
2016-04-14 09:04:03 -05:00
}
2017-08-21 09:27:29 -05:00
}
} ) ;
return obj ;
} ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// Generate Unique key for each pasted row(s)
// Convert array values to object to send to server
// Add flag is_row_copied to handle [default] and [null]
// for copied rows.
// Add index of copied row into temp_new_rows
// Trigger grid.onAddNewRow when a row is copied
// Reset selection
dataView . beginUpdate ( ) ;
2020-04-16 04:55:39 -05:00
_ . each ( copied _rows , function ( row ) {
2017-08-21 09:27:29 -05:00
var new _row = arr _to _object ( row ) ,
_key = ( self . gridView . client _primary _key _counter ++ ) . toString ( ) ;
new _row . is _row _copied = true ;
self . temp _new _rows . push ( count ) ;
new _row [ self . client _primary _key ] = _key ;
2020-04-16 04:55:39 -05:00
if ( self . has _oids && new _row . oid ) {
2019-08-28 03:05:40 -05:00
new _row . oid = null ;
}
2017-08-21 09:27:29 -05:00
dataView . addItem ( new _row ) ;
2018-01-12 01:29:51 -06:00
self . data _store . added [ _key ] = {
'err' : false ,
'data' : new _row ,
} ;
2017-08-21 09:27:29 -05:00
self . data _store . added _index [ count ] = _key ;
count ++ ;
} ) ;
dataView . endUpdate ( ) ;
2020-04-16 04:55:39 -05:00
grid . invalidateRow ( grid . getSelectedRows ( ) ) ;
2017-08-21 09:27:29 -05:00
grid . updateRowCount ( ) ;
2020-04-16 04:55:39 -05:00
grid . render ( ) ;
2017-08-21 09:27:29 -05:00
// Pasted row/s always append so bring last row in view port.
grid . scrollRowIntoView ( dataView . getLength ( ) ) ;
grid . setSelectedRows ( [ ] ) ;
}
} ,
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// This function will set the limit for SQL query
2018-01-12 01:29:51 -06:00
_set _limit : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ,
2018-01-12 01:29:51 -06:00
limit = parseInt ( $ ( '.limit' ) . val ( ) ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2018-01-12 01:29:51 -06:00
gettext ( 'Setting the limit on the result...' )
2017-08-21 09:27:29 -05:00
) ;
// Make ajax call to change the limit
$ . ajax ( {
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.set_limit' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2017-08-21 09:27:29 -05:00
data : JSON . stringify ( limit ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
setTimeout (
function ( ) {
if ( res . data . status ) {
2018-07-09 07:54:00 -05:00
// Refresh the sql grid
2019-03-14 10:11:16 -05:00
queryToolActions . executeQuery ( self ) ;
2020-06-26 02:42:07 -05:00
} else {
2019-03-14 10:11:16 -05:00
alertify . alert ( gettext ( 'Change limit Error' ) , res . data . result ) ;
2020-06-26 02:42:07 -05:00
}
2019-03-14 10:11:16 -05:00
} , 10
) ;
} )
. fail ( function ( e ) {
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , '_set_limit' , [ ] , true
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . alert ( gettext ( 'Change limit Error' ) , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-09-16 04:18:49 -05:00
2017-08-21 09:27:29 -05:00
// This function is used to enable/disable buttons
2019-07-17 05:45:20 -05:00
disable _tool _buttons : function ( disabled , disable _cancel = null ) {
2019-03-29 09:31:33 -05:00
let mode _disabled = disabled ;
/* Buttons be always disabled in view/edit mode */
if ( ! this . is _query _tool ) {
mode _disabled = true ;
}
$ ( '#btn-explain' ) . prop ( 'disabled' , mode _disabled ) ;
$ ( '#btn-explain-analyze' ) . prop ( 'disabled' , mode _disabled ) ;
$ ( '#btn-explain-options-dropdown' ) . prop ( 'disabled' , mode _disabled ) ;
$ ( '#btn-edit-dropdown' ) . prop ( 'disabled' , mode _disabled ) ;
$ ( '#btn-load-file' ) . prop ( 'disabled' , mode _disabled ) ;
2020-12-17 00:07:03 -06:00
if ( this . gridView . current _file ) {
if ( this . gridView . query _tool _obj . file _data != this . gridView . query _tool _obj . getValue ( ) ) {
$ ( '#btn-save-file' ) . prop ( 'disabled' , mode _disabled ) ;
}
} else {
$ ( '#btn-save-file' ) . prop ( 'disabled' , mode _disabled ) ;
}
2019-03-29 09:31:33 -05:00
$ ( '#btn-file-menu-dropdown' ) . prop ( 'disabled' , mode _disabled ) ;
$ ( '#btn-find' ) . prop ( 'disabled' , mode _disabled ) ;
$ ( '#btn-find-menu-dropdown' ) . prop ( 'disabled' , mode _disabled ) ;
2020-09-28 04:56:45 -05:00
$ ( '#btn-macro-dropdown' ) . prop ( 'disabled' , mode _disabled ) ;
2019-07-17 05:45:20 -05:00
2018-07-02 09:43:36 -05:00
if ( this . is _query _tool ) {
2019-07-17 05:45:20 -05:00
if ( disable _cancel !== null )
$ ( '#btn-cancel-query' ) . prop ( 'disabled' , disable _cancel ) ;
// Cancel query tool needs opposite behaviour if not explicitly given
else
$ ( '#btn-cancel-query' ) . prop ( 'disabled' , ! disabled ) ;
2019-03-29 09:31:33 -05:00
if ( this . is _transaction _buttons _disabled ) {
$ ( '#btn-query-dropdown' ) . prop ( 'disabled' , disabled ) ;
} else {
$ ( '#btn-query-dropdown' ) . prop ( 'disabled' , true ) ;
}
2019-03-04 04:44:13 -06:00
} else {
2019-03-29 09:31:33 -05:00
$ ( '#btn-query-dropdown' ) . prop ( 'disabled' , mode _disabled ) ;
2018-07-02 09:43:36 -05:00
}
2017-08-21 09:27:29 -05:00
} ,
2016-04-14 09:04:03 -05:00
2019-02-22 08:28:05 -06:00
// This function is used to enable/disable commit/rollback buttons
disable _transaction _buttons : function ( disabled ) {
this . is _transaction _buttons _disabled = disabled ;
if ( this . is _query _tool ) {
$ ( '#btn-commit' ) . prop ( 'disabled' , disabled ) ;
$ ( '#btn-rollback' ) . prop ( 'disabled' , disabled ) ;
}
} ,
2017-08-21 09:27:29 -05:00
/ * T h i s f u n c t i o n i s u s e d t o h i g h l i g h t t h e e r r o r l i n e a n d
* underlining for the error word .
* /
2018-01-12 01:29:51 -06:00
_highlight _error : function ( result ) {
2017-08-21 09:27:29 -05:00
var self = this ,
error _line _no = 0 ,
start _marker = 0 ,
end _marker = 0 ,
selected _line _no = 0 ;
// Remove already existing marker
self . gridView . query _tool _obj . removeLineClass ( self . marked _line _no , 'wrap' , 'CodeMirror-activeline-background' ) ;
// In case of selection we need to find the actual line no
if ( self . gridView . query _tool _obj . getSelection ( ) . length > 0 )
selected _line _no = self . gridView . query _tool _obj . getCursor ( true ) . line ;
// Fetch the LINE string using regex from the result
var line = /LINE (\d+)/ . exec ( result ) ,
// Fetch the Character string using regex from the result
char = /Character: (\d+)/ . exec ( result ) ;
// If line and character is null then no need to mark
if ( line != null && char != null ) {
error _line _no = self . marked _line _no = ( parseInt ( line [ 1 ] ) - 1 ) + selected _line _no ;
var error _char _no = ( parseInt ( char [ 1 ] ) - 1 ) ;
/ * W e n e e d t o l o o p t h r o u g h e a c h l i n e t i l l t h e e r r o r l i n e a n d
* count the total no of character to figure out the actual
* starting / ending marker point for the individual line . We
* have also added 1 per line for the "\n" character .
* /
var prev _line _chars = 0 ;
var loop _index = selected _line _no > 0 ? selected _line _no : 0 ;
for ( var i = loop _index ; i < error _line _no ; i ++ )
prev _line _chars += self . gridView . query _tool _obj . getLine ( i ) . length + 1 ;
/ * M a r k e r s t a r t i n g p o i n t f o r t h e i n d i v i d u a l l i n e i s
* equal to error character index minus total no of
* character till the error line starts .
* /
start _marker = error _char _no - prev _line _chars ;
// Find the next space from the character or end of line
var error _line = self . gridView . query _tool _obj . getLine ( error _line _no ) ;
2021-01-20 02:22:00 -06:00
if ( _ . isUndefined ( error _line ) ) return ;
2017-08-21 09:27:29 -05:00
end _marker = error _line . indexOf ( ' ' , start _marker ) ;
if ( end _marker < 0 )
end _marker = error _line . length ;
// Mark the error text
2018-01-12 01:29:51 -06:00
self . gridView . marker = self . gridView . query _tool _obj . markText ( {
line : error _line _no ,
ch : start _marker ,
} , {
line : error _line _no ,
ch : end _marker ,
} , {
className : 'sql-editor-mark' ,
} ) ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
self . gridView . query _tool _obj . addLineClass ( self . marked _line _no , 'wrap' , 'CodeMirror-activeline-background' ) ;
}
} ,
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// This function will cancel the running query.
2018-01-12 01:29:51 -06:00
_cancel _query : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
$ . ajax ( {
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.cancel_transaction' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
if ( ! res . data . status ) {
alertify . alert ( gettext ( 'Cancel Query Error' ) , res . data . result ) ;
}
self . disable _tool _buttons ( false ) ;
is _query _running = false ;
2020-12-14 00:28:53 -06:00
if ( ! _ . isUndefined ( self . download _results _obj ) ) {
self . download _results _obj . abort ( ) ;
2019-03-14 10:11:16 -05:00
$ ( '#btn-flash' ) . prop ( 'disabled' , false ) ;
self . trigger (
'pgadmin-sqleditor:loading-icon:hide' ) ;
}
setTimeout ( ( ) => { self . gridView . query _tool _obj . focus ( ) ; } , 200 ) ;
} )
. fail ( function ( e ) {
self . disable _tool _buttons ( false ) ;
2016-07-18 09:29:09 -05:00
2019-03-14 10:11:16 -05:00
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , '_cancel_query' , [ ] , false
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . alert ( gettext ( 'Cancel Query Error' ) , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// Trigger query result download to csv.
2020-12-14 00:28:53 -06:00
trigger _csv _download : function ( filename ) {
2017-08-21 09:27:29 -05:00
var self = this ,
2018-01-12 01:29:51 -06:00
url = url _for ( 'sqleditor.query_tool_download' , {
'trans_id' : self . transId ,
2019-02-27 11:08:53 -06:00
} ) ,
2020-12-14 00:28:53 -06:00
data = { filename : filename } ;
2019-02-20 05:49:45 -06:00
2019-03-29 09:31:33 -05:00
// Disable the Execute button
$ ( '#btn-flash' ) . prop ( 'disabled' , true ) ;
2020-12-14 00:28:53 -06:00
self . enable _disable _download _btn ( true ) ;
2019-03-29 09:31:33 -05:00
self . disable _tool _buttons ( true ) ;
self . set _sql _message ( '' ) ;
self . trigger (
'pgadmin-sqleditor:loading-icon:show' ,
2020-12-14 00:28:53 -06:00
gettext ( 'Downloading Results...' )
2019-03-29 09:31:33 -05:00
) ;
2019-02-20 05:49:45 -06:00
// Get the CSV file
2020-12-14 00:28:53 -06:00
self . download _results _obj = $ . ajax ( {
2019-02-27 11:08:53 -06:00
type : 'POST' ,
2019-02-20 05:49:45 -06:00
url : url ,
2019-02-27 11:08:53 -06:00
data : data ,
2019-02-20 05:49:45 -06:00
cache : false ,
2019-03-29 09:31:33 -05:00
} ) . done ( function ( response ) {
// if response.data present, extract the message
if ( ! _ . isUndefined ( response . data ) ) {
if ( ! response . status ) {
self . _highlight _error ( response . data . result ) ;
self . set _sql _message ( response . data . result ) ;
}
} else {
let respBlob = new Blob ( [ response ] , { type : 'text/csv' } ) ,
urlCreator = window . URL || window . webkitURL ,
2020-07-09 08:14:58 -05:00
download _url = urlCreator . createObjectURL ( respBlob ) ,
2019-03-14 10:11:16 -05:00
current _browser = pgAdmin . Browser . get _browser ( ) ,
link = document . createElement ( 'a' ) ;
2019-03-12 07:45:25 -05:00
2019-03-14 10:11:16 -05:00
document . body . appendChild ( link ) ;
2019-02-20 05:49:45 -06:00
2019-03-14 10:11:16 -05:00
if ( current _browser . name === 'IE' && window . navigator . msSaveBlob ) {
2019-03-01 07:32:40 -06:00
// IE10+ : (has Blob, but not a[download] or URL)
2019-03-29 09:31:33 -05:00
window . navigator . msSaveBlob ( respBlob , filename ) ;
2019-03-14 10:11:16 -05:00
} else {
2020-07-09 08:14:58 -05:00
link . setAttribute ( 'href' , download _url ) ;
2019-03-14 10:11:16 -05:00
link . setAttribute ( 'download' , filename ) ;
link . click ( ) ;
}
2019-02-20 05:49:45 -06:00
2019-03-14 10:11:16 -05:00
document . body . removeChild ( link ) ;
2020-12-14 00:28:53 -06:00
self . download _results _obj = undefined ;
2019-03-29 09:31:33 -05:00
}
2019-02-20 05:49:45 -06:00
2019-03-29 09:31:33 -05:00
// Enable the execute button
$ ( '#btn-flash' ) . prop ( 'disabled' , false ) ;
2020-12-14 00:28:53 -06:00
self . enable _disable _download _btn ( false ) ;
2019-03-29 09:31:33 -05:00
self . disable _tool _buttons ( false ) ;
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
} ) . fail ( function ( err ) {
let msg = '' ;
// Enable the execute button
$ ( '#btn-flash' ) . prop ( 'disabled' , false ) ;
2020-12-14 00:28:53 -06:00
self . enable _disable _download _btn ( false ) ;
2019-03-29 09:31:33 -05:00
self . disable _tool _buttons ( false ) ;
self . trigger ( 'pgadmin-sqleditor:loading-icon:hide' ) ;
2019-02-20 05:49:45 -06:00
2019-03-29 09:31:33 -05:00
if ( err . statusText == 'abort' ) {
msg = gettext ( 'CSV Download cancelled.' ) ;
} else {
msg = httpErrorHandler . handleQueryToolAjaxError (
2020-04-15 06:16:03 -05:00
pgAdmin , self , err , 'trigger_csv_download' , [ ] , true
2019-03-29 09:31:33 -05:00
) ;
}
2020-04-15 06:16:03 -05:00
// Check if error message is present
if ( msg )
alertify . alert ( gettext ( 'Download CSV error' ) , msg ) ;
2019-03-29 09:31:33 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-04-14 09:04:03 -05:00
2018-07-05 05:38:43 -05:00
call _cache _preferences : function ( ) {
2019-09-23 02:25:02 -05:00
let browser = pgWindow . default . pgAdmin . Browser ;
2018-07-05 05:38:43 -05:00
browser . cache _preferences ( 'sqleditor' ) ;
/* This will make sure to get latest updates only and not older events */
pgBrowser . preference _version ( pgBrowser . generate _preference _version ( ) ) ;
} ,
2018-01-12 01:29:51 -06:00
_auto _rollback : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ,
auto _rollback = true ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
if ( $ ( '.auto-rollback' ) . hasClass ( 'visibility-hidden' ) === true )
$ ( '.auto-rollback' ) . removeClass ( 'visibility-hidden' ) ;
else {
$ ( '.auto-rollback' ) . addClass ( 'visibility-hidden' ) ;
auto _rollback = false ;
}
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
// Make ajax call to change the limit
$ . ajax ( {
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.auto_rollback' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2017-08-21 09:27:29 -05:00
data : JSON . stringify ( auto _rollback ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
if ( ! res . data . status )
alertify . alert ( gettext ( 'Auto Rollback Error' ) , res . data . result ) ;
} )
. fail ( function ( e ) {
2016-04-14 09:04:03 -05:00
2019-03-14 10:11:16 -05:00
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , '_auto_rollback' , [ ] , true
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . alert ( gettext ( 'Auto Rollback Error' ) , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-04-14 09:04:03 -05:00
2018-01-12 01:29:51 -06:00
_auto _commit : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ,
auto _commit = true ;
2016-04-14 09:04:03 -05:00
2017-08-21 09:27:29 -05:00
if ( $ ( '.auto-commit' ) . hasClass ( 'visibility-hidden' ) === true )
$ ( '.auto-commit' ) . removeClass ( 'visibility-hidden' ) ;
else {
$ ( '.auto-commit' ) . addClass ( 'visibility-hidden' ) ;
auto _commit = false ;
}
2016-04-14 09:04:03 -05:00
2018-02-01 07:29:18 -06:00
// Make ajax call to toggle auto commit
2017-08-21 09:27:29 -05:00
$ . ajax ( {
2018-01-12 01:29:51 -06:00
url : url _for ( 'sqleditor.auto_commit' , {
'trans_id' : self . transId ,
} ) ,
2017-08-21 09:27:29 -05:00
method : 'POST' ,
2018-01-12 01:29:51 -06:00
contentType : 'application/json' ,
2017-08-21 09:27:29 -05:00
data : JSON . stringify ( auto _commit ) ,
2018-07-09 07:54:00 -05:00
} )
2019-03-14 10:11:16 -05:00
. done ( function ( res ) {
if ( ! res . data . status )
alertify . alert ( gettext ( 'Auto Commit Error' ) , res . data . result ) ;
} )
. fail ( function ( e ) {
let msg = httpErrorHandler . handleQueryToolAjaxError (
pgAdmin , self , e , '_auto_commit' , [ ] , true
) ;
2020-04-15 06:16:03 -05:00
if ( msg )
alertify . alert ( gettext ( 'Auto Commit Error' ) , msg ) ;
2019-03-14 10:11:16 -05:00
} ) ;
2016-05-17 02:01:39 -05:00
2018-07-05 05:38:43 -05:00
} ,
2017-08-21 09:27:29 -05:00
2019-07-03 07:57:56 -05:00
_toggle _explain _option : function ( type ) {
let selector = ` .explain- ${ type } ` ;
$ ( selector ) . toggleClass ( 'visibility-hidden' ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-05-15 14:37:52 -05:00
2018-07-05 05:38:43 -05:00
// This function will toggle "verbose" option in explain
_explain _verbose : function ( ) {
2019-07-03 07:57:56 -05:00
this . _toggle _explain _option ( 'verbose' ) ;
2018-07-05 05:38:43 -05:00
} ,
2017-08-21 09:27:29 -05:00
// This function will toggle "costs" option in explain
2018-01-12 01:29:51 -06:00
_explain _costs : function ( ) {
2019-07-03 07:57:56 -05:00
this . _toggle _explain _option ( 'costs' ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-05-15 14:37:52 -05:00
2017-08-21 09:27:29 -05:00
// This function will toggle "buffers" option in explain
2018-01-12 01:29:51 -06:00
_explain _buffers : function ( ) {
2019-07-03 07:57:56 -05:00
this . _toggle _explain _option ( 'buffers' ) ;
2017-08-21 09:27:29 -05:00
} ,
2016-05-17 02:01:39 -05:00
2017-08-21 09:27:29 -05:00
// This function will toggle "timing" option in explain
2018-01-12 01:29:51 -06:00
_explain _timing : function ( ) {
2019-07-03 07:57:56 -05:00
this . _toggle _explain _option ( 'timing' ) ;
} ,
2017-08-21 09:27:29 -05:00
2019-07-03 07:57:56 -05:00
_explain _summary : function ( ) {
this . _toggle _explain _option ( 'summary' ) ;
} ,
_explain _settings : function ( ) {
this . _toggle _explain _option ( 'settings' ) ;
2017-08-21 09:27:29 -05:00
} ,
2017-07-19 05:43:45 -05:00
2020-08-28 03:23:08 -05:00
_show _query _tool : function ( ) {
var self = this ;
2020-11-04 06:15:28 -06:00
var open _new _tab = self . browser _preferences . new _browser _tab _open ;
if ( open _new _tab && open _new _tab . includes ( 'qt' ) ) {
2020-09-10 01:39:56 -05:00
is _main _window _alive ( ) ;
}
2020-09-11 08:36:56 -05:00
this . _open _query _tool ( self ) ;
2020-09-10 01:39:56 -05:00
} ,
2020-08-28 03:23:08 -05:00
2020-09-11 08:36:56 -05:00
_open _query _tool : function ( that ) {
2020-09-10 01:39:56 -05:00
const transId = pgadminUtils . getRandomInt ( 1 , 9999999 ) ;
2020-09-11 08:36:56 -05:00
let url _endpoint = url _for ( 'datagrid.panel' , {
'trans_id' : transId ,
} ) ;
2020-09-14 07:12:59 -05:00
url _endpoint += ` ?is_query_tool= ${ true } `
2020-09-11 08:36:56 -05:00
+ ` &sgid= ${ that . url _params . sgid } `
+ ` &sid= ${ that . url _params . sid } `
2020-09-14 07:12:59 -05:00
+ ` &server_type= ${ that . url _params . server _type } ` ;
2020-09-11 08:36:56 -05:00
2020-09-14 07:12:59 -05:00
if ( that . url _params . did ) {
url _endpoint += ` &did= ${ that . url _params . did } ` ;
}
let panel _title = that . url _params . title ;
if ( that . url _params . is _query _tool == 'false' ) { //check whether query tool is hit from View/Edit
var split _title = that . url _params . title . split ( '/' ) ;
if ( split _title . length > 2 ) {
panel _title = split _title [ split _title . length - 2 ] + '/' + split _title [ split _title . length - 1 ] ;
}
}
launchDataGrid ( pgWindow . default . pgAdmin . DataGrid , transId , url _endpoint , panel _title , '' , alertify ) ;
2020-08-28 03:23:08 -05:00
} ,
2017-08-21 09:27:29 -05:00
/ *
* This function will indent selected code
* /
2018-01-12 01:29:51 -06:00
_indent _selected _code : function ( ) {
var self = this ,
editor = self . gridView . query _tool _obj ;
editor . execCommand ( 'indentMore' ) ;
2017-08-21 09:27:29 -05:00
} ,
2017-07-19 05:43:45 -05:00
2017-08-21 09:27:29 -05:00
/ *
* This function will unindent selected code
* /
2018-01-12 01:29:51 -06:00
_unindent _selected _code : function ( ) {
var self = this ,
editor = self . gridView . query _tool _obj ;
editor . execCommand ( 'indentLess' ) ;
2017-08-21 09:27:29 -05:00
} ,
2017-07-20 16:22:25 -05:00
2020-08-20 02:35:00 -05:00
/ *
* This function will format the SQL
* /
_format _sql : function ( ) {
var self = this ,
editor = self . gridView . query _tool _obj ,
selection = true ,
sql = '' ;
sql = editor . getSelection ( ) ;
if ( sql == '' ) {
sql = editor . getValue ( ) ;
selection = false ;
}
$ . ajax ( {
url : url _for ( 'sql.format' ) ,
data : JSON . stringify ( { 'sql' : sql } ) ,
method : 'POST' ,
contentType : 'application/json' ,
dataType : 'json' ,
} )
. done ( function ( res ) {
if ( selection === true ) {
editor . replaceSelection ( res . data . sql , 'around' ) ;
} else {
editor . setValue ( res . data . sql ) ;
}
} )
. fail ( function ( ) {
/* failure should be ignored */
} ) ;
} ,
2020-09-28 04:56:45 -05:00
// This function will open the manage macro dialog
_manage _macros : function ( ) {
let self = this ;
/ * W h e n s e r v e r i s d i s c o n n e c t e d a n d c o n n e c t e d , c o n n e c t i o n i s l o s t ,
* To reconnect pass true
* /
MacroHandler . dialog ( self ) ;
} ,
// This function will open the manage macro dialog
_execute _macro : function ( ) {
queryToolActions . executeMacro ( this . handler ) ;
} ,
2018-01-12 01:29:51 -06:00
isQueryRunning : function ( ) {
2017-08-21 09:27:29 -05:00
return is _query _running ;
} ,
2016-05-17 04:08:44 -05:00
2018-02-09 05:54:42 -06:00
setIsQueryRunning : function ( value ) {
is _query _running = value ;
} ,
2019-07-17 05:45:20 -05:00
/ * C h e c k s i f t h e r e i s a n y u n s a v e d d a t a c h a n g e s , u n s a v e d c h a n g e s i n t h e q u e r y
or uncommitted transactions before closing a panel * /
check _needed _confirmations _before _closing _panel : function ( is _close _event _call = false ) {
var self = this , msg ;
/ *
is _close _event _call = true only when the function is called when the
close panel event is triggered , otherwise ( on recursive calls ) it is false
* /
if ( ! self . ignore _on _close || is _close _event _call )
self . ignore _on _close = {
unsaved _data : false ,
unsaved _query : false ,
} ;
var ignore _unsaved _data = self . ignore _on _close . unsaved _data ,
ignore _unsaved _query = self . ignore _on _close . unsaved _query ;
// If there is unsaved data changes in the grid
if ( ! ignore _unsaved _data && self . can _edit
&& self . preferences . prompt _save _data _changes &&
self . data _store &&
( _ . size ( self . data _store . added ) ||
_ . size ( self . data _store . updated ) ||
_ . size ( self . data _store . deleted ) ) ) {
msg = gettext ( 'The data has changed. Do you want to save changes?' ) ;
self . unsaved _changes _user _confirmation ( msg , true ) ;
} // If there is unsaved query changes in the query editor
else if ( ! ignore _unsaved _query && self . is _query _tool
&& self . is _query _changed
&& self . preferences . prompt _save _query _changes ) {
msg = gettext ( 'The text has changed. Do you want to save changes?' ) ;
self . unsaved _changes _user _confirmation ( msg , false ) ;
} // If a transaction is currently ongoing
else if ( self . preferences . prompt _commit _transaction
2019-11-25 21:34:41 -06:00
&& ( self . last _transaction _status === queryTxnStatus . TRANSACTION _STATUS _INTRANS
|| self . last _transaction _status === queryTxnStatus . TRANSACTION _STATUS _INERROR ) ) {
var is _commit _disabled = self . last _transaction _status == queryTxnStatus . TRANSACTION _STATUS _INERROR ;
2019-07-17 05:45:20 -05:00
self . uncommitted _transaction _user _confirmation ( is _commit _disabled ) ;
}
else {
// No other function should call close() except through this function
// in order to perform necessary checks
self . ignore _on _close = undefined ;
self . close ( ) ;
}
// Return false so that the panel does not close unless close()
// is called explicitly (when all needed prompts are issued).
return false ;
} ,
/* To prompt the user for uncommitted transaction */
uncommitted _transaction _user _confirmation : function ( is _commit _disabled = false ) {
var self = this ;
alertify . confirmCommit || alertify . dialog ( 'confirmCommit' , function ( ) {
return {
2020-07-09 08:14:58 -05:00
main : function ( title , message , is _commit _disabled _arg ) {
this . is _commit _disabled = is _commit _disabled _arg ;
2019-07-17 05:45:20 -05:00
this . setHeader ( title ) ;
this . setContent ( message ) ;
} ,
setup : function ( ) {
return {
buttons : [ {
text : gettext ( 'Cancel' ) ,
key : 27 , // ESC
invokeOnClose : true ,
className : 'btn btn-secondary fa fa-lg fa-times pg-alertify-button' ,
} , {
text : gettext ( 'Rollback' ) ,
className : 'btn btn-primary fa fa-lg pg-alertify-button' ,
} , {
text : gettext ( 'Commit' ) ,
className : 'btn btn-primary fa fa-lg pg-alertify-button' ,
} ] ,
focus : {
element : 0 ,
select : false ,
} ,
options : {
maximizable : false ,
resizable : false ,
} ,
} ;
} ,
prepare : function ( ) {
// Disable commit button if needed
if ( this . is _commit _disabled )
this . _ _internal . buttons [ 2 ] . element . disabled = true ;
else
this . _ _internal . buttons [ 2 ] . element . disabled = false ;
} ,
callback : function ( closeEvent ) {
switch ( closeEvent . index ) {
case 0 : // Cancel
//Do nothing.
break ;
case 1 : // Rollback
self . close _on _idle _transaction = true ;
queryToolActions . executeRollback ( self ) ;
break ;
case 2 : // Commit
self . close _on _idle _transaction = true ;
queryToolActions . executeCommit ( self ) ;
break ;
}
} ,
} ;
} ) ;
2020-04-10 04:22:41 -05:00
let msg = gettext ( 'The current transaction is not commited to the database. '
2019-07-17 05:45:20 -05:00
+ 'Do you want to commit or rollback the transaction?' ) ;
alertify . confirmCommit ( gettext ( 'Commit transaction?' ) , msg , is _commit _disabled ) ;
} ,
/* To prompt user for unsaved changes */
unsaved _changes _user _confirmation : function ( msg , is _unsaved _data ) {
// If there is anything to save then prompt user
var self = this ;
alertify . confirmSave || alertify . dialog ( 'confirmSave' , function ( ) {
return {
2020-07-09 08:14:58 -05:00
main : function ( title , message , is _unsaved _data _arg ) {
this . is _unsaved _data = is _unsaved _data _arg ;
2019-07-17 05:45:20 -05:00
this . setHeader ( title ) ;
this . setContent ( message ) ;
} ,
setup : function ( ) {
return {
buttons : [ {
text : gettext ( 'Cancel' ) ,
key : 27 , // ESC
invokeOnClose : true ,
className : 'btn btn-secondary fa fa-lg fa-times pg-alertify-button' ,
} , {
text : gettext ( 'Don\'t save' ) ,
2020-08-13 01:34:00 -05:00
className : 'btn btn-secondary fa fa-lg fa-trash-alt pg-alertify-button' ,
2019-07-17 05:45:20 -05:00
} , {
text : gettext ( 'Save' ) ,
className : 'btn btn-primary fa fa-lg fa-save pg-alertify-button' ,
} ] ,
focus : {
element : 0 ,
select : false ,
} ,
options : {
maximizable : false ,
resizable : false ,
} ,
} ;
} ,
callback : function ( closeEvent ) {
switch ( closeEvent . index ) {
case 0 : // Cancel
//Do nothing.
break ;
case 1 : // Don't Save
self . close _on _save = false ;
if ( this . is _unsaved _data )
self . ignore _on _close . unsaved _data = true ;
else
self . ignore _on _close . unsaved _query = true ;
// Go back to check for any other needed confirmations before closing
2020-05-28 06:09:26 -05:00
if ( ! self . check _needed _confirmations _before _closing _panel ( ) ) {
closeEvent . cancel = true ;
}
2019-07-17 05:45:20 -05:00
break ;
case 2 : //Save
self . close _on _save = true ;
if ( this . is _unsaved _data ) {
self . save _data ( ) ;
}
else {
self . _save _file ( ) ;
}
break ;
}
} ,
} ;
} ) ;
alertify . confirmSave ( gettext ( 'Save changes?' ) , msg , is _unsaved _data ) ;
} ,
2018-01-12 01:29:51 -06:00
close : function ( ) {
2017-08-21 09:27:29 -05:00
var self = this ;
2018-02-01 07:29:18 -06:00
2018-04-04 05:20:36 -05:00
pgBrowser . Events . off ( 'pgadmin:user:logged-in' , this . initTransaction ) ;
2019-09-23 02:25:02 -05:00
_ . each ( pgWindow . default . pgAdmin . Browser . docker . findPanels ( 'frm_datagrid' ) , function ( panel ) {
2017-08-21 09:27:29 -05:00
if ( panel . isVisible ( ) ) {
window . onbeforeunload = null ;
panel . off ( wcDocker . EVENT . CLOSING ) ;
// remove col_size object on panel close
if ( ! _ . isUndefined ( self . col _size ) ) {
delete self . col _size ;
2017-07-04 17:39:10 -05:00
}
2019-09-23 02:25:02 -05:00
pgWindow . default . pgAdmin . Browser . docker . removePanel ( panel ) ;
2017-08-21 09:27:29 -05:00
}
} ) ;
2018-01-12 01:29:51 -06:00
} ,
2018-05-30 20:58:28 -05:00
/ * T h i s f u n c t i o n i s u s e d t o r a i s e n o t i f y m e s s a g e s a n d u p d a t e
* the notification grid .
* /
update _notifications : function ( notifications ) {
queryToolNotifications . updateNotifications ( notifications ) ;
} ,
2018-01-12 01:29:51 -06:00
} ) ;
2017-08-21 09:27:29 -05:00
pgAdmin . SqlEditor = {
// This function is used to create and return the object of grid controller.
2018-01-12 01:29:51 -06:00
create : function ( container ) {
2017-08-21 09:27:29 -05:00
return new SqlEditorController ( container ) ;
} ,
jquery : $ ,
} ;
return pgAdmin . SqlEditor ;
} ) ;