Skip to content
Snippets Groups Projects
Commit 2fe50f29 authored by Allen Gilliland's avatar Allen Gilliland
Browse files

update QueryHeader component to lay out inclusions for all the new things that...

update QueryHeader component to lay out inclusions for all the new things that will be handled there (add to dashboard, saver, download data, sql mode toggle)
parent d11dfcdf
No related branches found
No related tags found
No related merge requests found
......@@ -333,7 +333,11 @@ CardControllers.controller('CardDetail', [
}
},
getDownloadLink: function() {
return '/api/meta/dataset/csv/?query=' + encodeURIComponent(JSON.stringify(queryBuilder.card.dataset_query));
// TODO: this should be conditional and only return a valid url if we have valid
// data to be downloaded. otherwise return something falsey
if (queryBuilder.result) {
return '/api/meta/dataset/csv/?query=' + encodeURIComponent(JSON.stringify(queryBuilder.card.dataset_query));
}
},
cleanFilters: function(dataset_query) {
// TODO: 'native' query support
......@@ -386,6 +390,9 @@ CardControllers.controller('CardDetail', [
};
};
var isDirty = function() {
return false;
};
$scope.$watch('currentOrg', function (org) {
// we need org always, so we just won't do anything if we don't have one
......@@ -398,6 +405,7 @@ CardControllers.controller('CardDetail', [
Card.get({
'cardId': $routeParams.cardId
}, function(result) {
result.isDirty = isDirty;
console.log('result', result);
queryBuilder.extractQuery(result);
queryBuilder.getDatabaseList();
......@@ -482,7 +490,8 @@ CardControllers.controller('CardDetail', [
breakout: [],
filter: []
}
}
},
isDirty: isDirty
};
}
}); // end watch
......
'use strict';
/*global cx, OnClickOutside, SelectionModule*/
var AddToDashboard = React.createClass({
displayName: 'AddToDashboard',
propTypes: {
// description: React.PropTypes.string,
// hasChanged: React.PropTypes.bool,
// name: React.PropTypes.string,
// permissions: React.PropTypes.number,
// setPermissions: React.PropTypes.func.isRequired,
// save: React.PropTypes.func.isRequired
},
mixins: [OnClickOutside],
getInitialState: function () {
return {
modalOpen: false,
triggerAction: this._openModal
};
},
handleClickOutside: function () {
this.replaceState(this.getInitialState());
},
_openModal: function () {
this.setState({
modalOpen: true,
triggerAction: this._save
}, function () {
// focus the name field
this.refs.name.getDOMNode().focus();
});
},
// _save: function () {
// var name = this.refs.name.getDOMNode().value,
// description = this.refs.description.getDOMNode().value;
// this.props.save({
// name: name,
// description: description
// });
// // reset the modal
// this.setState({
// modalOpen: false,
// triggerAction: this._openModal
// });
// },
render: function () {
return (
<button className="Button Button--primary float-right">Add to Dash</button>
);
}
});
......@@ -2,16 +2,60 @@
var PureRenderMixin = React.addons.PureRenderMixin;
// Title - saved card title, otherwise static default
// Edit - only shown after Save
// Save - only shown after Run
// Download Data - only shown after Run
// Add to Dashboard - only shown after Save
// GUI vs SQL mode toggle - 2 mode slider
var QueryHeader = React.createClass({
displayName: 'QueryHeader',
propTypes: {
name: React.PropTypes.string
card: React.PropTypes.object.isRequired,
save: React.PropTypes.func.isRequired,
downloadLink: React.PropTypes.string
// :: Add To Dashboard
// :: Query Mode Toggle
// allow native queries (available types list?)
// setType() function
},
mixins: [PureRenderMixin],
render: function () {
var name = this.props.name || "What would you like to know?";
var title = this.props.card.name || "What would you like to know?",
editButton,
downloadButton,
buttonGroup;
// NOTE: we expect our component provider provided something falsey if now download available
if (this.props.downloadLink) {
downloadButton = (
<a className="Button inline-block mr1" href={this.props.downloadLink} target="_blank">Download data</a>
);
}
// we consider a card to be already saved if it has an id
if (this.props.card.id !== undefined) {
editButton = (
<button className="Button float-right">Edit</button>
);
}
return (
<h1 className="QueryName">{name}</h1>
<div class="clearfix">
<h1 className="QueryName">{title}</h1>
{editButton}
<Saver
card={this.props.card}
hasChanged={false}
save={this.props.save.bind(this.props.model)}
/>
{downloadButton}
<AddToDashboard />
<QueryModeToggle />
</div>
);
}
});
......@@ -114,20 +114,8 @@ var QueryBuilder = React.createClass({
'QueryPicker-group': true
});
var saver,
result,
download;
var result;
if(this.props.model.result) {
saver = (
<Saver
save={this.props.model.save.bind(this.props.model)}
name={this.props.model.card.name}
description={this.props.model.card.description}
hasChanged={this.props.model.hasChanged}
setPermissions={this.props.model.setPermissions.bind(this.props.model)}
permissions={this.props.model.card.public_perms}
/>
);
result = (
<QueryVisualization
card={this.props.model.card}
......@@ -135,64 +123,57 @@ var QueryBuilder = React.createClass({
setDisplay={this.props.model.setDisplay.bind(this.props.model)}
/>
);
download = (
<a className="Button inline-block mr1" href={this.props.model.getDownloadLink()} target="_blank">Download data</a>
);
}
return (
<div className="full-height">
<div className="QueryHeader">
<div className="QueryHeader">
<div className="QueryWrapper">
<div className="inline-block">
<QueryHeader
card={this.props.model.card}
save={this.props.model.save.bind(this.props.model)}
downloadLink={this.props.model.getDownloadLink()}
/>
</div>
</div>
</div>
<div className={queryPickerClasses}>
<div>
<div className="QueryWrapper">
<div className="inline-block">
<QueryHeader
name={this.props.model.card.name}
user={this.props.model.user}
<div className="clearfix">
{runButton}
<QueryPicker
dbList={this.props.model.database_list}
setDatabase={this.props.model.setDatabase.bind(this.props.model)}
db={this.props.model.card.dataset_query.database}
options={this.props.model.selected_table_fields}
tables={this.props.model.table_list}
aggregationFieldList={this.props.model.aggregation_field_list}
query={this.props.model.card.dataset_query.query}
setSourceTable={this.props.model.setSourceTable.bind(this.props.model)}
setAggregation={this.props.model.setAggregation.bind(this.props.model)}
setAggregationTarget={this.props.model.setAggregationTarget.bind(this.props.model)}
addDimension={this.props.model.addDimension.bind(this.props.model)}
removeDimension={this.props.model.removeDimension.bind(this.props.model)}
updateDimension={this.props.model.updateDimension.bind(this.props.model)}
aggregationComplete={this.props.model.aggregationComplete.bind(this.props.model)}
/>
</div>
</div>
</div>
<div className={queryPickerClasses}>
<div>
<div className="QueryWrapper">
<div className="clearfix">
{runButton}
<QueryPicker
dbList={this.props.model.database_list}
setDatabase={this.props.model.setDatabase.bind(this.props.model)}
db={this.props.model.card.dataset_query.database}
options={this.props.model.selected_table_fields}
tables={this.props.model.table_list}
aggregationFieldList={this.props.model.aggregation_field_list}
query={this.props.model.card.dataset_query.query}
setSourceTable={this.props.model.setSourceTable.bind(this.props.model)}
setAggregation={this.props.model.setAggregation.bind(this.props.model)}
setAggregationTarget={this.props.model.setAggregationTarget.bind(this.props.model)}
addDimension={this.props.model.addDimension.bind(this.props.model)}
removeDimension={this.props.model.removeDimension.bind(this.props.model)}
updateDimension={this.props.model.updateDimension.bind(this.props.model)}
aggregationComplete={this.props.model.aggregationComplete.bind(this.props.model)}
/>
</div>
</div>
<div>
<div className="QueryWrapper my2">
{filterHtml}
</div>
<div>
<div className="QueryWrapper my2">
{filterHtml}
</div>
</div>
</div>
<div className="QueryWrapper mb4">
{result}
</div>
</div>
<div className="ActionBar">
{saver}
{download}
</div>
<div className="QueryWrapper mb4">
{result}
</div>
</div>
)
}
......
'use strict';
/*global cx, OnClickOutside, SelectionModule*/
var QueryModeToggle = React.createClass({
displayName: 'QueryModeToggle',
propTypes: {
// description: React.PropTypes.string,
// hasChanged: React.PropTypes.bool,
// name: React.PropTypes.string,
// permissions: React.PropTypes.number,
// setPermissions: React.PropTypes.func.isRequired,
// save: React.PropTypes.func.isRequired
},
mixins: [],
getInitialState: function () {
return {};
},
render: function () {
return (
<div className="Button-group float-right">
<button className="Button">GUI</button>
<button className="Button">SQL</button>
</div>
);
}
});
......@@ -4,18 +4,16 @@
var Saver = React.createClass({
displayName: 'Saver',
propTypes: {
description: React.PropTypes.string,
card: React.PropTypes.object.isRequired,
hasChanged: React.PropTypes.bool,
name: React.PropTypes.string,
permissions: React.PropTypes.number,
setPermissions: React.PropTypes.func.isRequired,
save: React.PropTypes.func.isRequired
},
mixins: [OnClickOutside],
getInitialState: function () {
return {
modalOpen: false,
triggerAction: this._openModal
triggerAction: this._openModal,
permissions: this.props.card.public_perms
};
},
handleClickOutside: function () {
......@@ -30,13 +28,21 @@ var Saver = React.createClass({
this.refs.name.getDOMNode().focus();
});
},
_setPermissions: function(permission) {
console.log('setting perm to ', permission);
this.setState({
permissions: permission
});
},
_save: function () {
var name = this.refs.name.getDOMNode().value,
description = this.refs.description.getDOMNode().value;
description = this.refs.description.getDOMNode().value,
permissions = this.state.permissions;
this.props.save({
name: name,
description: description
description: description,
permissions: permissions
});
// reset the modal
this.setState({
......@@ -56,15 +62,6 @@ var Saver = React.createClass({
'Modal--showing': this.state.modalOpen
});
var buttonText;
// if the query has changed or the modal has been opened
if (this.props.hasChanged === true || this.state.modalOpen === true) {
buttonText = "Save";
} else {
buttonText = "Edit";
}
var privacyOptions = [
{
code: 0,
......@@ -80,31 +77,35 @@ var Saver = React.createClass({
},
];
return (
<div className="SaveWrapper float-right mr2">
<div className={modalClasses}>
<div className="ModalContent">
<input ref="name" type="text" placeholder="Name" autofocus defaultValue={this.props.name} />
<input ref="description" type="text" placeholder="Add a description" defaultValue={this.props.description}/>
<div className="mt4 ml2 mr2 clearfix">
<span className="text-grey-3 inline-block my1">Privacy:</span>
<div className="float-right">
<SelectionModule
placeholder="Privacy"
items={privacyOptions}
selectedKey='code'
selectedValue={this.props.permissions}
display='display'
action={this.props.setPermissions}
/>
// default state is false, which means we don't render anything in the DOM
var saver = false;
if (this.props.card.isDirty()) {
saver = (
<div className="SaveWrapper float-right mr2">
<div className={modalClasses}>
<div className="ModalContent">
<input ref="name" type="text" placeholder="Name" autofocus defaultValue={this.props.card.name} />
<input ref="description" type="text" placeholder="Add a description" defaultValue={this.props.card.description}/>
<div className="mt4 ml2 mr2 clearfix">
<span className="text-grey-3 inline-block my1">Privacy:</span>
<div className="float-right">
<SelectionModule
placeholder="Privacy"
items={privacyOptions}
selectedKey='code'
selectedValue={this.props.permissions}
display='display'
action={this._setPermissions}
/>
</div>
</div>
</div>
</div>
<a className={buttonClasses} onClick={this.state.triggerAction}>Save</a>
</div>
<a className={buttonClasses} onClick={this.state.triggerAction}>
{buttonText}
</a>
</div>
);
);
}
return saver;
}
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment