{ this.modal = modal; }}
+ triggerNode={this.props.triggerNode}
+ isButton
+ modalTitle="Save Dashboard"
+ modalBody={
+
+
+ Overwrite Dashboard [{this.props.dashboard.dashboard_title}]
+
+
+ Save as:
+
+
+
+ }
+ modalFooter={
+
+
+
+ }
+ />
+ );
+ }
+}
+SaveModal.propTypes = propTypes;
+
+export default SaveModal;
diff --git a/superset/assets/javascripts/modules/utils.js b/superset/assets/javascripts/modules/utils.js
index 98e4306647d..065341d9ce1 100644
--- a/superset/assets/javascripts/modules/utils.js
+++ b/superset/assets/javascripts/modules/utils.js
@@ -185,3 +185,9 @@ export function getParamObject(form_data, datasource_type) {
Object.assign(data, filterParams);
return data;
}
+
+export function getAjaxErrorMsg(error) {
+ const respJSON = error.responseJSON;
+ return (respJSON && respJSON.message) ? respJSON.message :
+ error.responseText;
+}
diff --git a/superset/views.py b/superset/views.py
index 5614209bbcf..70d4c0a72cd 100755
--- a/superset/views.py
+++ b/superset/views.py
@@ -1637,33 +1637,64 @@ class Superset(BaseSupersetView):
return Response(
json.dumps(payload), mimetype="application/json")
+ @api
+ @has_access_api
+ @expose("/copy_dash//", methods=['GET', 'POST'])
+ def copy_dash(self, dashboard_id):
+ """Copy dashboard"""
+ session = db.session()
+ data = json.loads(request.form.get('data'))
+ dash = models.Dashboard()
+ original_dash = (session
+ .query(models.Dashboard)
+ .filter_by(id=dashboard_id).first())
+
+ dash.owners = [g.user] if g.user else []
+ dash.dashboard_title = data['dashboard_title']
+ dash.slices = original_dash.slices
+ dash.params = original_dash.params
+
+ self._set_dash_metadata(dash, data)
+ session.add(dash)
+ session.commit()
+ dash_json = dash.json_data
+ session.close()
+ return Response(
+ dash_json, mimetype="application/json")
+
@api
@has_access_api
@expose("/save_dash//", methods=['GET', 'POST'])
def save_dash(self, dashboard_id):
"""Save a dashboard's metadata"""
+ session = db.session()
+ dash = (session
+ .query(models.Dashboard)
+ .filter_by(id=dashboard_id).first())
+ check_ownership(dash, raise_if_false=True)
data = json.loads(request.form.get('data'))
+ self._set_dash_metadata(dash, data)
+ session.merge(dash)
+ session.commit()
+ session.close()
+ return "SUCCESS"
+
+ @staticmethod
+ def _set_dash_metadata(dashboard, data):
positions = data['positions']
slice_ids = [int(d['slice_id']) for d in positions]
- session = db.session()
- Dash = models.Dashboard # noqa
- dash = session.query(Dash).filter_by(id=dashboard_id).first()
- check_ownership(dash, raise_if_false=True)
- dash.slices = [o for o in dash.slices if o.id in slice_ids]
+ dashboard.slices = [o for o in dashboard.slices if o.id in slice_ids]
positions = sorted(data['positions'], key=lambda x: int(x['slice_id']))
- dash.position_json = json.dumps(positions, indent=4, sort_keys=True)
- md = dash.params_dict
+ dashboard.position_json = json.dumps(positions, indent=4, sort_keys=True)
+ md = dashboard.params_dict
+ dashboard.css = data['css']
+
if 'filter_immune_slices' not in md:
md['filter_immune_slices'] = []
if 'filter_immune_slice_fields' not in md:
md['filter_immune_slice_fields'] = {}
md['expanded_slices'] = data['expanded_slices']
- dash.json_metadata = json.dumps(md, indent=4)
- dash.css = data['css']
- session.merge(dash)
- session.commit()
- session.close()
- return "SUCCESS"
+ dashboard.json_metadata = json.dumps(md, indent=4)
@api
@has_access_api
diff --git a/tests/core_tests.py b/tests/core_tests.py
index d5de2cc31ca..d79dd67baaa 100644
--- a/tests/core_tests.py
+++ b/tests/core_tests.py
@@ -251,6 +251,42 @@ class CoreTests(SupersetTestCase):
resp = self.client.post(url, data=dict(data=json.dumps(data)))
assert "SUCCESS" in resp.data.decode('utf-8')
+ def test_copy_dash(self, username='admin'):
+ self.login(username=username)
+ dash = db.session.query(models.Dashboard).filter_by(
+ slug="births").first()
+ positions = []
+ for i, slc in enumerate(dash.slices):
+ d = {
+ 'col': 0,
+ 'row': i * 4,
+ 'size_x': 4,
+ 'size_y': 4,
+ 'slice_id': '{}'.format(slc.id)}
+ positions.append(d)
+ data = {
+ 'css': '',
+ 'expanded_slices': {},
+ 'positions': positions,
+ 'dashboard_title': 'Copy Of Births',
+ }
+
+ # Save changes to Births dashboard and retrieve updated dash
+ dash_id = dash.id
+ url = '/superset/save_dash/{}/'.format(dash_id)
+ self.client.post(url, data=dict(data=json.dumps(data)))
+ dash = db.session.query(models.Dashboard).filter_by(
+ id=dash_id).first()
+ orig_json_data = json.loads(dash.json_data)
+
+ # Verify that copy matches original
+ url = '/superset/copy_dash/{}/'.format(dash_id)
+ resp = self.get_json_resp(url, data=dict(data=json.dumps(data)))
+ self.assertEqual(resp['dashboard_title'], 'Copy Of Births')
+ self.assertEqual(resp['position_json'], orig_json_data['position_json'])
+ self.assertEqual(resp['metadata'], orig_json_data['metadata'])
+ self.assertEqual(resp['slices'], orig_json_data['slices'])
+
def test_add_slices(self, username='admin'):
self.login(username=username)
dash = db.session.query(models.Dashboard).filter_by(