blob: 0872cfaf8339085f497ba9a06af8239362f3e7d3 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371// Copyright (c) 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * @implements {SDK.TargetManager.Observer}
7 */
8Resources.ClearStorageView = class extends UI.ThrottledWidget {
9 constructor() {
10 super(true, 1000);
11 const types = Protocol.Storage.StorageType;
12 this._pieColors = new Map([
13 [types.Appcache, 'rgb(110, 161, 226)'], // blue
14 [types.Cache_storage, 'rgb(229, 113, 113)'], // red
15 [types.Cookies, 'rgb(239, 196, 87)'], // yellow
16 [types.Indexeddb, 'rgb(155, 127, 230)'], // purple
17 [types.Local_storage, 'rgb(116, 178, 102)'], // green
18 [types.Service_workers, 'rgb(255, 167, 36)'], // orange
19 [types.Websql, 'rgb(203, 220, 56)'], // lime
20 ]);
21
22 this._reportView = new UI.ReportView(Common.UIString('Clear storage'));
23 this._reportView.registerRequiredCSS('resources/clearStorageView.css');
24 this._reportView.element.classList.add('clear-storage-header');
25 this._reportView.show(this.contentElement);
26 /** @type {?SDK.Target} */
27 this._target = null;
28 /** @type {?string} */
29 this._securityOrigin = null;
30
31 this._settings = new Map();
32 for (const type of
33 [types.Appcache, types.Cache_storage, types.Cookies, types.Indexeddb, types.Local_storage,
34 types.Service_workers, types.Websql])
35 this._settings.set(type, Common.settings.createSetting('clear-storage-' + type, true));
36
37 const quota = this._reportView.appendSection(Common.UIString('Usage'));
38 this._quotaRow = quota.appendRow();
39 this._quotaUsage = null;
40 this._pieChart = new PerfUI.PieChart(110, Number.bytesToString, true);
41 this._pieChartLegend = createElement('div');
42 const usageBreakdownRow = quota.appendRow();
43 usageBreakdownRow.classList.add('usage-breakdown-row');
44 usageBreakdownRow.appendChild(this._pieChart.element);
45 usageBreakdownRow.appendChild(this._pieChartLegend);
46
47 const application = this._reportView.appendSection(Common.UIString('Application'));
48 this._appendItem(application, Common.UIString('Unregister service workers'), 'service_workers');
49
50 const storage = this._reportView.appendSection(Common.UIString('Storage'));
51 this._appendItem(storage, Common.UIString('Local and session storage'), 'local_storage');
52 this._appendItem(storage, Common.UIString('IndexedDB'), 'indexeddb');
53 this._appendItem(storage, Common.UIString('Web SQL'), 'websql');
54 this._appendItem(storage, Common.UIString('Cookies'), 'cookies');
55
56 const caches = this._reportView.appendSection(Common.UIString('Cache'));
57 this._appendItem(caches, Common.UIString('Cache storage'), 'cache_storage');
58 this._appendItem(caches, Common.UIString('Application cache'), 'appcache');
59
60 SDK.targetManager.observeTargets(this, SDK.Target.Capability.Browser);
61 const footer = this._reportView.appendSection('', 'clear-storage-button').appendRow();
62 this._clearButton = UI.createTextButton(
63 Common.UIString('Clear site data'), this._clear.bind(this), Common.UIString('Clear site data'));
64 footer.appendChild(this._clearButton);
65 }
66
67 /**
68 * @param {!UI.ReportView.Section} section
69 * @param {string} title
70 * @param {string} settingName
71 */
72 _appendItem(section, title, settingName) {
73 const row = section.appendRow();
74 row.appendChild(UI.SettingsUI.createSettingCheckbox(title, this._settings.get(settingName), true));
75 }
76
77 /**
78 * @override
79 * @param {!SDK.Target} target
80 */
81 targetAdded(target) {
82 if (this._target)
83 return;
84 this._target = target;
85 const securityOriginManager = target.model(SDK.SecurityOriginManager);
86 this._updateOrigin(securityOriginManager.mainSecurityOrigin());
87 securityOriginManager.addEventListener(
88 SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, this._originChanged, this);
89 }
90
91 /**
92 * @override
93 * @param {!SDK.Target} target
94 */
95 targetRemoved(target) {
96 if (this._target !== target)
97 return;
98 const securityOriginManager = target.model(SDK.SecurityOriginManager);
99 securityOriginManager.removeEventListener(
100 SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, this._originChanged, this);
101 }
102
103 /**
104 * @param {!Common.Event} event
105 */
106 _originChanged(event) {
107 const origin = /** *@type {string} */ (event.data);
108 this._updateOrigin(origin);
109 }
110
111 /**
112 * @param {string} url
113 */
114 _updateOrigin(url) {
115 this._securityOrigin = new Common.ParsedURL(url).securityOrigin();
116 this._reportView.setSubtitle(this._securityOrigin);
117 this.doUpdate();
118 }
119
120 _clear() {
121 if (!this._securityOrigin)
122 return;
123 const storageTypes = [];
124 for (const type of this._settings.keys()) {
125 if (this._settings.get(type).get())
126 storageTypes.push(type);
127 }
128
129 this._target.storageAgent().clearDataForOrigin(this._securityOrigin, storageTypes.join(','));
130
131 const set = new Set(storageTypes);
132 const hasAll = set.has(Protocol.Storage.StorageType.All);
133 if (set.has(Protocol.Storage.StorageType.Cookies) || hasAll) {
134 const cookieModel = this._target.model(SDK.CookieModel);
135 if (cookieModel)
136 cookieModel.clear();
137 }
138
139 if (set.has(Protocol.Storage.StorageType.Indexeddb) || hasAll) {
140 for (const target of SDK.targetManager.targets()) {
141 const indexedDBModel = target.model(Resources.IndexedDBModel);
142 if (indexedDBModel)
143 indexedDBModel.clearForOrigin(this._securityOrigin);
144 }
145 }
146
147 if (set.has(Protocol.Storage.StorageType.Local_storage) || hasAll) {
148 const storageModel = this._target.model(Resources.DOMStorageModel);
149 if (storageModel)
150 storageModel.clearForOrigin(this._securityOrigin);
151 }
152
153 if (set.has(Protocol.Storage.StorageType.Websql) || hasAll) {
154 const databaseModel = this._target.model(Resources.DatabaseModel);
155 if (databaseModel) {
156 databaseModel.disable();
157 databaseModel.enable();
158 }
159 }
160
161 if (set.has(Protocol.Storage.StorageType.Cache_storage) || hasAll) {
162 const target = SDK.targetManager.mainTarget();
163 const model = target && target.model(SDK.ServiceWorkerCacheModel);
164 if (model)
165 model.clearForOrigin(this._securityOrigin);
166 }
167
168 if (set.has(Protocol.Storage.StorageType.Appcache) || hasAll) {
169 const appcacheModel = this._target.model(Resources.ApplicationCacheModel);
170 if (appcacheModel)
171 appcacheModel.reset();
172 }
173
174 this._clearButton.disabled = true;
175 const label = this._clearButton.textContent;
176 this._clearButton.textContent = Common.UIString('Clearing...');
177 setTimeout(() => {
178 this._clearButton.disabled = false;
179 this._clearButton.textContent = label;
180 }, 500);
181 }
182
183 /**
184 * @override
185 * @return {!Promise<?>}
186 */
187 async doUpdate() {
188 if (!this._securityOrigin)
189 return;
190
191 const securityOrigin = /** @type {string} */ (this._securityOrigin);
192 const response = await this._target.storageAgent().invoke_getUsageAndQuota({origin: securityOrigin});
193 if (response[Protocol.Error]) {
194 this._quotaRow.textContent = '';
195 this._resetPieChart(0);
196 return;
197 }
198 this._quotaRow.textContent = Common.UIString(
199 '%s used out of %s storage quota', Number.bytesToString(response.usage), Number.bytesToString(response.quota));
200
201 if (!this._quotaUsage || this._quotaUsage !== response.usage) {
202 this._quotaUsage = response.usage;
203 this._resetPieChart(response.usage);
204 for (const usageForType of response.usageBreakdown.sort((a, b) => b.usage - a.usage)) {
205 const value = usageForType.usage;
206 if (!value)
207 continue;
208 const title = this._getStorageTypeName(usageForType.storageType);
209 const color = this._pieColors.get(usageForType.storageType) || '#ccc';
210 this._pieChart.addSlice(value, color);
211 const rowElement = this._pieChartLegend.createChild('div', 'usage-breakdown-legend-row');
212 rowElement.createChild('span', 'usage-breakdown-legend-value').textContent = Number.bytesToString(value);
213 rowElement.createChild('span', 'usage-breakdown-legend-swatch').style.backgroundColor = color;
214 rowElement.createChild('span', 'usage-breakdown-legend-title').textContent = title;
215 }
216 }
217
218 this._usageUpdatedForTest(response.usage, response.quota, response.usageBreakdown);
219 this.update();
220 }
221
222 /**
223 * @param {number} total
224 */
225 _resetPieChart(total) {
226 this._pieChart.setTotal(total);
227 this._pieChartLegend.removeChildren();
228 }
229
230 /**
231 * @param {string} type
232 * @return {string}
233 */
234 _getStorageTypeName(type) {
235 switch (type) {
236 case Protocol.Storage.StorageType.File_systems:
237 return Common.UIString('File System');
238 case Protocol.Storage.StorageType.Websql:
239 return Common.UIString('Web SQL');
240 case Protocol.Storage.StorageType.Appcache:
241 return Common.UIString('Application Cache');
242 case Protocol.Storage.StorageType.Indexeddb:
243 return Common.UIString('IndexedDB');
244 case Protocol.Storage.StorageType.Cache_storage:
245 return Common.UIString('Cache Storage');
246 case Protocol.Storage.StorageType.Service_workers:
247 return Common.UIString('Service Workers');
248 default:
249 return Common.UIString('Other');
250 }
251 }
252
253 /**
254 * @param {number} usage
255 * @param {number} quota
256 * @param {!Array<!Protocol.Storage.UsageForType>} usageBreakdown
257 */
258 _usageUpdatedForTest(usage, quota, usageBreakdown) {
259 }
260};