Remove the large and unnecessary dependency on React and 87 other related libraries. Fixes #4018

This commit is contained in:
Aditya Toshniwal
2019-03-07 10:51:59 +00:00
committed by Dave Page
parent d7bf6ec69f
commit 4b895941b3
31 changed files with 792 additions and 3465 deletions

View File

@@ -10,8 +10,8 @@
export default class HistoryCollection {
constructor(history_model) {
this.historyList = history_model;
this.onChange(() => {});
this.historyList = _.sortBy(history_model, o=>o.start_time);
this.onAdd(() => {});
}
length() {
@@ -19,8 +19,10 @@ export default class HistoryCollection {
}
add(object) {
this.historyList.push(object);
this.onChangeHandler(this.historyList);
/* add object in sorted order */
let pushAt = _.sortedIndex(this.historyList, object, o=>o.start_time);
this.historyList.splice(pushAt, 0, object);
this.onAddHandler(object);
}
reset() {
@@ -28,8 +30,8 @@ export default class HistoryCollection {
this.onResetHandler(this.historyList);
}
onChange(onChangeHandler) {
this.onChangeHandler = onChangeHandler;
onAdd(onAddHandler) {
this.onAddHandler = onAddHandler;
}
onReset(onResetHandler) {

View File

@@ -0,0 +1,81 @@
import QueryHistoryDetails from './query_history_details';
import { QueryHistoryEntries } from './query_history_entries';
import Split from 'split.js';
import gettext from 'sources/gettext';
import $ from 'jquery';
export default class QueryHistory {
constructor(parentNode, histModel) {
this.parentNode = parentNode;
this.histCollection = histModel;
this.editorPref = {};
this.histCollection.onAdd(this.onAddEntry.bind(this));
this.histCollection.onReset(this.onResetEntries.bind(this));
}
focus() {
if (this.queryHistEntries) {
this.queryHistEntries.focus();
}
}
onAddEntry(entry) {
if (this.histCollection.length() == 1) {
this.render();
} else if (this.queryHistEntries) {
this.queryHistEntries.addEntry(entry);
}
}
onResetEntries() {
this.isRendered = false;
this.queryHistEntries = null;
this.queryHistDetails = null;
this.render();
}
setEditorPref(editorPref) {
this.editorPref = editorPref;
if(this.queryHistDetails) {
this.queryHistDetails.setEditorPref(this.editorPref);
}
}
render() {
if (this.histCollection.length() == 0) {
this.parentNode.empty()
.removeClass('d-flex')
.append(
`<div class='alert alert-info pg-panel-message'>${gettext(
'No history found'
)}</div>`
);
} else {
this.parentNode.empty().addClass('d-flex');
let $histEntries = $('<div><div>').appendTo(this.parentNode);
let $histDetails = $('<div><div>').appendTo(this.parentNode);
Split([$histEntries[0], $histDetails[0]], {
gutterSize: 1,
cursor: 'ew-resize',
});
this.queryHistDetails = new QueryHistoryDetails($histDetails);
this.queryHistDetails.setEditorPref(this.editorPref);
this.queryHistDetails.render();
this.queryHistEntries = new QueryHistoryEntries($histEntries);
this.queryHistEntries.onSelectedChange(
(entry => {
this.queryHistDetails.setEntry(entry);
}).bind(this)
);
this.queryHistEntries.render();
this.histCollection.historyList.map((entry)=>{
this.queryHistEntries.addEntry(entry);
});
}
}
}

View File

@@ -0,0 +1,177 @@
import CodeMirror from 'bundled_codemirror';
import clipboard from 'sources/selection/clipboard';
import moment from 'moment';
import $ from 'jquery';
export default class QueryHistoryDetails {
constructor(parentNode) {
this.parentNode = parentNode;
this.isCopied = false;
this.timeout = null;
this.isRendered = false;
this.sqlFontSize = null;
this.editorPref = {
'sql_font_size': '1em',
};
}
setEntry(entry) {
this.entry = entry;
if (this.isRendered) {
this.selectiveRender();
} else {
this.render();
}
}
setEditorPref(editorPref={}) {
this.editorPref = {
...this.editorPref,
...editorPref,
};
if(this.query_codemirror) {
$(this.query_codemirror.getWrapperElement()).css(
'font-size',this.editorPref.sql_font_size
);
this.query_codemirror.refresh();
}
}
parseErrorMessage(message) {
return message.match(/ERROR:\s*([^\n\r]*)/i)
? message.match(/ERROR:\s*([^\n\r]*)/i)[1]
: message;
}
formatDate(date) {
return moment(date).format('M-D-YY HH:mm:ss');
}
copyAllHandler() {
clipboard.copyTextToClipboard(this.entry.query);
this.clearPreviousTimeout();
this.updateCopyButton(true);
this.timeout = setTimeout(() => {
this.updateCopyButton(false);
}, 1500);
}
clearPreviousTimeout() {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
}
updateCopyButton(copied) {
if (copied) {
this.$copyBtn.attr('class', 'was-copied');
this.$copyBtn.text('Copied!');
} else {
this.$copyBtn.attr('class', 'copy-all');
this.$copyBtn.text('Copy All');
}
}
updateQueryMetaData() {
let itemTemplate = (data, description) => {
return `<div class='item'>
<span class='value'>${data}</span>
<span class='description'>${description}</span>
</div>`;
};
this.$metaData.empty().append(
`<div class='metadata'>
${itemTemplate(this.formatDate(this.entry.start_time), 'Date')}
${itemTemplate(
this.entry.row_affected.toLocaleString(),
'Rows Affected'
)}
${itemTemplate(this.entry.total_time, 'Duration')}
</div>`
);
}
updateMessageContent() {
this.$message_content
.empty()
.append(`<pre class='content-value'>${this.entry.message}</pre>`);
}
updateErrorMessage() {
if (!this.entry.status) {
this.$errMsgBlock.removeClass('d-none');
this.$errMsgBlock.empty().append(
`<div class='history-error-text'>
<span>Error Message</span> ${this.parseErrorMessage(
this.entry.message
)}
</div>`
);
} else {
this.$errMsgBlock.addClass('d-none');
this.$errMsgBlock.empty();
}
}
selectiveRender() {
this.updateErrorMessage();
this.updateCopyButton(false);
this.updateQueryMetaData();
this.query_codemirror.setValue(this.entry.query);
this.updateMessageContent();
}
render() {
if (this.entry) {
this.parentNode.empty().append(
`<div id='query_detail' class='query-detail'>
<div class='error-message-block'></div>
<div class='metadata-block'></div>
<div class='query-statement-block'>
<div id='history-detail-query'>
<button class='' tabindex=0 accesskey='y'></button>
<div></div>
</div>
</div>
<div>
<hr class='block-divider'/>
</div>
<div class='message-block'>
<div class='message'>
<div class='message-header'>Messages</div>
<div class='content'></div>
</div>
</div>
</div>`
);
this.$errMsgBlock = this.parentNode.find('.error-message-block');
this.$copyBtn = this.parentNode.find('#history-detail-query button');
this.$copyBtn.off('click').on('click', this.copyAllHandler.bind(this));
this.$metaData = this.parentNode.find('.metadata-block');
this.query_codemirror = CodeMirror(
this.parentNode.find('#history-detail-query div')[0],
{
tabindex: -1,
mode: 'text/x-pgsql',
readOnly: true,
}
);
$(this.query_codemirror.getWrapperElement()).css(
'font-size',this.editorPref.sql_font_size
);
this.$message_content = this.parentNode.find('.message-block .content');
this.isRendered = true;
this.selectiveRender();
}
}
}

View File

@@ -0,0 +1,230 @@
import moment from 'moment';
import $ from 'jquery';
const ARROWUP = 38;
const ARROWDOWN = 40;
export class QueryHistoryEntryDateGroup {
constructor(date, groupKey) {
this.date = date;
this.formatString = 'MMM DD YYYY';
this.groupKey = groupKey;
}
getDatePrefix() {
let prefix = '';
if (this.isDaysBefore(0)) {
prefix = 'Today - ';
} else if (this.isDaysBefore(1)) {
prefix = 'Yesterday - ';
}
return prefix;
}
getDateFormatted(momentToFormat) {
return momentToFormat.format(this.formatString);
}
getDateMoment() {
return moment(this.date);
}
isDaysBefore(before) {
return (
this.getDateFormatted(this.getDateMoment()) ===
this.getDateFormatted(moment().subtract(before, 'days'))
);
}
render() {
return $(`<div class='query-group' data-key='${this.groupKey}'>
<div class='date-label'>${this.getDatePrefix()}${this.getDateFormatted(
this.getDateMoment()
)}</div>
<ul class='query-entries'></ul>
</div>`);
}
}
export class QueryHistoryItem {
constructor(entry) {
this.entry = entry;
this.$el = null;
this.onClickHandler = null;
}
onClick(onClickHandler) {
this.onClickHandler = onClickHandler;
if (this.$el) {
this.$el.off('click').on('click', e => {
this.onClickHandler($(e.currentTarget));
});
}
}
formatDate(date) {
return moment(date).format('HH:mm:ss');
}
render() {
this.$el = $(
`<li class='list-item' tabindex='0' data-key='${this.formatDate(this.entry.start_time)}'>
<div class='entry ${this.entry.status ? '' : 'error'}'>
<div class='query'>${this.entry.query}</div>
<div class='other-info'>
<div class='timestamp'>${this.formatDate(this.entry.start_time)}</div>
</div>
</div>
</li>`
)
.data('entrydata', this.entry)
.on('click', e => {
this.onClickHandler($(e.currentTarget));
});
}
}
export class QueryHistoryEntries {
constructor(parentNode) {
this.parentNode = parentNode;
this.$selectedItem = null;
this.groupKeyFormat = 'YYYY MM DD';
this.$el = null;
}
onSelectedChange(onSelectedChangeHandler) {
this.onSelectedChangeHandler = onSelectedChangeHandler;
}
focus() {
let self = this;
if (!this.$selectedItem) {
this.setSelectedListItem(this.$el.find('.list-item').first());
}
setTimeout(() => {
self.$selectedItem.trigger('click');
}, 500);
}
isArrowDown(event) {
return (event.keyCode || event.which) === ARROWDOWN;
}
isArrowUp(event) {
return (event.keyCode || event.which) === ARROWUP;
}
navigateUpAndDown(event) {
let arrowKeys = [ARROWUP, ARROWDOWN];
let key = event.keyCode || event.which;
if (arrowKeys.indexOf(key) > -1) {
event.preventDefault();
this.onKeyDownHandler(event);
return false;
}
return true;
}
onKeyDownHandler(event) {
if (this.isArrowDown(event)) {
if (this.$selectedItem.next().length > 0) {
this.setSelectedListItem(this.$selectedItem.next());
} else {
/* if last, jump to next group */
let $group = this.$selectedItem.closest('.query-group');
if ($group.next().length > 0) {
this.setSelectedListItem(
$group.next().find('.list-item').first()
);
}
}
} else if (this.isArrowUp(event)) {
if (this.$selectedItem.prev().length > 0) {
this.setSelectedListItem(this.$selectedItem.prev());
} else {
/* if first, jump to prev group */
let $group = this.$selectedItem.closest('.query-group');
if ($group.prev().length > 0) {
this.setSelectedListItem(
$group.prev().find('.list-item').last()
);
}
}
}
}
onSelectListItem(event) {
this.setSelectedListItem($(event.currentTarget));
}
dateAsGroupKey(date) {
return moment(date).format(this.groupKeyFormat);
}
setSelectedListItem($listItem) {
if (this.$selectedItem) {
this.$selectedItem.removeClass('selected');
}
$listItem.addClass('selected');
this.$selectedItem = $listItem;
this.$selectedItem[0].scrollIntoView(false);
if (this.onSelectedChangeHandler) {
this.onSelectedChangeHandler(this.$selectedItem.data('entrydata'));
}
}
addEntry(entry) {
/* Add the entry in respective date group in descending sorted order. */
let groups = this.$el.find('.query-group');
let groupsKeys = $.map(groups, group => {
return $(group).attr('data-key');
});
let entryGroupKey = this.dateAsGroupKey(entry.start_time);
let groupIdx = _.indexOf(groupsKeys, entryGroupKey);
let $groupEl = null;
/* if no groups present */
if (groups.length == 0) {
$groupEl = new QueryHistoryEntryDateGroup(
entry.start_time,
entryGroupKey
).render();
this.$el.prepend($groupEl);
} else if (groupIdx < 0 && groups.length != 0) {
/* if groups are present, but this is a new group */
$groupEl = new QueryHistoryEntryDateGroup(
entry.start_time,
entryGroupKey
).render();
if (groups[groupIdx]) {
$groupEl.insertBefore(groups[groupIdx]);
} else {
this.$el.prepend($groupEl);
}
} else if (groupIdx >= 0) {
/* if groups present, but this is a new one */
$groupEl = $(groups[groupIdx]);
}
let newItem = new QueryHistoryItem(entry);
newItem.onClick(this.setSelectedListItem.bind(this));
newItem.render();
$groupEl.find('.query-entries').prepend(newItem.$el);
this.setSelectedListItem(newItem.$el);
}
render() {
let self = this;
self.$el = $(`
<div id='query_list' class='query-history' tabindex='0'>
</div>
`).on('keydown', this.navigateUpAndDown.bind(this));
self.parentNode.empty().append(self.$el);
}
}

View File

@@ -173,7 +173,9 @@ function updateUIPreferences(sqlEditor) {
sqlEditor.query_tool_obj.refresh();
/* Render history to reflect Font size change */
sqlEditor.render_history_grid();
sqlEditor.historyComponent.setEditorPref({
'sql_font_size' : sql_font_size,
});
}
export {updateUIPreferences};