Files
freeCodeCamp/tools/contributor/dashboard-app/client/src/components/Pareto.js
Oliver Eyton-Williams c8d7f0a782 feat(tools): remove eslint-plugin-prettier for prettier (#42438)
* feat: remove eslint-plugin-prettier for prettier

This removes the annoying lint warnings when all that needs to change is
formatting

* fix: use .js lint-staged config to ignore properly

* fix: lint everything if a lot of files are changed

It's faster than making lots of individual linter calls

* chore: apply prettier

* fix: ignore code in curriculum-file-structure
2021-10-06 21:02:21 +05:30

238 lines
6.7 KiB
JavaScript

import React from 'react';
import styled from 'styled-components';
import ListItem from './ListItem';
import FullWidthDiv from './FullWidthDiv';
import Result from './Result';
import FilterOption from './FilterOption';
import { ENDPOINT_PARETO } from '../constants';
const List = styled.div`
margin: 5px;
display: flex;
flex-direction: column;
`;
const Options = styled.div`
display: flex;
`;
const detailsStyle = { padding: '3px' };
const filenameTitle = { fontWeight: '600' };
class Pareto extends React.Component {
state = {
data: [],
all: [],
selectedFileType: 'all',
selectedLanguage: 'all',
options: {},
rateLimitMessage: ''
};
componentDidMount() {
fetch(ENDPOINT_PARETO)
.then((response) => response.json())
.then(({ ok, rateLimitMessage, pareto }) => {
if (ok) {
if (!pareto.length) {
pareto.push({
filename: 'Nothing to show in Pareto Report',
count: 0,
prs: []
});
}
this.setState((prevState) => ({
data: pareto,
all: [...pareto],
options: this.createOptions(pareto)
}));
} else if (rateLimitMessage) {
this.setState((prevState) => ({
rateLimitMessage
}));
}
})
.catch(() => {
const pareto = [
{ filename: 'Nothing to show in Pareto Report', count: 0, prs: [] }
];
this.setState((prevState) => ({ data: pareto }));
});
}
createOptions = (data) => {
const options = data.reduce((seen, { filename }) => {
const { articleType, language } = this.getFilenameOptions(filename);
if (articleType && language) {
if (!seen.hasOwnProperty(articleType)) {
seen[articleType] = {};
}
seen[articleType][language] = true;
}
return seen;
}, {});
return options;
};
handleFileTypeOptionChange = (changeEvent) => {
let { all, selectedLanguage, options } = this.state;
const selectedFileType = changeEvent.target.value;
let data = [...all].filter(({ filename }) => {
const { articleType, language } = this.getFilenameOptions(filename);
let condition;
if (selectedFileType === 'all') {
condition = true;
selectedLanguage = 'all';
} else {
if (selectedLanguage === 'all') {
condition = articleType === selectedFileType;
} else if (!options[selectedFileType][selectedLanguage]) {
condition = articleType === selectedFileType;
selectedLanguage = 'all';
} else {
condition =
articleType === selectedFileType && language === selectedLanguage;
}
}
return condition;
});
this.setState((prevState) => ({
data,
selectedFileType,
selectedLanguage
}));
};
handleLanguageOptionChange = (changeEvent) => {
const { all, selectedFileType } = this.state;
const selectedLanguage = changeEvent.target.value;
let data = [...all].filter(({ filename }) => {
const { articleType, language } = this.getFilenameOptions(filename);
let condition;
if (selectedLanguage === 'all') {
condition = articleType === selectedFileType;
} else {
condition =
language === selectedLanguage && articleType === selectedFileType;
}
return condition;
});
this.setState((prevState) => ({ data, selectedLanguage }));
};
getFilenameOptions = (filename) => {
const filenameReplacement = filename.replace(
/^curriculum\/challenges\//,
'curriculum/'
);
const regex =
/^(docs|curriculum|guide)(?:\/)(english|arabic|chinese|portuguese|russian|spanish)?\/?/;
// need an array to pass to labelsAdder
// eslint-disable-next-line
const [_, articleType, language] = filenameReplacement.match(regex) || [];
return { articleType, language };
};
render() {
const {
data,
options,
selectedFileType,
selectedLanguage,
rateLimitMessage
} = this.state;
const elements = rateLimitMessage
? rateLimitMessage
: data.map((entry) => {
const { filename, count, prs } = entry;
const prsList = prs.map(({ number, username, title }) => {
return (
<ListItem
key={number}
number={number}
username={username}
prTitle={title}
/>
);
});
const fileOnMain = `https://github.com/freeCodeCamp/freeCodeCamp/blob/main/${filename}`;
return (
<Result key={filename}>
<span style={filenameTitle}>{filename}</span>{' '}
<a href={fileOnMain} rel="noopener noreferrer" target="_blank">
(File on Main)
</a>
<br />
<details style={detailsStyle}>
<summary># of PRs: {count}</summary>
<List>{prsList}</List>
</details>
</Result>
);
});
let fileTypeOptions = Object.keys(options).map(
(articleType) => articleType
);
const typeOptions = ['all', ...fileTypeOptions].map((type) => (
<FilterOption
key={type}
name="filetype"
value={type}
onOptionChange={this.handleFileTypeOptionChange}
selectedOption={selectedFileType}
>
{type.charAt().toUpperCase() + type.slice(1)}
</FilterOption>
));
let languageOptions = null;
if (selectedFileType !== 'all') {
let languages = Object.keys(options[selectedFileType]);
languages = ['all', ...languages.sort()];
languageOptions = languages.map((language) => (
<FilterOption
key={language}
name="language"
value={language}
onOptionChange={this.handleLanguageOptionChange}
selectedOption={selectedLanguage}
>
{language.charAt().toUpperCase() + language.slice(1)}
</FilterOption>
));
}
return (
<FullWidthDiv>
{fileTypeOptions.length > 0 && <strong>Filter Options</strong>}
<Options>
{fileTypeOptions.length > 0 && (
<>
<fieldset>
<legend>File Type:</legend>
<div>{typeOptions}</div>
</fieldset>
</>
)}
{languageOptions && (
<fieldset>
<legend>Language:</legend>
<div>{languageOptions}</div>
</fieldset>
)}
</Options>
{rateLimitMessage
? rateLimitMessage
: data.length
? elements
: 'Report Loading...'}
</FullWidthDiv>
);
}
}
export default Pareto;