import json

from flask import request

from redash import models
from redash.wsgi import api
from redash.permissions import require_permission
from redash.handlers.base import BaseResource


class WidgetListAPI(BaseResource):
    @require_permission('edit_dashboard')
    def post(self):
        widget_properties = request.get_json(force=True)
        widget_properties['options'] = json.dumps(widget_properties['options'])
        widget_properties.pop('id', None)
        widget_properties['dashboard'] = widget_properties.pop('dashboard_id')
        widget_properties['visualization'] = widget_properties.pop('visualization_id')
        widget = models.Widget(**widget_properties)
        widget.save()

        layout = json.loads(widget.dashboard.layout)
        new_row = True

        if len(layout) == 0 or widget.width == 2:
            layout.append([widget.id])
        elif len(layout[-1]) == 1:
            neighbour_widget = models.Widget.get(models.Widget.id == layout[-1][0])
            if neighbour_widget.width == 1:
                layout[-1].append(widget.id)
                new_row = False
            else:
                layout.append([widget.id])
        else:
            layout.append([widget.id])

        widget.dashboard.layout = json.dumps(layout)
        widget.dashboard.save()

        return {'widget': widget.to_dict(), 'layout': layout, 'new_row': new_row}


class WidgetAPI(BaseResource):
    @require_permission('edit_dashboard')
    def delete(self, widget_id):
        widget = models.Widget.get(models.Widget.id == widget_id)
        widget.delete_instance()

api.add_resource(WidgetListAPI, '/api/widgets', endpoint='widgets')
api.add_resource(WidgetAPI, '/api/widgets/<int:widget_id>', endpoint='widget')

redash/handlers/widgets.py
import json

from flask import request

from redash import models
from redash.wsgi import api
from redash.permissions import require_permission
from redash.handlers.base import BaseResource


class WidgetListAPI(BaseResource):
    @require_permission('edit_dashboard')
    def post(self):
        widget_properties = request.get_json(force=True)
        widget_properties['options'] = json.dumps(widget_properties['options'])
        widget_properties.pop('id', None)
        widget_properties['dashboard'] = widget_properties.pop('dashboard_id')
        widget_properties['visualization'] = widget_properties.pop('visualization_id')
        widget = models.Widget(**widget_properties)
        widget.save()

        layout = json.loads(widget.dashboard.layout)
        new_row = True

        if len(layout) == 0 or widget.width == 2:
            layout.append([widget.id])
        elif len(layout[-1]) == 1:
            neighbour_widget = models.Widget.get(models.Widget.id == layout[-1][0])
            if neighbour_widget.width == 1:
                layout[-1].append(widget.id)
                new_row = False
            else:
                layout.append([widget.id])
        else:
            layout.append([widget.id])

        widget.dashboard.layout = json.dumps(layout)
        widget.dashboard.save()

        return {'widget': widget.to_dict(), 'layout': layout, 'new_row': new_row}


class WidgetAPI(BaseResource):
    @require_permission('edit_dashboard')
    def delete(self, widget_id):
        widget = models.Widget.get(models.Widget.id == widget_id)
        widget.delete_instance()

        return {'layout': widget.dashboard.layout }

api.add_resource(WidgetListAPI, '/api/widgets', endpoint='widgets')
api.add_resource(WidgetAPI, '/api/widgets/<int:widget_id>', endpoint='widget')

redash/handlers/widgets.py
diff --git a/rd_ui/app/scripts/controllers/dashboard.js b/rd_ui/app/scripts/controllers/dashboard.js
index f61c9b8cd4..d30747a0b7 100644
--- a/rd_ui/app/scripts/controllers/dashboard.js
+++ b/rd_ui/app/scripts/controllers/dashboard.js
@@ -134,12 +134,16 @@
 
       Events.record(currentUser, "delete", "widget", $scope.widget.id);
 
-      $scope.widget.$delete(function() {
+      $scope.widget.$delete(function(response) {
         $scope.dashboard.widgets = _.map($scope.dashboard.widgets, function(row) {
           return _.filter(row, function(widget) {
             return widget.id != undefined;
           })
         });
+
+        $scope.dashboard.widgets = _.filter($scope.dashboard.widgets, function(row) { return row.length > 0 });
+
+        $scope.dashboard.layout = response.layout;
       });
     };
 
diff --git a/rd_ui/app/scripts/directives/dashboard_directives.js b/rd_ui/app/scripts/directives/dashboard_directives.js
index 8bb34550c0..19d7f63b37 100644
--- a/rd_ui/app/scripts/directives/dashboard_directives.js
+++ b/rd_ui/app/scripts/directives/dashboard_directives.js
@@ -85,7 +85,9 @@
                 'name': $scope.dashboard.name,
                 'layout': layout
               }).success(function(response) {
-                $scope.dashboard = new Dashboard(response);
+                // TODO(@arikfr): we should use the whole response object here, but because we need to manipulate it
+                // we can't until we move the manipulation code into a central place (like we did for Alerts).
+                $scope.dashboard.layout = response.layout;
                 $scope.saveInProgress = false;
                 $(element).modal('hide');
               });
diff --git a/redash/handlers/widgets.py b/redash/handlers/widgets.py
index 11d9facaff..bb311ab0dd 100644
--- a/redash/handlers/widgets.py
+++ b/redash/handlers/widgets.py
@@ -46,5 +46,7 @@ def delete(self, widget_id):
         widget = models.Widget.get(models.Widget.id == widget_id)
         widget.delete_instance()
 
+        return {'layout': widget.dashboard.layout }
+
 api.add_resource(WidgetListAPI, '/api/widgets', endpoint='widgets')
 api.add_resource(WidgetAPI, '/api/widgets/<int:widget_id>', endpoint='widget')

Deleting and re-adding widgets to a dashboard breaks it
There's a specific set of steps that has messed up some of our users' dashboards:
1. Create a new dashboard
2. Add multiple widgets to it.
3. Remove all those widgets from the dashboard
4. Re-add some widgets
5. Click the "Edit Dashboard (Name/Layout)" button
6. Click Save without changing anything.
7. Refresh the page

This makes none of the widgets appear and causes the "Layout" array in the admin panel to contain one or more "null" values (depending on how many widgets you added/deleted):
![image](https://cloud.githubusercontent.com/assets/844493/11826038/76c749fa-a348-11e5-9f46-bbae43c4b6f6.png)

The only way to recover from this state is to manually delete the "null" values through the admin interface.

This is on re:dash version 0.8.2

