diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py
index 905e08550..d60859964 100644
--- a/web/pgadmin/feature_tests/query_tool_journey_test.py
+++ b/web/pgadmin/feature_tests/query_tool_journey_test.py
@@ -78,6 +78,10 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.page.click_tab("History")
selected_history_entry = self.page.find_by_css_selector("#query_list .selected")
self.assertIn("SELECT * FROM shoes", selected_history_entry.text)
+ failed_history_detail_pane = self.page.find_by_id("query_detail")
+
+ self.assertIn("Error Message relation \"shoes\" does not exist", failed_history_detail_pane.text)
+
ActionChains(self.page.driver) \
.send_keys(Keys.ARROW_DOWN) \
.perform()
diff --git a/web/pgadmin/static/jsx/history/detail/history_error_message.jsx b/web/pgadmin/static/jsx/history/detail/history_error_message.jsx
new file mode 100644
index 000000000..0b5e27bf1
--- /dev/null
+++ b/web/pgadmin/static/jsx/history/detail/history_error_message.jsx
@@ -0,0 +1,30 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2017, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////////////////
+
+import React from 'react';
+
+import Shapes from '../../react_shapes';
+
+export default class HistoryErrorMessage extends React.Component {
+
+ parseErrorMessage(message) {
+ return message.match(/ERROR:\s*([^\n\r]*)/i)[1];
+ }
+
+ render() {
+ return (
+
+ {historyErrorMessage}
diff --git a/web/pgadmin/static/scss/sqleditor/_history.scss b/web/pgadmin/static/scss/sqleditor/_history.scss
index c8255762b..ed0c10f77 100644
--- a/web/pgadmin/static/scss/sqleditor/_history.scss
+++ b/web/pgadmin/static/scss/sqleditor/_history.scss
@@ -11,7 +11,7 @@
border: 2px solid transparent;
margin-left: 1px;
- .other-info{
+ .other-info {
@extend .text-13;
@extend .font-gray-4;
font-family: monospace;
@@ -47,7 +47,7 @@
font-weight: bold;
border: 2px solid;
- .other-info{
+ .other-info {
@extend .font-primary-blue;
font-weight: bold;
}
@@ -62,19 +62,37 @@
.query-detail {
width: 100%;
- padding-top: 10px;
display: flex;
flex-direction: column;
+ .error-message-block {
+ @extend .bg-red-1;
+ flex: 0.3;
+ padding-left: 20px;
+
+ .history-error-text {
+ @extend .text-12;
+ padding: 7px 0;
+
+ span {
+ @extend .font-red-3;
+ font-weight: 500;
+ margin-right: 8px;
+ }
+ }
+ }
+
.metadata-block {
- flex: 1;
- padding: 0 10px;
+ flex: 0.4;
+ padding: 10px 20px;
.metadata {
display: flex;
+ flex-wrap: wrap;
.item {
flex: 1;
+ min-width: 130px;
.value {
@extend .text-14;
@@ -106,7 +124,7 @@
.message-block {
flex: 2;
display: flex;
- padding-left: 10px;
+ padding: 0 20px;
.message {
flex: 2 2 0%;
diff --git a/web/regression/javascript/history/query_history_spec.jsx b/web/regression/javascript/history/query_history_spec.jsx
index a60aeb1e9..2fa6a7db8 100644
--- a/web/regression/javascript/history/query_history_spec.jsx
+++ b/web/regression/javascript/history/query_history_spec.jsx
@@ -49,6 +49,7 @@ describe('QueryHistory', () => {
expect(foundChildren.length).toBe(0);
done();
});
+
it('nothing is displayed on right panel', (done) => {
let foundChildren = historyWrapper.find(QueryHistoryDetail);
expect(foundChildren.length).toBe(1);
@@ -68,7 +69,7 @@ describe('QueryHistory', () => {
status: true,
row_affected: 12345,
total_time: '14 msec',
- message: 'message from first sql query',
+ message: 'something important ERROR: message from first sql query',
}, {
query: 'second sql statement',
start_time: new Date(2016, 11, 11, 1, 33, 5, 99),
@@ -191,27 +192,41 @@ describe('QueryHistory', () => {
done();
}, 1000);
});
+
+ describe('when the query failed', () => {
+ let failedEntry;
+
+ beforeEach(() => {
+ failedEntry = foundChildren.at(1);
+ failedEntry.simulate('click');
+ });
+ it('displays the error message on top of the details pane', () => {
+ expect(queryDetail.at(0).text()).toContain('Error Message message from second sql query');
+ });
+ });
});
describe('when the older query is clicked on', () => {
+ let firstEntry, secondEntry;
+
beforeEach(() => {
- foundChildren.at(1).simulate('click');
+ firstEntry = foundChildren.at(0);
+ secondEntry = foundChildren.at(1);
+ secondEntry.simulate('click');
});
it('displays the query in the right pane', () => {
expect(queryDetail.at(0).text()).toContain('second sql statement');
});
- it('renders the most recent query as selected in the left pane', () => {
- expect(foundChildren.at(0).nodes.length).toBe(1);
- expect(foundChildren.at(0).hasClass('selected')).toBeFalsy();
- expect(foundChildren.at(0).hasClass('error')).toBeFalsy();
+ it('deselects the first history entry', () => {
+ expect(firstEntry.nodes.length).toBe(1);
+ expect(firstEntry.hasClass('selected')).toBeFalsy();
});
- it('renders the older query as selected in the left pane', () => {
- expect(foundChildren.at(1).nodes.length).toBe(1);
- expect(foundChildren.at(1).hasClass('selected')).toBeTruthy();
- expect(foundChildren.at(1).hasClass('error')).toBeTruthy();
+ it('selects the second history entry', () => {
+ expect(secondEntry.nodes.length).toBe(1);
+ expect(secondEntry.hasClass('selected')).toBeTruthy();
});
});
@@ -223,7 +238,7 @@ describe('QueryHistory', () => {
status: false,
row_affected: 5,
total_time: '26 msec',
- message: 'third sql message',
+ message: 'pretext ERROR: third sql message',
});
foundChildren = historyWrapper.find(QueryHistoryEntry);