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
--- 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