Skip to content

Commit

Permalink
feat(panel): Add the "Report a broken page" view
Browse files Browse the repository at this point in the history
  • Loading branch information
smalluban committed Dec 23, 2024
1 parent 5fce1f6 commit 6df993b
Show file tree
Hide file tree
Showing 25 changed files with 389 additions and 29 deletions.
67 changes: 67 additions & 0 deletions src/background/broken-page-report.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Ghostery Browser Extension
* https://www.ghostery.com/
*
* Copyright 2017-present Ghostery GmbH. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/

import getBrowserInfo from '/utils/browser-info.js';
import { SUPPORT_PAGE_URL } from '/utils/urls.js';

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.action === 'report-broken-page') {
(async () => {
try {
const formData = new FormData();
const browserInfo = await getBrowserInfo();

formData.append('support_ticket[user_name]', '');
formData.append('support_ticket[user_email]', msg.email);
formData.append(
'support_ticket[subject]',
`[GBE] Broken page report: ${msg.url}`,
);
formData.append('support_ticket[message]', msg.description);
formData.append('support_ticket[selected_browser]', browserInfo.name);
formData.append('support_ticket[browser_version]', browserInfo.version);
formData.append('support_ticket[selected_os]', browserInfo.osVersion);
formData.append('support_ticket[os_version]', '');

if (msg.screenshot) {
const screenshot = await chrome.tabs.captureVisibleTab(null, {
format: 'jpeg',
quality: 100,
});
formData.append(
'support_ticket[screenshot]',
await fetch(screenshot).then((res) => res.blob()),
'screenshot.jpeg',
);
}

await fetch(SUPPORT_PAGE_URL, {
method: 'POST',
body: formData,
}).then((res) => {
if (!res.ok || res.status > 204) {
throw new Error(
`Sending report has failed with status: ${res.status}`,
);
}
});

sendResponse();
} catch (e) {
sendResponse(e.message);
}
})();

return true;
}

return false;
});
1 change: 1 addition & 0 deletions src/background/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import './session.js';
import './stats.js';
import './notifications.js';
import './serp.js';
import './broken-page-report.js';

import './helpers.js';
import './external.js';
Expand Down
2 changes: 1 addition & 1 deletion src/background/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/
import { UPDATE_SESSION_ACTION_NAME } from '/store/session.js';
import { HOME_PAGE_URL, ACCOUNT_PAGE_URL } from '/utils/api.js';
import { HOME_PAGE_URL, ACCOUNT_PAGE_URL } from '/utils/urls.js';

// Observe cookie changes (login/logout actions)
chrome.webNavigation.onDOMContentLoaded.addListener(async ({ url = '' }) => {
Expand Down
2 changes: 1 addition & 1 deletion src/background/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Session from '/store/session.js';

import { getUserOptions, setUserOptions } from '/utils/api.js';
import * as OptionsObserver from '/utils/options-observer.js';
import { HOME_PAGE_URL, ACCOUNT_PAGE_URL } from '/utils/api.js';
import { HOME_PAGE_URL, ACCOUNT_PAGE_URL } from '/utils/urls.js';
import debounce from '/utils/debounce.js';

const syncOptions = debounce(
Expand Down
1 change: 1 addition & 0 deletions src/manifest.chromium.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"storage",
"scripting",
"tabs",
"activeTab",
"webRequest",
"offscreen"
],
Expand Down
1 change: 1 addition & 0 deletions src/manifest.firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"storage",
"scripting",
"tabs",
"activeTab",
"webNavigation",
"webRequest",
"webRequestBlocking",
Expand Down
3 changes: 2 additions & 1 deletion src/manifest.safari.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"webNavigation",
"storage",
"scripting",
"tabs"
"tabs",
"activeTab"
],
"host_permissions": [
"http://*/*",
Expand Down
44 changes: 44 additions & 0 deletions src/pages/panel/assets/contribution.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/pages/panel/components/pause.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export default {
html`<ui-text type="body-xs" color="inherit">
<ui-revoke-at revokeAt="${revokeAt}"></ui-revoke-at>
</ui-text>`}
<slot></slot>
</div>
</div>
<div
Expand Down Expand Up @@ -119,6 +118,7 @@ export default {
`}
</div>
</button>
<slot></slot>
${pauseList &&
html`
<section
Expand Down
29 changes: 28 additions & 1 deletion src/pages/panel/views/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import sleep from '../assets/sleep.svg';
import Menu from './menu.js';
import TrackerDetails from './tracker-details.js';
import ProtectionStatus from './protection-status.js';
import ReportForm from './report-form.js';
import ReportConfirm from './report-confirm.js';

const SETTINGS_URL = chrome.runtime.getURL(
'/pages/settings/index.html#@settings-privacy',
Expand Down Expand Up @@ -101,7 +103,9 @@ function tail(hostname) {
}

export default {
[router.connect]: { stack: [Menu, TrackerDetails, ProtectionStatus] },
[router.connect]: {
stack: [Menu, ReportForm, ReportConfirm, TrackerDetails, ProtectionStatus],
},
options: store(Options),
stats: store(TabStats),
notification: store(Notification),
Expand Down Expand Up @@ -170,6 +174,29 @@ export default {
revokeAt="${globalPause?.revokeAt || paused?.revokeAt}"
data-qa="component:pause"
>
${paused?.revokeAt &&
html`
<div layout="row center">
<ui-action>
<a
href="${router.url(ReportForm)}"
layout="row center gap padding:0.5:1:1 margin:top:-1"
>
<ui-text type="body-s">Something wrong?</ui-text>
<ui-text
type="label-s"
layout="row inline items:center gap:0.5"
>
Report a broken page
<ui-icon
name="arrow-right"
layout="size:1.5"
></ui-icon>
</ui-text>
</a>
</ui-action>
</div>
`}
</panel-pause>
`
: html`
Expand Down
48 changes: 48 additions & 0 deletions src/pages/panel/views/report-confirm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Ghostery Browser Extension
* https://www.ghostery.com/
*
* Copyright 2017-present Ghostery GmbH. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/

import { html, router } from 'hybrids';

import contributionImage from '../assets/contribution.svg';

export default {
render: () => html`
<template layout="column grow">
<ui-header>
<div layout="row gap items:center">
<ui-icon name="report" layout="size:2"></ui-icon>
Report a broken page
</div>
<ui-action slot="actions">
<a href="${router.backUrl()}">
<ui-icon name="close" color="gray-800" layout="size:3"></ui-icon>
</a>
</ui-action>
</ui-header>
<panel-container>
<div layout="column items:center gap padding:2:2:4">
<img
src="${contributionImage}"
alt="Contribution"
layout="size:20 margin:3"
/>
<ui-text type="headline-s" layout="block:center width:::40">
Thank you for your report!
</ui-text>
<ui-text type="body-m" layout="block:center width:::36">
We appreciate your help in making the web a better place.
</ui-text>
</div>
</panel-container>
</template>
`,
};
157 changes: 157 additions & 0 deletions src/pages/panel/views/report-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/**
* Ghostery Browser Extension
* https://www.ghostery.com/
*
* Copyright 2017-present Ghostery GmbH. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0
*/

import { html, router, store } from 'hybrids';

import Session from '/store/session.js';
import { getCurrentTab } from '/utils/tabs.js';

import ReportConfirm from './report-confirm.js';

const Form = {
url: '',
email: '',
description: '',
screenshot: false,
[store.connect]: {
async get() {
const [currentTab, session] = await Promise.all([
getCurrentTab(),
store.resolve(Session),
]);

const url = currentTab && new URL(currentTab.url);

return {
url: url ? `${url.origin}${url.pathname}` : '',
email: session.email,
};
},
async set(_, values) {
const error = await chrome.runtime.sendMessage({
action: 'report-broken-page',
...values,
});

if (error) throw new Error(error);

return values;
},
},
};

function submit(host, event) {
try {
router.resolve(
event,
store.submit(host.form).then(() => store.clear(Form)),
);
} catch {
event.preventDefault();
}
}

export default {
form: store(Form, { draft: true }),
render: ({ form }) => html`
<template layout="column grow shrink">
<ui-header>
<div layout="row gap items:center">
<ui-icon name="report" layout="size:2"></ui-icon>
Report a broken page
</div>
<ui-action slot="actions">
<a href="${router.backUrl()}">
<ui-icon name="close" color="gray-800" layout="size:3"></ui-icon>
</a>
</ui-action>
</ui-header>
<panel-container>
${store.ready(form) &&
html`
<form
layout="column gap:2 padding:2"
onsubmit="${submit}"
action="${router.url(ReportConfirm)}"
>
${store.error(form) &&
!store.pending(form) &&
html`
<div layout="row gap items:center">
<ui-icon
name="warning"
layout="inline size:2"
color="danger-700"
></ui-icon>
<ui-text color="danger-700">
${store.error(form).message}
</ui-text>
</div>
`}
<ui-text layout="width:::40">
Inform us about a broken page so we can investigate and fix it.
</ui-text>
<ui-line></ui-line>
<ui-text
type="label-s"
color="primary-700"
style="word-break: break-all"
layout="width:::40"
>
${form.url}
</ui-text>
<ui-input>
<textarea
placeholder="Describe the issue"
rows="4"
autocomplete="off"
style="resize: vertical"
oninput="${html.set(form, 'description')}"
maxlength="5000"
layout="::ui:font:body-s"
required
></textarea>
</ui-input>
<ui-input>
<input
type="email"
name="email"
placeholder="Email address"
layout="::ui:font:body-s"
value="${form.email}"
oninput="${html.set(form, 'email')}"
required
/>
</ui-input>
<label layout="row gap items:center">
<input
type="checkbox"
onchange="${html.set(form, 'screenshot')}"
/>
<ui-text type="body-s">
Include a screenshot of this page
</ui-text>
</label>
<ui-line></ui-line>
<div layout="grid:2 gap:1">
<ui-button type="transparent" disabled="${store.pending(form)}">
<a href="${router.backUrl()}">Cancel</a>
</ui-button>
<ui-button type="primary" disabled="${store.pending(form)}">
<button type="submit">Send</button>
</ui-button>
</div>
</form>
`}
</panel-container>
</template>
`,
};
Loading

0 comments on commit 6df993b

Please sign in to comment.