Bug 1320362 - Move indexedDb storage type in the storage inspector into a new column r?jdescottes draft
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Tue, 29 Nov 2016 10:57:18 +0000
changeset 445855 0828dc74260f2c20fcce78acd5f3f5334b89335b
parent 445848 13736e2db6eb94b02dd28cc88f2943b8109aa374
child 538651 8840d0072cedbaf517b7bd9d7fdf8562432202cf
push id37643
push userbmo:mratcliffe@mozilla.com
push dateWed, 30 Nov 2016 13:36:03 +0000
reviewersjdescottes
bugs1320362
milestone53.0a1
Bug 1320362 - Move indexedDb storage type in the storage inspector into a new column r?jdescottes Ideally we would have used the GUID to join fields to build the compound key but because we show the uniqueId in the tree that would lead to an ugly user experience. As an alternative we simply use e.g. db1 (default) as the uniqueId. This works as a unique key, is informative for the user and means minimal changes to tests. MozReview-Commit-ID: I0XxTIoV33p
devtools/client/locales/en-US/storage.properties
devtools/client/shared/widgets/TableWidget.js
devtools/client/storage/ui.js
devtools/server/actors/storage.js
devtools/server/tests/browser/browser_storage_listings.js
devtools/shared/specs/storage.js
--- a/devtools/client/locales/en-US/storage.properties
+++ b/devtools/client/locales/en-US/storage.properties
@@ -48,18 +48,20 @@ table.headers.localStorage.name=Key
 table.headers.localStorage.value=Value
 
 table.headers.sessionStorage.name=Key
 table.headers.sessionStorage.value=Value
 
 table.headers.Cache.url=URL
 table.headers.Cache.status=Status
 
+table.headers.indexedDB.uniqueKey=Unique key
 table.headers.indexedDB.name=Key
 table.headers.indexedDB.db=Database Name
+table.headers.indexedDB.storage=Storage
 table.headers.indexedDB.objectStore=Object Store Name
 table.headers.indexedDB.value=Value
 table.headers.indexedDB.origin=Origin
 table.headers.indexedDB.version=Version
 table.headers.indexedDB.objectStores=Object Stores
 table.headers.indexedDB.keyPath2=Key Path
 table.headers.indexedDB.autoIncrement=Auto Increment
 table.headers.indexedDB.indexes=Indexes
--- a/devtools/client/shared/widgets/TableWidget.js
+++ b/devtools/client/shared/widgets/TableWidget.js
@@ -714,16 +714,20 @@ TableWidget.prototype = {
       if (this.firstColumn && id == this.firstColumn) {
         continue;
       }
 
       this.columns.set(id, new Column(this, id, columns[id]));
       if (hiddenColumns.includes(id) || privateColumns.includes(id)) {
         // Hide the column.
         this.columns.get(id).toggleColumn();
+
+        if (privateColumns.includes(id)) {
+          this.columns.get(id).private = true;
+        }
       }
     }
     this.sortedOn = sortOn;
     this.sortBy(this.sortedOn);
     this.populateMenuPopup(privateColumns);
   },
 
   /**
@@ -973,16 +977,19 @@ module.exports.TableWidget = TableWidget
  * @param {TableWidget} table
  *        The table object to which the column belongs.
  * @param {string} id
  *        Id of the column.
  * @param {String} header
  *        The displayed string on the column's header.
  */
 function Column(table, id, header) {
+  // By default cells are visible in the UI.
+  this._private = false;
+
   this.tbody = table.tbody;
   this.document = table.document;
   this.window = table.window;
   this.id = id;
   this.uniqueId = table.uniqueId;
   this.wrapTextInElements = table.wrapTextInElements;
   this.table = table;
   this.cells = [];
@@ -1056,16 +1063,33 @@ Column.prototype = {
    * 1 - ascending order
    * 2 - descending order
    */
   get sorted() {
     return this._sortState || 0;
   },
 
   /**
+   * Get the private state of the column (visibility in the UI).
+   */
+  get private() {
+    return this._private;
+  },
+
+  /**
+   * Set the private state of the column (visibility in the UI).
+   *
+   * @param  {Boolean} state
+   *         Private (true or false)
+   */
+  set private(state) {
+    this._private = state;
+  },
+
+  /**
    * Sets the sorted value
    */
   set sorted(value) {
     if (!value) {
       this.header.removeAttribute("sorted");
     } else {
       this.header.setAttribute("sorted",
         value == 1 ? "ascending" : "descending");
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -568,17 +568,17 @@ StorageUI.prototype = {
         if (!this.tree.selectedItem) {
           this.tree.selectedItem = [type, host];
         }
       }
     }
   },
 
   /**
-   * Populates the selected entry from teh table in the sidebar for a more
+   * Populates the selected entry from the table in the sidebar for a more
    * detailed view.
    */
   displayObjectSidebar: Task.async(function* () {
     let item = this.table.selectedRow;
     if (!item) {
       // Make sure that sidebar is hidden and return
       this.sidebar.hidden = true;
       return;
@@ -610,27 +610,37 @@ StorageUI.prototype = {
       let itemProps = Object.keys(item);
       if (itemProps.length > 3) {
         // Display any other information other than the item name and value
         // which may be available.
         let rawObject = Object.create(null);
         let otherProps = itemProps.filter(
           e => !["name", "value", "valueActor"].includes(e));
         for (let prop of otherProps) {
+          let column = this.table.columns.get(prop);
+          if (column && column.private) {
+            continue;
+          }
+
           let cookieProp = COOKIE_KEY_MAP[prop] || prop;
           // The pseduo property of HostOnly refers to converse of isDomain property
           rawObject[cookieProp] = (prop === "isDomain") ? !item[prop] : item[prop];
         }
         itemVar.populate(rawObject, {sorted: true});
         itemVar.twisty = true;
         itemVar.expanded = true;
       }
     } else {
       // Case when displaying IndexedDB db/object store properties.
       for (let key in item) {
+        let column = this.table.columns.get(key);
+        if (column && column.private) {
+          continue;
+        }
+
         mainScope.addItem(key, {}, true).setGrip(item[key]);
         this.parseItemValue(key, item[key]);
       }
     }
 
     this.emit("sidebar-updated");
   }),
 
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -1471,17 +1471,19 @@ function DatabaseMetadata(origin, db, st
 }
 DatabaseMetadata.prototype = {
   get objectStores() {
     return this._objectStores;
   },
 
   toObject() {
     return {
-      name: `${this._name} (${this.storage})`,
+      uniqueKey: `${this._name}${SEPARATOR_GUID}${this.storage}`,
+      name: this._name,
+      storage: this.storage,
       origin: this._origin,
       version: this._version,
       objectStores: this._objectStores.size
     };
   }
 };
 
 StorageActors.createActor({
@@ -1683,17 +1685,19 @@ StorageActors.createActor({
         keyPath: item.keyPath,
         autoIncrement: item.autoIncrement,
         indexes: item.indexes
       };
     }
     if ("objectStores" in item) {
       // DB meta data
       return {
+        uniqueKey: `${item.name} (${item.storage})`,
         db: item.name,
+        storage: item.storage,
         origin: item.origin,
         version: item.version,
         objectStores: item.objectStores
       };
     }
 
     let value = JSON.stringify(item.value);
 
@@ -1825,17 +1829,19 @@ StorageActors.createActor({
         return [
           { name: "name", editable: false },
           { name: "value", editable: false }
         ];
 
       // Detail of indexedDB for one origin
       default:
         return [
+          { name: "uniqueKey", editable: false, private: true },
           { name: "db", editable: false },
+          { name: "storage", editable: false },
           { name: "origin", editable: false },
           { name: "version", editable: false },
           { name: "objectStores", editable: false },
         ];
     }
   })
 });
 
--- a/devtools/server/tests/browser/browser_storage_listings.js
+++ b/devtools/server/tests/browser/browser_storage_listings.js
@@ -465,27 +465,27 @@ var testIndexedDB = Task.async(function*
 var testIndexedDBs = Task.async(function* (index, hosts, indexedDBActor) {
   let host = Object.keys(hosts)[index];
   let matchItems = data => {
     is(data.total, IDBValues.dbDetails[host].length,
        "Number of indexed db in host " + host + " matches");
     for (let item of data.data) {
       let found = false;
       for (let toMatch of IDBValues.dbDetails[host]) {
-        if (item.db == toMatch.db) {
+        if (item.uniqueKey == toMatch.db) {
           found = true;
-          ok(true, "Found indexed db " + item.db + " in response");
+          ok(true, "Found indexed db " + item.uniqueKey + " in response");
           is(item.origin, toMatch.origin, "The origin matches.");
           is(item.version, toMatch.version, "The version matches.");
           is(item.objectStores, toMatch.objectStores,
-             "The numebr of object stores matches.");
+             "The number of object stores matches.");
           break;
         }
       }
-      ok(found, "indexed db " + item.name + " should exist in response");
+      ok(found, "indexed db " + item.uniqueKey + " should exist in response");
     }
   };
 
   ok(!!IDBValues.dbDetails[host], "Host is present in the list : " + host);
   matchItems(yield indexedDBActor.getStoreObjects(host));
   if (index == Object.keys(hosts).length - 1) {
     return;
   }
--- a/devtools/shared/specs/storage.js
+++ b/devtools/shared/specs/storage.js
@@ -35,16 +35,17 @@ function createStorageSpec(options) {
   childSpecs[options.typeName] = protocol.generateActorSpec({
     typeName: options.typeName,
     methods
   });
 }
 
 // Cookies store object
 types.addDictType("cookieobject", {
+  uniqueKey: "string",
   name: "string",
   value: "longstring",
   path: "nullable:string",
   host: "string",
   isDomain: "boolean",
   isSecure: "boolean",
   isHttpOnly: "boolean",
   creationTime: "number",
@@ -171,21 +172,23 @@ createStorageSpec({
     },
   }
 });
 
 // Indexed DB store object
 // This is a union on idb object, db metadata object and object store metadata
 // object
 types.addDictType("idbobject", {
+  uniqueKey: "string",
   name: "nullable:string",
   db: "nullable:string",
   objectStore: "nullable:string",
   origin: "nullable:string",
   version: "nullable:number",
+  storage: "nullable:string",
   objectStores: "nullable:number",
   keyPath: "nullable:string",
   autoIncrement: "nullable:boolean",
   indexes: "nullable:string",
   value: "nullable:longstring"
 });
 
 // Array of Indexed DB store objects