Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/Constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IExtension } from './Interfaces';

export const definedExtensions:Record<string, IExtension> = {
'.AppImage': {
name: 'Linux',
color: '#A88C46'
},
'.exe': {
name: 'Windows',
color: '#F2C62E'
},
'.dmg': {
name: 'Mac',
color: '#E27827'
},
'.vsix': {
name: 'Visual Studio extensions',
color: '#F2C62E'
}
};
5 changes: 5 additions & 0 deletions src/Interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export interface IExtension {
Comment on lines +1 to +2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export interface IExtension {
export interface IExtension {

Or, in generally, run prettier :)

name: string,
color: string
}
136 changes: 56 additions & 80 deletions src/Pages/Stat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import {
} from '@material-ui/core';
import { red } from '@material-ui/core/colors';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
import Header from '../../Components/Header';
import * as Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import Header from '../../Components/Header';
import { definedExtensions } from '../../Constants';
import { IExtension } from '../../Interfaces';

const default_options: Highcharts.Options = {
chart: {
Expand Down Expand Up @@ -107,103 +109,76 @@ interface IProps {
history: any
}

interface IExtension {
name: string,
color: string
}

const validExt:Record<string, IExtension> = {
'.AppImage': {
name: 'Linux',
color: '#A88C46'
},
'.exe': {
name: 'Windows',
color: '#F2C62E'
},
'.dmg': {
name: 'Mac',
color: '#E27827'
}
};

const nameFilter = (name:string) => (Object.keys(validExt).find(x => name.indexOf(x) !== -1) || '');
const nameFilter = (name:string) => (Object.keys(definedExtensions).find(x => name.indexOf(x) !== -1) || '');
const Stat: React.FC<IProps> = ({ match, history }) => {
const classes = useStyles();
const [isLoading, setIsLoading] = React.useState(false);
const [releases, setReleases] = React.useState([]);
const [chartOption, setChartOption] = React.useState(default_options);
const [model, setModel] = React.useState({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the next version, try to set its type (to avoid anys later)

loading: false,
user: '',
repo: '',
avatar: '',
version: 0,
data: [[]]
releases: []
});
const [chartOption, setChartOption] = React.useState(default_options);

const handleBack = () => history.push('/');
const handleReleaseChange = (event: React.ChangeEvent<{ value: unknown }>) => prepareAsset(event.target.value as number);

const handleVersionChange = (event: React.ChangeEvent<{ value: unknown }>) => prepareAsset(event.target.value as number);

const prepareAsset = (id:number) => {
const release:any = releases.find((item:any) => item.id === id);

if (release) {
prepareChartData(id, release.author.avatar_url, release.assets);
}
}

const prepareChartData = (id:number, avatar:string, assets:any) => {
const { user, repo } = match.params;
const fetchReleases = (user:string, repo: string) => {
setModel(prevStat => ({
...prevStat,
loading: true,
}));
fetch(`https://api.github.com/repos/${user}/${repo}/releases`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider converting it to async / await

.then(res => res.json())
.then(releases => {
setModel(prevStat => ({
...prevStat,
user: user,
repo: repo,
avatar: releases.length ? releases[0].author.avatar_url : null,
releases: releases
}));
},
error => setModel(prevStat=>({ ...prevStat, loading: false }))
)
};
const prepareAsset = (release_id:number) => {
const release:any = model.releases.find(({ id }) => id === release_id);
if (!release) {return;}

const data = assets
const data = release.assets
.filter((item:any) => (!item.name.includes('.exe.blockmap') && nameFilter(item.name)))
.map((item:any) => {
const extension_name:string = nameFilter(item.name);
const extension:IExtension = validExt[extension_name];
const extension:IExtension = definedExtensions[extension_name];
return {
name: (extension.name || item.ext),
y: item.download_count,
color: (extension.color || '#34595A')
};
});

setChartOption(prevStat => ({
...prevStat,
xAxis: {
categories: data.map(({ name }: { name: string}) => name)
},
series: [{
type: 'column',
name: 'Download',
data: data.map(({y, color}: { y: number, color: string}) => ({ y, color }))
}]
}));

setModel({
user: user,
repo: repo,
avatar: avatar,
version: id,
data: [
['OS', 'Download', { role: "style" }],
...data
]
});
setIsLoading(false);
setChartOption(prevStat => ({
...prevStat,
xAxis: {
categories: data.map(({ name }: { name: string}) => name)
},
series: [{
type: 'column',
name: 'Download',
data: data.map(({y, color}: { y: number, color: string}) => ({ y, color }))
}]
}));
setModel(prevStat => ({
...prevStat,
version: release_id,
loading: false
}));
}


const fetchReleases = (user:string, repo: string) => {
setIsLoading(true);
fetch(`https://api.github.com/repos/${user}/${repo}/releases`)
.then(res => res.json())
.then(
result => setReleases(result),
error => setIsLoading(false)
)
};

React.useEffect(()=> {
const { user, repo } = match.params;

Expand All @@ -214,18 +189,19 @@ const Stat: React.FC<IProps> = ({ match, history }) => {
}, [match.params.user, match.params.repo]);

React.useEffect(()=> {
if (releases && releases.length){
const release:any = releases[0];
prepareAsset(release.id);
if (model.releases && model.releases.length){
const { id } = model.releases[0];
prepareAsset(id);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [releases.length]);
}, [model.releases]);


return (
<Container className={classes.root} maxWidth="md">
<Header />
{
isLoading
model.loading
? (<Grid container justify="center">
<CircularProgress />
</Grid>)
Expand All @@ -252,9 +228,9 @@ const Stat: React.FC<IProps> = ({ match, history }) => {
labelId="demo-simple-select-label"
id="demo-simple-select"
value={model.version}
onChange={handleVersionChange}
onChange={handleReleaseChange}
>
{releases.map((item:any)=> (<MenuItem key={item.id} value={item.id}>{item.name}</MenuItem>))}
{model.releases.map((item:any)=> (<MenuItem key={item.id} value={item.id}>{item.name}</MenuItem>))}
</Select>
</FormControl>
</>
Expand Down