diff --git a/package.json b/package.json
index 826a3a93ed62ad0127ea32cb19a47da9bb1220a1..4fb6766940ab198c3da68b79dce4cf507a237338 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
     "dc": "2.0.0-beta.1",
     "fixed-data-table": "0.2.0",
     "humanize-plus": "1.5.0",
-    "inflection": "1.7.1",
+    "inflection": "^1.7.1",
     "jquery": "2.1.4",
     "moment": "2.9.0",
     "ng-sortable": "1.2.0",
diff --git a/resources/frontend_client/app/card/card.controllers.js b/resources/frontend_client/app/card/card.controllers.js
index ac5686fe5e0f14651391be43eb7789b51b35a4a1..2f09cad568a7a9cfadfa463f67a0767c9416c366 100644
--- a/resources/frontend_client/app/card/card.controllers.js
+++ b/resources/frontend_client/app/card/card.controllers.js
@@ -129,6 +129,7 @@ CardControllers.controller('CardDetail', [
 
         var headerModel = {
             card: null,
+            tableMetadata: null,
             cardApi: Card,
             dashboardApi: Dashboard,
             broadcastEventFn: function(eventName, value) {
@@ -177,6 +178,9 @@ CardControllers.controller('CardDetail', [
                     setCard(card, { setDirty: true, replaceState: false })
                 });
             },
+            revertCardFn: function() {
+                revertCard();
+            },
             toggleDataReferenceFn: toggleDataReference,
             cardIsNewFn: cardIsNew,
             cardIsDirtyFn: cardIsDirty
@@ -365,6 +369,7 @@ CardControllers.controller('CardDetail', [
         function renderHeader() {
             // ensure rendering model is up to date
             headerModel.card = angular.copy(card);
+            headerModel.tableMetadata = tableMetadata;
             headerModel.isShowingDataReference = $scope.isShowingDataReference;
 
             React.render(<QueryHeader {...headerModel}/>, document.getElementById('react_qb_header'));
@@ -844,6 +849,10 @@ CardControllers.controller('CardDetail', [
             savedCardSerialized = null;
         }
 
+        function revertCard() {
+            loadAndSetCard();
+        }
+
         // needs to be performed asynchronously otherwise we get weird infinite recursion
         var updateUrl = _.debounce(function(replaceState) {
             var copy = cleanCopyCard(card);
diff --git a/resources/frontend_client/app/css/edit.css b/resources/frontend_client/app/css/edit.css
new file mode 100644
index 0000000000000000000000000000000000000000..a6e3dfbc05037de05def463c717e72a6e3ae021b
--- /dev/null
+++ b/resources/frontend_client/app/css/edit.css
@@ -0,0 +1,42 @@
+.EditHeader {
+    background-color: #6CAFED;
+}
+
+.EditHeader-title {
+    color: white;
+}
+
+.EditHeader-subtitle {
+    color: rgba(255,255,255,0.5);
+}
+
+.EditHeader .Button {
+    margin-left: 0.75em;
+}
+
+
+.EditHeader .Button {
+    color: var(--brand-color);
+    border: none;
+    text-transform: uppercase;
+    font-size: 0.75rem;
+    background-color: rgba(255,255,255,0.5);
+    font-weight: normal;
+}
+
+.EditHeader .Button--primary {
+    background-color: white;
+}
+
+.EditHeader .Button:hover {
+    background-color: white;
+}
+
+
+.EditHeader .Button.Button--primary:hover {
+    background-color: var(--brand-color);
+}
+
+.EditTitle {
+    width: 455px;
+}
diff --git a/resources/frontend_client/app/lib/query.js b/resources/frontend_client/app/lib/query.js
index 2bad68608393a83ca1627ee4b3f79c4d51b06e30..c7586e62b9276ba70fae92aff25d126c1953f689 100644
--- a/resources/frontend_client/app/lib/query.js
+++ b/resources/frontend_client/app/lib/query.js
@@ -1,5 +1,7 @@
 'use strict';
 
+import inflection from "inflection";
+
 var Query = {
 
     canRun: function(query) {
@@ -305,6 +307,68 @@ var Query = {
             }).filter((r) => r.fields.length > 0);
         }
         return results;
+    },
+
+    generateQueryDescription: function(dataset_query, tableMetadata) {
+        if (!tableMetadata) {
+            return "";
+        }
+
+        function getFieldName(id, table) {
+            if (Array.isArray(id)) {
+                if (id[0] === "fk->") {
+                    var field = table.fields_lookup[id[1]];
+                    if (field) {
+                        return field.display_name + " " + getFieldName(id[2], field.target.table);
+                    }
+                }
+            } else if (table.fields_lookup[id]) {
+                return table.fields_lookup[id].display_name
+            }
+            return '[unknown]';
+        }
+
+        function getFilterDescription(filter) {
+            if (filter[0] === "AND" || filter[0] === "OR") {
+                return filter.slice(1).map(getFilterDescription).join(" " + filter[0].toLowerCase() + " ");
+            } else {
+                return getFieldName(filter[1], tableMetadata);
+            }
+        }
+
+        var query = dataset_query.query;
+
+        var name = inflection.pluralize(tableMetadata.display_name) + " ";
+
+        switch (query.aggregation[0]) {
+            case "rows":     name += "raw data"; break;
+            case "count":    name += "count"; break;
+            case "avg":      name += "average of " + getFieldName(query.aggregation[1], tableMetadata); break;
+            case "distinct": name += "distinct values of " + getFieldName(query.aggregation[1], tableMetadata); break;
+            case "stddev":   name += "standard deviation of " + getFieldName(query.aggregation[1], tableMetadata); break;
+            case "sum":      name += "sum of " + getFieldName(query.aggregation[1], tableMetadata); break;
+            case "cum_sum":  name += "cumulative sum of " + getFieldName(query.aggregation[1], tableMetadata); break;
+            default:
+        }
+
+        if (query.breakout && query.breakout.length > 0) {
+            name += ", grouped by " + query.breakout.map((b) => getFieldName(b, tableMetadata)).join(" and ");
+        }
+
+        var filters = Query.getFilters(dataset_query.query);
+        if (filters && filters.length > 0) {
+            name += ", filtered by " + getFilterDescription(filters);
+        }
+
+        if (query.order_by && query.order_by.length > 0) {
+            name += ", sorted by " + query.order_by.map((ordering) => getFieldName(ordering[0], tableMetadata) + " " + ordering[1]).join(" and ");
+        }
+
+        if (query.limit != null) {
+            name += ", " + query.limit + " " + inflection.inflect("row", query.limit);
+        }
+
+        return name;
     }
 }
 
diff --git a/resources/frontend_client/app/query_builder/header.react.js b/resources/frontend_client/app/query_builder/header.react.js
index 9b1cbe1aaaffa470be22d3e7facdd44d80f7158c..b37085c120847009bd1e3e86e1898cfef8f8af75 100644
--- a/resources/frontend_client/app/query_builder/header.react.js
+++ b/resources/frontend_client/app/query_builder/header.react.js
@@ -8,6 +8,8 @@ import Icon from './icon.react';
 import QueryModeToggle from './query_mode_toggle.react';
 import Saver from './saver.react';
 
+import Input from '../admin/metadata/components/Input.react';
+
 var cx = React.addons.classSet;
 var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
 
@@ -15,9 +17,11 @@ export default React.createClass({
     displayName: 'QueryHeader',
     propTypes: {
         card: React.PropTypes.object.isRequired,
+        tableMetadata: React.PropTypes.object, // can't be required, sometimes null
         cardApi: React.PropTypes.func.isRequired,
         dashboardApi: React.PropTypes.func.isRequired,
         notifyCardChangedFn: React.PropTypes.func.isRequired,
+        revertCardFn: React.PropTypes.func.isRequired,
         setQueryModeFn: React.PropTypes.func.isRequired,
         isShowingDataReference: React.PropTypes.bool.isRequired,
         toggleDataReferenceFn: React.PropTypes.func.isRequired,
@@ -104,20 +108,57 @@ export default React.createClass({
         }
     },
 
-    render: function() {
-        var title = this.props.card.name || "New question";
+    renderEditHeader: function() {
+        if (!this.props.cardIsNewFn()) {
+            var updateButton, discardButton;
+            if (this.props.cardIsDirtyFn()) {
+                discardButton = <a className="Button Button--small text-uppercase" href="#" onClick={this.props.revertCardFn}>Discard Changes</a>;
+            }
+            if (this.state.recentlySaved === "updated" || (this.props.cardIsDirtyFn() && this.props.card.is_creator)) {
+                updateButton = (
+                    <ActionButton
+                        actionFn={this.save}
+                        className='Button Button--small Button--primary text-uppercase'
+                        normalText="Update"
+                        activeText="Updating…"
+                        failedText="Update failed"
+                        successText="Updated"
+                    />
+                );
+            }
+            return (
+                <div className="EditHeader p1 px3 flex align-center">
+                    <span className="EditHeader-title">You are editing a saved question.</span>
+                    <span className="EditHeader-subtitle mx1">Changes will be reflected in 1 dashboard and can be reverted.</span>
+                    <span className="flex-align-right">
+                        {updateButton}
+                        {discardButton}
+                        <a className="Button Button--small text-uppercase" href="#">Delete</a>
+                    </span>
+                </div>
+            );
+        }
+    },
+
+    setCardAttribute: function(attribute, event) {
+        this.props.card[attribute] = event.target.value;
+        this.props.notifyCardChangedFn(this.props.card);
+    },
 
-        var editButton;
+    render: function() {
+        var titleAndDescription;
         if (!this.props.cardIsNewFn() && this.props.card.is_creator) {
-            editButton = (
-                <Saver
-                    card={this.props.card}
-                    saveFn={this.props.notifyCardChangedFn}
-                    saveButtonText="Update"
-                    className='inline-block ml1 link'
-                    canDelete={this.props.card.is_creator}
-                    deleteFn={this.deleteCard}
-                />
+            titleAndDescription = (
+                <div className="EditTitle flex flex-column flex-full bordered rounded mt1 mb2">
+                    <Input className="AdminInput text-bold border-bottom rounded-top h3" type="text" value={this.props.card.name} onChange={this.setCardAttribute.bind(null, "name")}/>
+                    <Input className="AdminInput rounded-bottom h4" type="text" value={this.props.card.description} onChange={this.setCardAttribute.bind(null, "description")} placeholder="No description yet" />
+                </div>
+            );
+        } else {
+            titleAndDescription = (
+                <div className="flex align-center">
+                    <h1 className="Entity-title">New question</h1>
+                </div>
             );
         }
 
@@ -127,20 +168,13 @@ export default React.createClass({
             saveButton = (
                 <Saver
                     card={this.props.card}
+                    tableMetadata={this.props.tableMetadata}
                     saveFn={this.saveCard}
                     buttonText="Save"
                     saveButtonText="Save"
                     canDelete={false}
                 />
             );
-        } else if (this.state.recentlySaved === "updated" || (this.props.cardIsDirtyFn() && this.props.card.is_creator)) {
-            // for existing cards we render a very simply ActionButton
-            saveButton = (
-                <ActionButton
-                    actionFn={this.save}
-                    className='Button Button--primary'
-                />
-            );
         }
 
         var cloneButton;
@@ -192,8 +226,7 @@ export default React.createClass({
         );
 
         var attribution;
-
-        if(this.props.card.creator) {
+        if(this.props.card.creator && false) {
             attribution = (
                 <div className="Entity-attribution">
                     Asked by {this.props.card.creator.common_name}
@@ -210,30 +243,29 @@ export default React.createClass({
         }
 
         return (
-            <div className="py1 lg-py2 xl-py3 QueryBuilder-section wrapper flex align-center">
-                <div className="Entity">
-                    <div className="flex align-center">
-                        <h1 className="Entity-title">{title}</h1>
-                        {this.permissions()}
-                        {editButton}
+            <div>
+                {this.renderEditHeader()}
+                <div className="py1 lg-py2 xl-py3 QueryBuilder-section wrapper flex align-center">
+                    <div className="Entity">
+                        {titleAndDescription}
+                        {attribution}
                     </div>
-                    {attribution}
-                </div>
 
-                <div className="flex align-center flex-align-right">
+                    <div className="flex align-center flex-align-right">
 
-                    <span className="pr3">
-                        {saveButton}
-                        {queryModeToggle}
-                    </span>
+                        <span className="pr3">
+                            {saveButton}
+                            {queryModeToggle}
+                        </span>
 
-                    {cardFavorite}
-                    {cloneButton}
-                    {addToDashButton}
+                        {cardFavorite}
+                        {cloneButton}
+                        {addToDashButton}
 
-                    {dividerRight}
+                        {dividerRight}
 
-                    {dataReferenceButton}
+                        {dataReferenceButton}
+                    </div>
                 </div>
             </div>
         );
diff --git a/resources/frontend_client/app/query_builder/saver.react.js b/resources/frontend_client/app/query_builder/saver.react.js
index d162ff1d2f5229a86bbef09b8f44cf7e5eeb12e7..18051f6feaef8c5f5bfd3f1dc2a9ff51c04fcf6a 100644
--- a/resources/frontend_client/app/query_builder/saver.react.js
+++ b/resources/frontend_client/app/query_builder/saver.react.js
@@ -5,12 +5,15 @@ import OnClickOutside from 'react-onclickoutside';
 import FormField from './form_field.react';
 import Icon from './icon.react';
 
+import Query from "metabase/lib/query";
+
 var cx = React.addons.classSet;
 
 export default React.createClass({
     displayName: 'Saver',
     propTypes: {
         card: React.PropTypes.object.isRequired,
+        tableMetadata: React.PropTypes.object, // can't be required, sometimes null
         saveFn: React.PropTypes.func.isRequired,
         deleteFn: React.PropTypes.func
     },
@@ -72,7 +75,7 @@ export default React.createClass({
         var card = this.props.card;
         card.name = this.refs.name.getDOMNode().value.trim();
         card.description = this.refs.description.getDOMNode().value.trim();
-        card.public_perms = parseInt(this.refs.public_perms.getDOMNode().value);
+        card.public_perms = 2; // public read/write
 
         this.props.saveFn(card).then((success) => {
             if (this.isMounted()) {
@@ -109,12 +112,6 @@ export default React.createClass({
             return false;
         }
 
-        // TODO: hard coding values :(
-        var privacyOptions = [
-            (<option key="0" value={0}>Private</option>),
-            (<option key="1" value={1}>Public (others can read)</option>)
-        ];
-
         var formError;
         if (this.state.errors) {
             var errorMessage;
@@ -140,6 +137,8 @@ export default React.createClass({
             "Button--primary": this.isFormReady()
         });
 
+        var name = this.props.card.name || Query.generateQueryDescription(this.props.card.dataset_query, this.props.tableMetadata);
+
         return (
             <form className="NewForm full" onSubmit={this.save}>
                 <div className="Form-header flex align-center">
@@ -154,25 +153,14 @@ export default React.createClass({
                         displayName="Name"
                         fieldName="name"
                         errors={this.state.errors}>
-                        <input ref="name" className="Form-input full" name="name" placeholder="What is the name of your card?" defaultValue={this.props.card.name} autofocus/>
+                        <input ref="name" className="Form-input full" name="name" placeholder="What is the name of your card?" defaultValue={name} autofocus/>
                     </FormField>
 
                     <FormField
                         displayName="Description (optional)"
                         fieldName="description"
                         errors={this.state.errors}>
-                        <input ref="description" className="Form-input full" name="description" placeholder="What else should people know about this?" defaultValue={this.props.card.description} />
-                    </FormField>
-
-                    <FormField
-                        displayName="Privacy"
-                        fieldName="public_perms"
-                        errors={this.state.errors}>
-                        <label className="Select">
-                            <select className="mt1" ref="public_perms" defaultValue={this.props.card.public_perms}>
-                                {privacyOptions}
-                            </select>
-                        </label>
+                        <textarea ref="description" className="Form-input full" name="description" placeholder="It's optional but oh, so helpful" defaultValue={this.props.card.description} />
                     </FormField>
 
                     {this.renderCardDelete()}