-
-
Notifications
You must be signed in to change notification settings - Fork 281
Conversation
static/css/Preview.css
Outdated
@@ -17,6 +17,13 @@ th, td { | |||
overflow: auto; | |||
} | |||
|
|||
.scheduleButton { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this style rule should go into app/components/Settings/Preview/code-editor.css
Please, see some examples of Falcon's naming conventions in https://github.com/plotly/falcon-sql-client/blob/master/CODING_GUIDELINES.md . TODO
|
@@ -0,0 +1,14 @@ | |||
import {DIALECTS} from '../../../constants/constants.js'; | |||
|
|||
export function mapDialect(dialect) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate code: code-editor.jsx already defines this code.
Please, add the following untested code to app/constants/constants.js
:
export function getHighlightMode(dialect) {
if (!SQL_DIALECTS_USING_EDITOR.includes(dialect)) {
return 'text/plain';
}
return {
[DIALECTS.APACHE_SPARK]: 'text/x-sparksql',
[DIALECTS.MYSQL]: 'text/x-mysql',
[DIALECTS.SQLITE]: 'text/x-sqlite',
[DIALECTS.MARIADB]: 'text/x-mariadb',
[DIALECTS.ORACLE]: 'text/x-plsql',
[DIALECTS.POSTGRES]: 'text/x-pgsql',
[DIALECTS.REDSHIFT]: 'text/x-pgsql',
[DIALECTS.MSSQL]: 'text/x-mssql'
}[dialect] || 'text/x-sql';
}
And update the following files accordingly:
-
app/components/Settings/Preview/code-editor.jsx
-
app/components/Settings/Scheduler/createModal.jsx
-
app/components/Settings/Scheduler/updateModal.jsx
|
For this PR, please:
TO DISCUSS: This PR has convinced me that the Schedule panel, should be a subpanel under the Query panel:
|
app/actions/sessions.js
Outdated
connectionId | ||
} | ||
)).then((res) => { | ||
dispatch(createScheduledQueryAction(res)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is createScheduledQueryAction
necessary? It doesn't seem to be used anywhere else.
If not, let's just do:
dispatch({
type: 'CREATE_SCHEDULED_QUERY',
payload: res
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scratch the above comment. I'll come back to you about this.
When I first read the code, I found confusing and I missed the significance of having the following pairs of actions:
As the actions I've tested the change below and it works for me: diff --git a/app/actions/sessions.js b/app/actions/sessions.js
index 1c9738d..754da7d 100644
--- a/app/actions/sessions.js
+++ b/app/actions/sessions.js
@@ -9,10 +9,6 @@ export const mergeTabMap = createAction('MERGE_TAB_MAP');
export const setTab = createAction('SET_TAB');
export const setTable = createAction('SET_TABLE');
export const setIndex = createAction('SET_INDEX');
-export const setScheduledQueries = createAction('SET_SCHEDULED_QUERIES');
-export const createScheduledQueryAction = createAction('CREATE_SCHEDULED_QUERY');
-export const updateScheduledQueryAction = createAction('UPDATE_SCHEDULED_QUERY');
-export const deleteScheduledQueryAction = createAction('DELETE_SCHEDULED_QUERY');
export const mergeConnections = createAction('MERGE_CONNECTIONS');
export const updateConnection = createAction('UPDATE_CREDENTIAL');
export const deleteConnection = createAction('DELETE_CREDENTIAL');
@@ -148,7 +144,10 @@ export function getScheduledQueries() {
'GET',
'scheduledQueriesRequest'
)).then((json => {
- dispatch(setScheduledQueries(json));
+ dispatch({
+ type: 'SET_SCHEDULED_QUERIES',
+ payload: json
+ });
return json;
}));
};
@@ -171,8 +170,11 @@ export function createScheduledQuery(connectionId, payload = {}) {
connectionId
}
)).then((res) => {
- dispatch(createScheduledQueryAction(res));
- return res;
+ dispatch({
+ type: 'CREATE_SCHEDULED_QUERY',
+ payload: res
+ });
+ return res;
});
};
}
@@ -196,8 +198,11 @@ export function updateScheduledQuery(connectionId, payload = {}) {
payload.filename,
body
)).then((res) => {
- dispatch(updateScheduledQueryAction(body));
- return res;
+ dispatch({
+ type: 'UPDATE_SCHEDULED_QUERY',
+ payload: body
+ });
+ return res;
});
};
}
@@ -209,8 +214,11 @@ export function deleteScheduledQuery(fid) {
'DELETE',
'createScheduledQueryRequest'
)).then((res) => {
- dispatch(deleteScheduledQueryAction(fid));
- return res;
+ dispatch({
+ type: 'DELETE_SCHEDULED_QUERY',
+ payload: fid
+ });
+ return res;
});
};
} |
@@ -347,6 +348,7 @@ class Preview extends Component { | |||
|
|||
dialect={dialect} | |||
runQuery={this.runQuery} | |||
scheduleQuery={this.props.openScheduler} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to rename this property to openScheduler
? (this seems to be the name used elsewhere)
className="btn btn-outline" | ||
> | ||
Upload Dataset (auto-updating) | ||
</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this button as it doesn't do anything in this PR.
@@ -25,6 +25,7 @@ export default class CodeEditor extends React.Component { | |||
|
|||
dialect: PropTypes.string, | |||
runQuery: PropTypes.func, | |||
scheduleQuery: PropTypes.func, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see this comment
}; | ||
const boxStyle = { boxSizing: 'border-box', width: '50%' }; | ||
|
||
export class PreviewModal extends Component { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add description; e.g.: "implements a modal window to view details of a scheduled query"
onChange: PropTypes.func | ||
}; | ||
|
||
class CreateModal extends Component { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add description; e.g.: "implements a modal window to schedule a new query"
{ label: 'Run weekly', value: 7 * 24 * 60 * 60 } | ||
]; | ||
|
||
const styles = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a blocking change, but these styles should go into its own file, e.g. create-modal.css
; (having so many <xxxx style={styles.xxxx}>
is a maintenance burden).
import { Row, Column } from '../../layout.jsx'; | ||
import Modal from '../../modal.jsx'; | ||
|
||
const styles = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a blocking change, but these styles should go into its own file, e.g. login-modal.css
; (having so many <xxxx style={styles.xxxx}>
is a maintenance burden).
@tarzzz At the moment Falcon uses https://github.com/plotly/falcon-sql-client/blob/6797d9e9c1411a23d1cffc25ccfdd63a7f4e0431/backend/persistent/plotly-api.js#L97-L120 to create a new grid. How should we do so that this function doesn't require a filename? |
The best way to handle this is to hit the |
this.close = this.close.bind(this); | ||
} | ||
|
||
componentDidUpdate(prevProps) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use componentWillReceiveProps
instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you want to use componentWillReceiveProps
? That API is deprecated in react@^16.3.0
. No worries either way, just wanted to make sure you knew 😄
}); | ||
this.setState({ editing: false, confirmedDelete: false }); | ||
} else { | ||
this.toggleEditing(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit confusing to read because I have to remember what the current value of this.state.editing
is.
Since toggleEditting()
is only used here, please remove toggleEditing()
and use this.setState({editing: true});
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely (:
} | ||
} | ||
|
||
onDelete() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
neat!
} | ||
} | ||
|
||
close() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment, the modal window closes as soon as the user clicks a button. With this behaviour, users can't tell whether the request is still being processed or it has failed.
Ideally, we want to tell the user whether the request failed and if it did fail we don't want to close the modal window.
> | ||
{editing ? ( | ||
<div> | ||
<CodeMirror |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
expect(component.find(Modal).get(2).props.open).toBe(true); | ||
|
||
const modalSqlElements = component |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs updating (test failure here). see https://circleci.com/gh/plotly/falcon-sql-client/5113
I still need to review the changes to I'll do it tomorrow. I noticed there is a race that allows users to open the schedule panel first and then immediately after switch to the query panel before it's ready. |
updateScheduledQuery={updateScheduledQuery} | ||
deleteScheduledQuery={deleteScheduledQuery} | ||
initialCode={this.state.scheduledQuery} | ||
openLogin={this.updateSelectedPanel.bind(this, 3)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we define this.openLogin
(as was done with `this.openScheduler)?
} | ||
|
||
openScheduler() { | ||
this.setState({ scheduledQuery: this.props.preview.code }, () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how this code works. Why do we need to set scheduleQuery
before opening the panel and unset it immediately after?
Also note that the value of this.props.preview.code
isn't properly set before the connection has successfully connected to the database and retrieve the list of available tables.
When I reviewed the previous PR, I thought it was OK for the schedule panel to open before the Query panel is ready (because Falcon runs the scheduled queries even if the user isn't connected).
Now, I think it's easier if we stop the Scheduler panel from being open before the connection is ready.
How about having <Tab disabled={queryPanelDisabled}>Schedule</Tab>
here?
let CreateModal; | ||
beforeAll(() => { | ||
configure({ adapter: new Adapter() }); | ||
global.document.createRange = function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the tests we already have, polyfills and imports are run in the global context.
See:
https://github.com/jakedex/falcon-sql-client/blob/498420c042490870b6669819ddfb8a1047cd2627/test/app/components/Settings/Preview/chart-editor.test.jsx#L5-L11
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. I moved it to the global context, but if I'm not mistaken, you all don't already have polyfills for document.createRange
so I'll keep the one I wrote 👍
@n-riesco for connection dialects that don't use the query panel editor, is it still meaningful to display a query input within the create scheduled query modal? How are scheduled queries currently handled for dialects which are not contained in SQL_DIALECTS_USING_EDITOR? |
Re the filename I would love it if the user could specify a filename and if the API doesn't like it that we bubble that error through. If the API currently doesn't return an informative message, let's change that on the API side to enable this feature /cc @tarzzz FYI |
I also think we should ask for and store a Query Name, independent of the filename |
Yep, It's already covered in API .. ⬇️
|
@nicolaskruchten I currently have this implemented, but maybe since we are adding "Query Name"/"Query Title" we can just uncomment it and enable this with Stage 3? |
yes, it is possible to have scheduled queries for those connectors too.
Same as for other connectors (it already works with your PR) |
<a | ||
className="btn btn-primary runButton" | ||
onClick={runQuery} | ||
disabled={!isLoading} | ||
disabled={isLoading} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch!
error: 'Please enter the query to be scheduled above.' | ||
}); | ||
} | ||
// if (!this.state.filename || !this.state.filename.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, ignore this comment for now. The second condition isn't necessary, if (!this.state.code)
is enough, because an empty string is converted to false.
onClickAway={this.closePreview} | ||
query={this.state.selectedQuery} | ||
onSave={this.handleUpdate} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just noticed while testing. We need to disable onSave
and onDelete
when !loggedIn
.
} | ||
}; | ||
}; | ||
const CreateModal = require('../../../../../app/components/Settings/scheduler/create-modal.jsx').default; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not terribly familiar with jest
. Don't we need to use jest.unmock?
All the other tests use it; e.g. https://github.com/plotly/falcon-sql-client/blob/824b3920738f0f51d631aee2421aa9f1ae23135b/test/app/components/Settings/Preview/chart-editor.test.jsx#L10
Also, is there a reason for using require
instead of import
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need to use jest.unmock
in this test since we aren't mocking anything using jest.mock
. If anything I should just delete global.document.createRange
in the afterAll
hook.
Also the reason for require
instead of import
is because require
is run sequentially after global.document.createRange = function() {
and import
is hoisted to the top. Typically this doesn't matter either but CodeMirror has side-effects at the top level which is causing failures on import.
@mfix22 @briandennis the PR looks very good and ready to merge (after addressing the few minor comments I posted today). I'm aiming at merging tonight when I'm back. |
@mfix22 I've tested 508ca66 and it doesn't look good: How about hiding the buttons instead? Please, don't forget about the comment here. |
@n-riesco yes for sure! I was planning on doing it and then forgot. Just pushed the update. Thanks for catching that! 👍 |
I've tested the latest changes and it looks good to me. There is an issue that I can't reproduce reliably (sometimes I need to click a schedule twice to be able to open the PreviewModal). I'm merging so that we can progress to stage-3. |
Hey @n-riesco @nicolaskruchten 👋
Here is the Stage 2 PR for the Scheduled Queries projects.
Just FYI we still have more tests to write, but we are going to include those with Stage 3 to try and balance the front and backend work 👍 Hope that works.
Also FYI: we will be mostly offline tomorrow for the 4th of July, but probably will have time to make some quick fixes in the morning!