mirror of
https://github.com/SoPat712/Speeder.git
synced 2026-08-19 11:52:31 -04:00
feat(options): add diagnostics copy action
This commit is contained in:
@@ -1029,6 +1029,7 @@
|
||||
<button id="restore">Restore Defaults</button>
|
||||
<button id="exportSettings">Export Settings</button>
|
||||
<button id="importSettings">Import Settings</button>
|
||||
<button id="copyDiagnostics">Copy Diagnostics</button>
|
||||
</div>
|
||||
|
||||
<div id="status" role="status" aria-live="polite"></div>
|
||||
|
||||
@@ -2104,6 +2104,41 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
.addEventListener("change", updatePopupEditorDisabledState);
|
||||
|
||||
document.getElementById("save").addEventListener("click", save_options);
|
||||
document.getElementById("copyDiagnostics").addEventListener("click", function () {
|
||||
var status = document.getElementById("status");
|
||||
if (
|
||||
!navigator.clipboard ||
|
||||
typeof navigator.clipboard.writeText !== "function"
|
||||
) {
|
||||
status.textContent = "Clipboard access is unavailable.";
|
||||
return;
|
||||
}
|
||||
var report = popupControlUtils.buildDiagnosticReport({
|
||||
speederVersion: manifest.version,
|
||||
browser: navigator.userAgent,
|
||||
platform: navigator.platform || null,
|
||||
storage: {
|
||||
enabled: document.getElementById("enabled").checked,
|
||||
rememberSpeed: document.getElementById("rememberSpeed").checked,
|
||||
forceLastSavedSpeed:
|
||||
document.getElementById("forceLastSavedSpeed").checked,
|
||||
audioBoolean: document.getElementById("audioBoolean").checked,
|
||||
startHidden: document.getElementById("startHidden").checked,
|
||||
hideWithControls: document.getElementById("hideWithControls").checked,
|
||||
controllerLocation: document.getElementById("controllerLocation").value,
|
||||
shortcutTargetMode:
|
||||
document.getElementById("shortcutTargetMode").value
|
||||
}
|
||||
});
|
||||
navigator.clipboard.writeText(report).then(
|
||||
function() {
|
||||
status.textContent = "Diagnostics copied. Review before sharing.";
|
||||
},
|
||||
function() {
|
||||
status.textContent = "Could not copy diagnostics.";
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const addSelector = document.getElementById("addShortcutSelector");
|
||||
if (addSelector) {
|
||||
|
||||
+11
-48
@@ -54,18 +54,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
);
|
||||
}
|
||||
|
||||
function getSafePageDetails(url) {
|
||||
try {
|
||||
var parsed = new URL(url);
|
||||
return {
|
||||
protocol: parsed.protocol,
|
||||
hostname: parsed.hostname || null
|
||||
};
|
||||
} catch (_error) {
|
||||
return { protocol: null, hostname: null };
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentSiteRuleDetails(url) {
|
||||
try {
|
||||
var parsed = new URL(url);
|
||||
@@ -86,42 +74,17 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
function buildDiagnosticReport() {
|
||||
if (!diagnosticContext) return null;
|
||||
var storage = diagnosticContext.storage;
|
||||
var siteRule = diagnosticContext.siteRule;
|
||||
var frame = diagnosticContext.frame;
|
||||
return JSON.stringify(
|
||||
{
|
||||
speederVersion: chrome.runtime.getManifest().version,
|
||||
browser: navigator.userAgent,
|
||||
platform: navigator.platform || null,
|
||||
page: getSafePageDetails(diagnosticContext.url),
|
||||
globalSettings: {
|
||||
enabled: storage.enabled !== false,
|
||||
rememberSpeed: storage.rememberSpeed === true,
|
||||
forceLastSavedSpeed: storage.forceLastSavedSpeed === true,
|
||||
audioEnabled: storage.audioBoolean === true,
|
||||
startHidden: storage.startHidden === true,
|
||||
hideWithControls: storage.hideWithControls === true,
|
||||
controllerLocation: storage.controllerLocation,
|
||||
shortcutTargetMode: storage.shortcutTargetMode
|
||||
},
|
||||
matchedSiteRule: {
|
||||
matched: Boolean(siteRule),
|
||||
disabled: isSiteRuleDisabled(siteRule),
|
||||
overrideKeys: siteRule
|
||||
? Object.keys(siteRule)
|
||||
.filter(function(key) {
|
||||
return key !== "pattern" && key !== "title";
|
||||
})
|
||||
.sort()
|
||||
: []
|
||||
},
|
||||
tabPaused: diagnosticContext.tabPaused === true,
|
||||
frame: frame && frame.diagnostics ? frame.diagnostics : null
|
||||
},
|
||||
null,
|
||||
2
|
||||
);
|
||||
return popupControlUtils.buildDiagnosticReport({
|
||||
speederVersion: chrome.runtime.getManifest().version,
|
||||
browser: navigator.userAgent,
|
||||
platform: navigator.platform || null,
|
||||
url: diagnosticContext.url,
|
||||
storage: diagnosticContext.storage,
|
||||
siteRule: diagnosticContext.siteRule,
|
||||
siteRuleDisabled: isSiteRuleDisabled(diagnosticContext.siteRule),
|
||||
tabPaused: diagnosticContext.tabPaused,
|
||||
frame: diagnosticContext.frame
|
||||
});
|
||||
}
|
||||
|
||||
function persistExpandedSettings(rawStorage, settings, callback) {
|
||||
|
||||
@@ -97,7 +97,61 @@
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function getSafePageDetails(url) {
|
||||
try {
|
||||
var parsed = new URL(url);
|
||||
return {
|
||||
protocol: parsed.protocol,
|
||||
hostname: parsed.hostname || null
|
||||
};
|
||||
} catch (_error) {
|
||||
return { protocol: null, hostname: null };
|
||||
}
|
||||
}
|
||||
|
||||
function buildDiagnosticReport(context) {
|
||||
var config = context || {};
|
||||
var storage = config.storage || {};
|
||||
var siteRule = config.siteRule || null;
|
||||
var frame = config.frame || null;
|
||||
|
||||
return JSON.stringify(
|
||||
{
|
||||
speederVersion: config.speederVersion || null,
|
||||
browser: config.browser || null,
|
||||
platform: config.platform || null,
|
||||
page: getSafePageDetails(config.url),
|
||||
globalSettings: {
|
||||
enabled: storage.enabled !== false,
|
||||
rememberSpeed: storage.rememberSpeed === true,
|
||||
forceLastSavedSpeed: storage.forceLastSavedSpeed === true,
|
||||
audioEnabled: storage.audioBoolean === true,
|
||||
startHidden: storage.startHidden === true,
|
||||
hideWithControls: storage.hideWithControls === true,
|
||||
controllerLocation: storage.controllerLocation,
|
||||
shortcutTargetMode: storage.shortcutTargetMode
|
||||
},
|
||||
matchedSiteRule: {
|
||||
matched: Boolean(siteRule),
|
||||
disabled: config.siteRuleDisabled === true,
|
||||
overrideKeys: siteRule
|
||||
? Object.keys(siteRule)
|
||||
.filter(function(key) {
|
||||
return key !== "pattern" && key !== "title";
|
||||
})
|
||||
.sort()
|
||||
: []
|
||||
},
|
||||
tabPaused: config.tabPaused === true,
|
||||
frame: frame && frame.diagnostics ? frame.diagnostics : null
|
||||
},
|
||||
null,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
buildDiagnosticReport: buildDiagnosticReport,
|
||||
pickBestFrameSpeedResult: pickBestFrameSpeedResult,
|
||||
resolvePopupButtons: resolvePopupButtons,
|
||||
sanitizeButtonOrder: sanitizeButtonOrder
|
||||
|
||||
@@ -84,6 +84,42 @@ describe("options.js", () => {
|
||||
expect(document.getElementById("status").textContent).toBe("Auto-saved");
|
||||
});
|
||||
|
||||
it("copies privacy-safe diagnostics from settings", async () => {
|
||||
bootOptions({
|
||||
syncData: {
|
||||
enabled: false,
|
||||
rememberSpeed: true,
|
||||
siteRules: [
|
||||
{
|
||||
title: "Private account",
|
||||
pattern: "secret.example/private-token",
|
||||
enabled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
const writeText = vi.fn(() => Promise.resolve());
|
||||
Object.defineProperty(navigator, "clipboard", {
|
||||
configurable: true,
|
||||
value: { writeText }
|
||||
});
|
||||
await flushAsyncWork(3);
|
||||
|
||||
document.getElementById("copyDiagnostics").click();
|
||||
await flushAsyncWork(3);
|
||||
|
||||
const reportText = writeText.mock.calls[0][0];
|
||||
const report = JSON.parse(reportText);
|
||||
expect(report.globalSettings.enabled).toBe(false);
|
||||
expect(report.globalSettings.rememberSpeed).toBe(true);
|
||||
expect(report.page).toEqual({ protocol: null, hostname: null });
|
||||
expect(report.matchedSiteRule.matched).toBe(false);
|
||||
expect(report.frame).toBeNull();
|
||||
expect(reportText).not.toContain("Private account");
|
||||
expect(reportText).not.toContain("private-token");
|
||||
expect(document.getElementById("status").textContent).toContain("copied");
|
||||
});
|
||||
|
||||
it("does not partially save options when a required site shortcut is invalid", async () => {
|
||||
const chrome = bootOptions({ syncData: { rememberSpeed: false } });
|
||||
await flushAsyncWork(3);
|
||||
|
||||
Reference in New Issue
Block a user