Skip to content
Permalink
Browse files

Fix: Pre-populate known environment data when clicking "Feedback"

Fix #2711 
Close #2777
  • Loading branch information...
sarvaje authored and antross committed Aug 5, 2019
1 parent e84e4c9 commit f4ce80c66b1962eeac68da812a22d5d2f69dfd85
@@ -28,7 +28,6 @@ resolution, or progress updates.

* __webhint version:__ <!-- ✍️ Menu > Add-ons / Extensions -->
* __Browser version:__ <!-- ✍️ Menu > Help > About -->
* __Operating system:__ <!-- ✍️ -->
* __URL for which webhint failed:__ <!-- ✍️ -->

## `webhint` configuration
@@ -46,12 +45,12 @@ Categories:

Your target browsers:
* [x] Recommended settings
* [ ] Custom: <!-- ✍️ -->
* [ ] Custom: <!-- Custom target browsers -->

Ignored resources:
* [x] None
* [ ] Different origin
* [ ] Custom: <!-- ✍️ -->
* [ ] Custom: <!-- Custom ignored resources -->

</details>

@@ -58,7 +58,7 @@
"clean:root": "rimraf dist",
"lint": "npm-run-all --parallel lint:*",
"lint:dependencies": "node scripts/lint-dependencies.js",
"lint:md": "node scripts/lint-markdown && markdown-link-validator .",
"lint:md": "node scripts/lint-markdown && markdown-link-validator . -i www\\.cloudflare\\.com/learning/dns/what-is-dns/ -i twitter\\.com/jacobrossi/status/591435377291866112 -f igm",
"lint:packages": "yarn workspaces run lint",
"lint:scripts": "eslint scripts release --cache --ext js --ext ts --report-unused-disable-directives",
"release": "npm run clean:packages && npm run build:scripts && node dist/release/main.js",
@@ -61,6 +61,7 @@ you will be warned when a hint is going to be ignored
for a connector.

e.g.

```text
Warning: The hint "babel-config/is-valid" will be ignored for the connector "puppeteer"
```
@@ -0,0 +1,12 @@
import { Category } from 'hint/dist/src/lib/enums/category';

import metas from '../../shared/metas.import';

/**
* Returns a list with all the hint categories.
*/
export const getCategories = () => {
return [...new Set(metas.map((meta) => {
return (meta.docs && meta.docs.category || Category.other);
}))].sort();
};
@@ -94,9 +94,9 @@ const App = (props: Props) => {
case Page.Config:
return <ConfigPage disabled={isAnalyzing} onStart={onStart}/>;
case Page.Error:
return <ErrorPage disabled={isAnalyzing} error={error} onConfigure={onConfigure} onRestart={onRestart}/>;
return <ErrorPage config={config} disabled={isAnalyzing} error={error} onConfigure={onConfigure} onRestart={onRestart}/>;
case Page.Results:
return <ResultsPage disabled={isAnalyzing} results={results} onConfigure={onConfigure} onRestart={onRestart}/>;
return <ResultsPage disabled={isAnalyzing} config={config} results={results} onConfigure={onConfigure} onRestart={onRestart}/>;
default:
throw new Error(`Unknown page: ${page}`);
}
@@ -1,18 +1,75 @@
import * as React from 'react';
import { useState, useEffect } from 'react';

import { getMessage } from '../../utils/i18n';
import { Config, ErrorData } from '../../../shared/types';

import ExternalLink from './external-link';
import { evaluate } from '../../utils/inject';
import { getCategories } from '../../utils/categories';
import escapeRegExp = require('lodash/escapeRegExp');
import { getCategoryName } from '@hint/utils/dist/src/i18n';

const openIssueUrl = 'https://github.com/webhintio/hint/issues/new?labels=type%3Abug&amp;template=2-bug-report-browser.md&amp;title=%5BBug%5D+Bug+description';
const categories = getCategories();

const { version } = require('../../../manifest.json');
let template = require('../../../../../../../.github/ISSUE_TEMPLATE/2-bug-report-browser.md').default;

// Remove frontMatter from template.
template = template.replace(/---([\s\S]*)---/gm, '').trim();

type Props = {
config: Config;
error?: ErrorData;
children?: any;
}

const labels = 'type:bug';
const title = '[Bug] Bug description';

/**
* Link to github to give feedback.
*/
const FeedbackLink = () => {
const FeedbackLink = ({ config, error, children }: Props) => {
const [issueUrl, setIssueUrl] = useState('');

useEffect(() => {
const disabledCategories = config.disabledCategories || [];
const browserslists = config.browserslist || '';
const ignoredUrls = config.ignoredUrls;

let body = template
.replace('__webhint version:__', `__webhint version:__ ${version}`)
.replace('__Browser version:__', `__Browser version:__ ${navigator.userAgent}`)
.replace('[x] Recommended settings', `[${!browserslists ? 'x' : ' '}] Recommended settings`)
.replace('[ ] Custom: <!-- Custom target browsers -->', `[${browserslists ? 'x' : ' '}] Custom: ${browserslists ? browserslists : ''} <!-- Custom target browsers -->`);

for (const category of categories) {
body = body.replace(`[x] ${getCategoryName(category)}`, `[${disabledCategories.includes(category) ? ' ' : 'x'}] ${getCategoryName(category)}`);
}

if (error) {
body = body.replace('<!-- ✍️ Paste the error details here -->', `${error.message}\n${error.stack}`);
}

evaluate('window.location', (loc) => {
const origin = loc.origin;
const noIgnored = ignoredUrls === undefined;
const isSameOrigin = !noIgnored && (ignoredUrls === '--webhint-third-party' || ignoredUrls === `^(?!${escapeRegExp(origin)})`);
const isCustom = !noIgnored && !isSameOrigin;

body = body.replace('[x] None', `* [${noIgnored ? 'x' : ' '}] None`)
.replace('[ ] Different origin', `* [${isSameOrigin ? 'x' : ' '}] Different origin`)
.replace('[ ] Custom: <!-- Custom ignored resources -->', `* [${isCustom ? 'x' : ' '}] Custom: ${isCustom ? ignoredUrls : ''} <!-- Custom ignored resources -->`);
body = body.replace('`__URL for which webhint failed:__', `__URL for which webhint failed:__ ${loc.href}`);

setIssueUrl(`https://github.com/webhintio/hint/issues/new?labels=${encodeURIComponent(labels)}&template=2-bug-report-browser.md&body=${encodeURIComponent(body)}&title=${encodeURIComponent(title)}`);
});
});

return (
<ExternalLink href={openIssueUrl}>
{getMessage('feedback')}
<ExternalLink href={issueUrl}>
{children ? children : getMessage('feedback')}
</ExternalLink>
);
};
@@ -71,7 +71,7 @@ const ConfigPage = ({ disabled, onStart }: Props) => {

return (
<Page className={styles.root} disabled={disabled} onAction={onAnalyzeClick}>
<ConfigHeader />
<ConfigHeader config={config} />
<main>
<div className={styles.categories}>
<CategoriesConfig disabled={config.disabledCategories} onChange={onCategoriesChange} />
@@ -4,16 +4,21 @@ import { getMessage } from '../../../utils/i18n';

import Button from '../../controls/button';
import FeedbackLink from '../../controls/feedback-link';
import { Config } from '../../../../shared/types';

import * as styles from './header.css';

const ConfigHeader = () => {
type Props = {
config: Config;
}

const ConfigHeader = ({ config }: Props) => {
return (
<header className={styles.root}>
<h1 className={styles.help}>
{getMessage('checkForBestPracticesDescription')}
</h1>
<FeedbackLink />
<FeedbackLink config={config} />
<Button type="submit" primary={true}>
{getMessage('startScanButtonLabel')}
</Button>
@@ -1,12 +1,10 @@
import * as React from 'react';
import { useCallback, FormEvent } from 'react';

import { Category } from 'hint/dist/src/lib/enums/category';
import { getCategoryName } from '@hint/utils/dist/src/i18n/get-category-name';

import metas from '../../../../../shared/metas.import';

import { getMessage } from '../../../../utils/i18n';
import { getCategories } from '../../../../utils/categories';

import Checkbox from '../../../controls/checkbox';
import LabelText from '../../../controls/label-text';
@@ -22,10 +20,7 @@ type Props = {
onChange: (disabled?: string[]) => void;
};

// Extract category names from bundled hint metadata.
const categories = [...new Set(metas.map((meta) => {
return (meta.docs && meta.docs.category || Category.other);
}))].sort();
const categories = getCategories();

/**
* Display options to include/exclude entire categories of hints from a scan.
@@ -1,18 +1,16 @@
import * as React from 'react';

import { ErrorData } from '../../../shared/types';
import { ErrorData, Config } from '../../../shared/types';

import { getMessage } from '../../utils/i18n';

import Button from '../controls/button';
import ExternalLink from '../controls/external-link';
import FeedbackLink from '../controls/feedback-link';
import Page from '../page';
import Summary from '../controls/summary';

import * as styles from './error.css';

const openIssueUrl = 'https://github.com/webhintio/hint/issues/new?labels=type%3Abug&amp;template=2-bug-report-browser.md&amp;title=%5BBug%5D+Bug+description';

type Props = {
disabled?: boolean;

@@ -24,12 +22,15 @@ type Props = {

/** The error that occured when the scan failed. */
error: ErrorData;

/** Configuration used for the analysis. */
config: Config;
};

/**
* Display an error which occured during a scan.
*/
const ErrorPage = ({ disabled, error, onConfigure, onRestart }: Props) => {
const ErrorPage = ({ disabled, error, onConfigure, onRestart, config }: Props) => {
return (
<Page disabled={disabled} onAction={onRestart}>
<section className={styles.content}>
@@ -39,9 +40,9 @@ const ErrorPage = ({ disabled, error, onConfigure, onRestart }: Props) => {
</h1>
<p>
{getMessage('errorMessage')}
<ExternalLink href={openIssueUrl}>
<FeedbackLink config={config} error={error}>
{getMessage('openAnIssue')}
</ExternalLink>
</FeedbackLink>
</p>
<div className={styles.actions}>
<Button type="submit" primary={true}>
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useState } from 'react';

import { Results as ResultsData } from '../../../shared/types';
import { Results as ResultsData, Config } from '../../../shared/types';

import PoweredBy from '../powered-by';
import Page from '../page';
@@ -12,6 +12,9 @@ import ResultsHeader from './results/header';
import * as styles from './results.css';

type Props = {
/** Configuration used for the analysis. */
config: Config;

disabled?: boolean;

/** Listener for when the user decides to configure a new scan. */
@@ -27,7 +30,7 @@ type Props = {
/**
* Display problems reported by a scan.
*/
const ResultsPage = ({ disabled, onConfigure, onRestart, results }: Props) => {
const ResultsPage = ({ config, disabled, onConfigure, onRestart, results }: Props) => {
const [showPassed, setShowPassed] = useState(true);

const shownCategories = results.categories.filter((category) => {
@@ -36,7 +39,7 @@ const ResultsPage = ({ disabled, onConfigure, onRestart, results }: Props) => {

return (
<Page className={styles.root} disabled={disabled} onAction={onRestart}>
<ResultsHeader showPassed={showPassed} url={results.url} onConfigureClick={onConfigure} setShowPassed={setShowPassed} />
<ResultsHeader showPassed={showPassed} url={results.url} onConfigureClick={onConfigure} setShowPassed={setShowPassed} config={config} />
<div className={styles.results}>
<nav className={styles.nav}>
<ul className={styles.summary}>
@@ -8,17 +8,19 @@ import FeedbackLink from '../../controls/feedback-link';
import Label from '../../controls/label';
import LabelText from '../../controls/label-text';
import Toggle from '../../controls/toggle';
import { Config } from '../../../../shared/types';

import * as styles from './header.css';

type Props = {
config: Config;
onConfigureClick: () => void;
setShowPassed: (showPassed: boolean) => void;
showPassed: boolean;
url: string;
};

const ResultsHeader = ({ onConfigureClick, showPassed, setShowPassed, url }: Props) => {
const ResultsHeader = ({ config, onConfigureClick, showPassed, setShowPassed, url }: Props) => {

const onShowPassedChange = useCallback((event: FormEvent<HTMLInputElement>) => {
const input = (event.target as HTMLInputElement);
@@ -32,7 +34,7 @@ const ResultsHeader = ({ onConfigureClick, showPassed, setShowPassed, url }: Pro
<h1 className={`${styles.title} ${styles.headerText}`}>
{getMessage('scanResultTitle')}
</h1>
<FeedbackLink />
<FeedbackLink config={config}/>
</div>
<div className={styles.headerText}>
{getMessage('targetUrl', url)}
@@ -26,12 +26,15 @@ const mockExtensionAPIs = (results: Results) => {

(window as any).browser = {
devtools: {
inspectedWindow: { tabId: 1 },
inspectedWindow: {
eval() { },
tabId: 1
},
network: {
getHAR: () => {},
getHAR: () => { },
onRequestFinished: {
addListener: () => {},
removeListener: () => {}
addListener: () => { },
removeListener: () => { }
}
},
panels: { themeName: 'dark' }
@@ -1,7 +1,9 @@
(function() {
window.browser = {
devtools: {
inspectedWindow: { tabId: 1 },
inspectedWindow: {
eval() {},
tabId: 1 },
network: {
getHAR: () => {},
onRequestFinished: {
@@ -48,6 +48,10 @@ module.exports = (env) => {
loader: 'svg-url-loader',
options: { noquotes: true }
}
},
{
test: /\.md$/,
use: 'raw-loader'
}
]
},

0 comments on commit f4ce80c

Please sign in to comment.
You can’t perform that action at this time.