add ASU compatibility
51
.eslintrc.js
|
|
@ -1,42 +1,31 @@
|
|||
module.exports = {
|
||||
extends: [
|
||||
'airbnb-typescript',
|
||||
'airbnb/hooks',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:jest/recommended',
|
||||
'prettier',
|
||||
'prettier/react',
|
||||
'prettier/@typescript-eslint',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
plugins: ['react', '@typescript-eslint', 'jest'],
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
jest: true,
|
||||
},
|
||||
globals: {
|
||||
Atomics: 'readonly',
|
||||
SharedArrayBuffer: 'readonly',
|
||||
},
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
parser: '@typescript-eslint/parser', // Specifies the ESLint parserx
|
||||
plugins: ['react-hooks', 'prettier'],
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
|
||||
},
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
extends: [
|
||||
'plugin:react/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended', // Make sure this is always the last configuration in the extends array.
|
||||
'plugin:jest/recommended',
|
||||
],
|
||||
rules: {
|
||||
'linebreak-style': 'off',
|
||||
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
|
||||
// Consider turning on eventually... lots of warnings though.
|
||||
'max-len': ['error', 100],
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
// This rule is redundent when using arrow functions and we should only use arrow functions
|
||||
'react/prop-types': 'off',
|
||||
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
trailingComma: 'all',
|
||||
arrowParens: 'always',
|
||||
printWidth: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,12 +13,14 @@
|
|||
"i18next": "^17.0.4",
|
||||
"i18next-browser-languagedetector": "^3.0.1",
|
||||
"lodash": "^4.17.20",
|
||||
"luxon": "^1.26.0",
|
||||
"match-sorter": "^6.1.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-i18next": "^10.11.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "4.0.1",
|
||||
"react-svg": "^12.1.0",
|
||||
"react-use": "^15.3.8",
|
||||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
|
|
@ -50,6 +52,7 @@
|
|||
"@testing-library/react": "^11.2.3",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/lodash": "^4.14.167",
|
||||
"@types/luxon": "^1.26.2",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
|
|
@ -57,15 +60,10 @@
|
|||
"@typescript-eslint/parser": "^4.12.0",
|
||||
"axios-mock-adapter": "^1.19.0",
|
||||
"eslint": "7.2.0",
|
||||
"eslint-config-airbnb": "18.2.1",
|
||||
"eslint-config-airbnb-typescript": "^12.0.0",
|
||||
"eslint-config-prettier": "^7.1.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jest": "^24.1.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-react": "^7.21.5",
|
||||
"eslint-plugin-react-hooks": "4.0.0",
|
||||
"husky": "^3.0.5",
|
||||
"jest": "^26.6.3",
|
||||
"prettier": "^2.2.1",
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 54 KiB |
22
src/App.scss
|
|
@ -46,6 +46,18 @@
|
|||
}
|
||||
|
||||
.header {
|
||||
.logo {
|
||||
height: 40px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
|
||||
& svg {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.title-desktop {
|
||||
@media all and (max-width: 820px) {
|
||||
display: none;
|
||||
|
|
@ -74,7 +86,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 800px) {
|
||||
.mobile {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 800px) {
|
||||
.desktop {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.report-problem-container {
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
|
|
|
|||
41
src/App.tsx
|
|
@ -13,12 +13,47 @@ import Footer from './components/Footer';
|
|||
const theme = createMuiTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: '#3F51B5',
|
||||
main: '#00B5E2',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
secondary: {
|
||||
main: '#009688',
|
||||
main: '#212322',
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
h1: {
|
||||
fontWeight: 600,
|
||||
},
|
||||
h2: {
|
||||
fontWeight: 600,
|
||||
},
|
||||
h3: {
|
||||
fontWeight: 600,
|
||||
},
|
||||
h4: {
|
||||
fontWeight: 600,
|
||||
},
|
||||
h5: {
|
||||
fontWeight: 600,
|
||||
},
|
||||
h6: {
|
||||
fontWeight: 600,
|
||||
},
|
||||
fontFamily: [
|
||||
'Open Sans',
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'Segoe UI',
|
||||
'Roboto',
|
||||
'Oxygen',
|
||||
'Ubuntu',
|
||||
'Cantarell',
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
,
|
||||
].join(','),
|
||||
},
|
||||
});
|
||||
|
||||
const App: FunctionComponent = () => {
|
||||
|
|
@ -30,7 +65,7 @@ const App: FunctionComponent = () => {
|
|||
<Router>
|
||||
<Switch>
|
||||
<Route path="" exact component={Home} />
|
||||
<Route default component={NotFound} />
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
</Router>
|
||||
<Footer />
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import React from 'react';
|
||||
import { fireEvent, render, RenderResult, waitFor } from '@testing-library/react';
|
||||
|
||||
import Header from './Header';
|
||||
import Header from '.';
|
||||
|
||||
const mockChangeLanguage = jest.fn();
|
||||
|
||||
|
|
@ -11,9 +11,11 @@ import {
|
|||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ReactSVG } from 'react-svg';
|
||||
|
||||
import locales from '../locales';
|
||||
import '../App.scss';
|
||||
import logo from '../../images/logo-white.svg';
|
||||
import locales from '../../locales';
|
||||
import '../../App.scss';
|
||||
|
||||
const Header: FunctionComponent = () => {
|
||||
const { t, i18n } = useTranslation();
|
||||
|
|
@ -32,8 +34,10 @@ const Header: FunctionComponent = () => {
|
|||
return (
|
||||
<AppBar position="sticky" className="header">
|
||||
<Toolbar>
|
||||
<Typography variant="h6">{t('tr-title')}</Typography>
|
||||
<span className="title-mobile">{t('tr-title')}</span>
|
||||
<ReactSVG src={logo} className="logo" />
|
||||
<Typography variant="h5" component="div">
|
||||
{t('tr-title')}
|
||||
</Typography>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
<Box position="relative">
|
||||
<Button
|
||||
|
|
@ -5,10 +5,10 @@ const config = {
|
|||
show_help: true,
|
||||
|
||||
// Path to overview.json file or URL to the ASU API
|
||||
versions: { '19.07.5': 'data/19.07.5', SNAPSHOT: 'data/SNAPSHOT' },
|
||||
versions: { '19.07.7': 'data/19.07.7', SNAPSHOT: 'data/SNAPSHOT' },
|
||||
|
||||
// Pre-selected version (optional)
|
||||
default_version: '19.07.5',
|
||||
default_version: '19.07.7',
|
||||
|
||||
// Image download URL (optional)
|
||||
image_url: 'https://downloads.openwrt.org/releases/{version}/targets/{target}',
|
||||
|
|
@ -18,7 +18,7 @@ const config = {
|
|||
|
||||
// Build custom images (optional)
|
||||
// See https://github.com/aparcar/asu
|
||||
// asu_url: 'https://chef.libremesh.org'
|
||||
asu_url: 'https://chef.libremesh.org',
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,16 @@ import React, { FunctionComponent, ReactNode, useCallback, useEffect, useState }
|
|||
import {
|
||||
Box,
|
||||
Button,
|
||||
Chip,
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
Grid,
|
||||
IconButton,
|
||||
Input,
|
||||
InputAdornment,
|
||||
InputLabel,
|
||||
Link,
|
||||
makeStyles,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
|
|
@ -12,15 +20,26 @@ import {
|
|||
TableRow,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { Launch, CloudDownload } from '@material-ui/icons';
|
||||
import Axios from 'axios';
|
||||
import { Launch, CloudDownload, Add } from '@material-ui/icons';
|
||||
import axios from 'axios';
|
||||
import { isEqual } from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { ProfilesEntity } from '../../../types/overview';
|
||||
import { Profile, TitlesEntity } from '../../../types/profile';
|
||||
import config from '../../../config';
|
||||
import { getTitle } from '../utils/title';
|
||||
import asu from '../../../utils/asu';
|
||||
import { GetBuildResponse } from '../../../types/asu';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
chip: {
|
||||
'&:focus': {
|
||||
border: `2px solid #000`,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
type Props = {
|
||||
selectedVersion: string;
|
||||
|
|
@ -30,7 +49,15 @@ type Props = {
|
|||
const profilesData: { [key: string]: Profile } = {};
|
||||
|
||||
const ProfileDetails: FunctionComponent<Props> = ({ selectedVersion, selectedProfile }) => {
|
||||
const [profile, setProfileData] = useState<Profile>();
|
||||
const classes = useStyles();
|
||||
const [profile, setProfile] = useState<Profile>();
|
||||
const [showAddPackages, setShowAddPackages] = useState(false);
|
||||
const [customPackages, setCustomPackages] = useState<Set<string>>(new Set());
|
||||
const [customPackagesInputValue, setCustomPackagesInputValue] = useState<string>('');
|
||||
const [showPackageExistsError, setShowPackageExistsError] = useState(false);
|
||||
const [buildStatus, setBuildStatus] = useState<React.ReactNode>();
|
||||
const [buildResponse, setBuildResponse] = useState<GetBuildResponse>();
|
||||
const [buildError, setBuildError] = useState<string>();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getHelpKey = (type: string) => {
|
||||
|
|
@ -56,12 +83,18 @@ const ProfileDetails: FunctionComponent<Props> = ({ selectedVersion, selectedPro
|
|||
return 'other-help';
|
||||
};
|
||||
|
||||
const preExistingPackages = (_profile = profile) =>
|
||||
Array.from(
|
||||
new Set([...(_profile?.default_packages || []), ...(_profile?.device_packages || [])])
|
||||
);
|
||||
|
||||
const getProfileData = useCallback(async () => {
|
||||
let profileData = profilesData[selectedProfile.id];
|
||||
|
||||
if (!profileData) {
|
||||
const response = await Axios.get<Profile>(
|
||||
`${process.env.PUBLIC_URL}/data/${selectedVersion}/${selectedProfile.target}/${selectedProfile.id}.json`
|
||||
const response = await axios.get<Profile>(
|
||||
`${process.env.PUBLIC_URL}/data/${selectedVersion}` +
|
||||
`/${selectedProfile.target}/${selectedProfile.id}.json`
|
||||
);
|
||||
profileData = response.data;
|
||||
profilesData[selectedProfile.id] = profileData;
|
||||
|
|
@ -73,7 +106,10 @@ const ProfileDetails: FunctionComponent<Props> = ({ selectedVersion, selectedPro
|
|||
useEffect(() => {
|
||||
let mounted = true;
|
||||
getProfileData().then((_profileData) => {
|
||||
if (mounted && !isEqual(profile, _profileData)) setProfileData(_profileData);
|
||||
if (mounted && !isEqual(profile, _profileData)) {
|
||||
setProfile(_profileData);
|
||||
setCustomPackages(new Set(preExistingPackages(_profileData)));
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
|
|
@ -81,14 +117,64 @@ const ProfileDetails: FunctionComponent<Props> = ({ selectedVersion, selectedPro
|
|||
};
|
||||
}, [selectedVersion, selectedProfile, getProfileData, profile]);
|
||||
|
||||
const toggleAddPackages = () => {
|
||||
if (!profile) return;
|
||||
setShowAddPackages(!showAddPackages);
|
||||
setCustomPackages(new Set(preExistingPackages()));
|
||||
};
|
||||
|
||||
const appendAddPackageInput = (
|
||||
e?: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
if (((e && e.key === 'Enter') || !e) && customPackagesInputValue) {
|
||||
setCustomPackages((prev) => {
|
||||
setShowPackageExistsError(false);
|
||||
if (
|
||||
!profile?.device_packages?.includes(customPackagesInputValue) &&
|
||||
!profile?.default_packages?.includes(customPackagesInputValue)
|
||||
) {
|
||||
return new Set(prev.add(customPackagesInputValue));
|
||||
}
|
||||
setShowPackageExistsError(true);
|
||||
return prev;
|
||||
});
|
||||
setCustomPackagesInputValue('');
|
||||
}
|
||||
};
|
||||
|
||||
const onBuildStatusChange = (status: string) => {
|
||||
setBuildStatus(status);
|
||||
};
|
||||
|
||||
if (!profile) return <CircularProgress />;
|
||||
|
||||
const buildAt = new Date(profile.build_at);
|
||||
const buildCustomImage = async () => {
|
||||
setBuildStatus('Please wait...');
|
||||
try {
|
||||
const response = await asu.build(
|
||||
Array.from(customPackages.values()),
|
||||
profile.id,
|
||||
profile.version_number,
|
||||
onBuildStatusChange
|
||||
);
|
||||
setBuildResponse(response);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
setBuildError(e.response.data.message);
|
||||
}
|
||||
setBuildStatus(undefined);
|
||||
};
|
||||
|
||||
const buildAt = DateTime.fromFormat(profile.build_at, 'yyyy-MM-dd TT').toLocaleString(
|
||||
DateTime.DATETIME_MED
|
||||
);
|
||||
const hasAbilityToBuildCustomPackages = Object.keys(config).includes('asu_url');
|
||||
const canBuild = !isEqual(Array.from(customPackages.values()), preExistingPackages());
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box paddingTop={3} paddingBottom={2}>
|
||||
<Typography variant="h6" component="h1" align="left">
|
||||
<Typography variant="h5" component="h3" align="left">
|
||||
{t('tr-version-build')}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
|
@ -150,7 +236,7 @@ const ProfileDetails: FunctionComponent<Props> = ({ selectedVersion, selectedPro
|
|||
</Table>
|
||||
</TableContainer>
|
||||
<Box paddingTop={3} paddingBottom={2}>
|
||||
<Typography variant="h6" component="h1" align="left">
|
||||
<Typography variant="h5" component="h3" align="left">
|
||||
{t('tr-downloads')}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
|
@ -188,6 +274,182 @@ const ProfileDetails: FunctionComponent<Props> = ({ selectedVersion, selectedPro
|
|||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Box paddingTop={3} paddingBottom={2}>
|
||||
<Typography variant="h5" component="h3" align="left">
|
||||
{t('Packages')}
|
||||
</Typography>
|
||||
</Box>
|
||||
{profile.default_packages && profile.default_packages.length > 0 && (
|
||||
<Box mb={2}>
|
||||
<Typography variant="h6" align="left">
|
||||
{t('Default Packages')}
|
||||
</Typography>
|
||||
{profile.default_packages?.join(', ')}
|
||||
</Box>
|
||||
)}
|
||||
{profile.device_packages && profile.device_packages.length > 0 && (
|
||||
<Box mb={2}>
|
||||
<Typography variant="h6" align="left">
|
||||
{t('Device Packages')}
|
||||
</Typography>
|
||||
{profile.device_packages.join(', ')}
|
||||
</Box>
|
||||
)}
|
||||
{hasAbilityToBuildCustomPackages && (
|
||||
<Box>
|
||||
{!showAddPackages && (
|
||||
<Button variant="outlined" size="small" onClick={toggleAddPackages}>
|
||||
customize packages
|
||||
</Button>
|
||||
)}
|
||||
{showAddPackages && (
|
||||
<>
|
||||
<Typography variant="h6" align="left">
|
||||
{t('Customize Packages')}
|
||||
<Box display="inline-block" ml={2}>
|
||||
<Link href="https://openwrt.org/packages/table/start" target="_blank">
|
||||
<Typography variant="caption">find packages index on this page</Typography>
|
||||
</Link>
|
||||
</Box>
|
||||
</Typography>
|
||||
<br />
|
||||
{Array.from(customPackages.values()).map((p) => {
|
||||
const isDefaultPackage = profile.default_packages?.includes(p);
|
||||
return (
|
||||
<Box key={p} pr={1} pb={1} display="inline-block">
|
||||
<Chip
|
||||
size="small"
|
||||
label={p}
|
||||
color={isDefaultPackage ? 'default' : 'primary'}
|
||||
className={classes.chip}
|
||||
onDelete={
|
||||
isDefaultPackage
|
||||
? undefined
|
||||
: () =>
|
||||
setCustomPackages((prev) => {
|
||||
const newSet = new Set(Array.from(prev.values()));
|
||||
newSet.delete(p);
|
||||
return newSet;
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
<br />
|
||||
<FormControl size="small">
|
||||
<InputLabel style={{ fontSize: '0.9em' }}>Custom Package Name</InputLabel>
|
||||
<Input
|
||||
value={customPackagesInputValue}
|
||||
onChange={(e) => e && setCustomPackagesInputValue(e.currentTarget.value)}
|
||||
onKeyUp={appendAddPackageInput}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<IconButton size="small" onClick={() => appendAddPackageInput()}>
|
||||
<Add />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
{showPackageExistsError && (
|
||||
<Box pt={2}>
|
||||
<Typography color="error" variant="caption" component="div">
|
||||
This profile already includes this package. Please try a diffrent one
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<Box mt={3}>
|
||||
{!buildStatus && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!canBuild}
|
||||
onClick={buildCustomImage}
|
||||
>
|
||||
build customized image
|
||||
</Button>
|
||||
)}
|
||||
{buildStatus && (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
alignContent="center"
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
>
|
||||
{typeof buildStatus === 'string' && (
|
||||
<Grid item>
|
||||
<CircularProgress />
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item>{buildStatus}</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
{buildError && <Typography color="error">{buildError}</Typography>}
|
||||
{buildResponse && (
|
||||
<Box mt={3}>
|
||||
<Typography variant="h5">Built Image:</Typography>
|
||||
<Table>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>Build At</TableCell>
|
||||
<TableCell id="title">
|
||||
{DateTime.fromFormat(
|
||||
buildResponse.build_at.substr(0, 25),
|
||||
'ccc, dd MMM yyyy TT',
|
||||
{
|
||||
zone: buildResponse.build_at.substr(26),
|
||||
setZone: true,
|
||||
}
|
||||
).toLocaleString(DateTime.DATETIME_MED)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<br />
|
||||
<br />
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Download link</TableCell>
|
||||
<TableCell>Help Text</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{buildResponse.images?.map((i) => {
|
||||
const downloadURL = `${config.image_url
|
||||
.replace('{target}', profile.target)
|
||||
.replace('{version}', profile.version_number)}/${i.name}`;
|
||||
return (
|
||||
<TableRow key={downloadURL + i.type}>
|
||||
<TableCell>
|
||||
<Link href={downloadURL} target="_blank" data-testid="download_link">
|
||||
<Button endIcon={<CloudDownload />} variant="contained" color="primary">
|
||||
{i.type}
|
||||
</Button>
|
||||
</Link>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Box p={1}>
|
||||
<Typography>{t(`tr-${getHelpKey(i.type)}`)}</Typography>
|
||||
<Typography variant="caption">sha256sum: {i.sha256}</Typography>
|
||||
</Box>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@ const ProfileSearch: FunctionComponent<Props> = ({ selectedVersion, onProfileCha
|
|||
toggleWorking(true);
|
||||
|
||||
if (!overview) {
|
||||
const response = await Axios.get<Overview>(
|
||||
`${process.env.PUBLIC_URL}/data/${selectedVersion}/overview.json`
|
||||
);
|
||||
const overviewPath = `${process.env.PUBLIC_URL}/data/${selectedVersion}/overview.json`;
|
||||
const response = await Axios.get<Overview>(overviewPath);
|
||||
overview = response.data;
|
||||
overviewData[selectedVersion] = overview;
|
||||
}
|
||||
|
|
|
|||
394
src/images/logo-white.svg
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="529.16669mm"
|
||||
height="162.23152mm"
|
||||
viewBox="0 0 529.16669 162.23152"
|
||||
version="1.1"
|
||||
id="svg1356"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
|
||||
sodipodi:docname="logo_full_white.svg">
|
||||
<defs
|
||||
id="defs1350">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath594">
|
||||
<path
|
||||
d="M 0,0 H 792 V 612 H 0 Z"
|
||||
id="path592" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath622">
|
||||
<path
|
||||
d="M 0,0 H 792 V 612 H 0 Z"
|
||||
id="path620" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath646">
|
||||
<path
|
||||
d="M 0,0 H 792 V 612 H 0 Z"
|
||||
id="path644" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath670">
|
||||
<path
|
||||
d="M 0,0 H 792 V 612 H 0 Z"
|
||||
id="path668" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath690">
|
||||
<path
|
||||
d="M 0,0 H 792 V 612 H 0 Z"
|
||||
id="path688" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath710">
|
||||
<path
|
||||
d="M 0,0 H 792 V 612 H 0 Z"
|
||||
id="path708" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath730">
|
||||
<path
|
||||
d="M 0,0 H 792 V 612 H 0 Z"
|
||||
id="path728" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.18520099"
|
||||
inkscape:cx="514.14383"
|
||||
inkscape:cy="22.780654"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1533"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="26"
|
||||
inkscape:window-y="23"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata1353">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-139.40571,-167.43852)">
|
||||
<g
|
||||
id="g588"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,-1224.4529,899.56869)">
|
||||
<g
|
||||
id="g590"
|
||||
clip-path="url(#clipPath594)">
|
||||
<g
|
||||
id="g596"
|
||||
transform="translate(476.7686,191.1094)">
|
||||
<path
|
||||
d="m 0,0 c 0,-5.89 -4.604,-10.521 -10.493,-10.521 -5.889,0 -10.493,4.631 -10.493,10.521 0,5.916 4.604,10.627 10.493,10.627 C -4.604,10.627 0,5.916 0,0 m -3.667,0 c 0,4.095 -2.998,7.2 -6.826,7.2 -3.828,0 -6.826,-3.105 -6.826,-7.2 0,-4.095 2.998,-7.121 6.826,-7.121 3.828,0 6.826,3.025 6.826,7.121"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path598" />
|
||||
</g>
|
||||
<g
|
||||
id="g600"
|
||||
transform="translate(492.605,187.6562)">
|
||||
<path
|
||||
d="m 0,0 c 0,-4.203 -3.158,-7.067 -6.559,-7.067 -1.82,0 -3.292,0.536 -4.416,1.445 v -8.539 h -3.534 V 6.692 h 3.535 V 5.621 C -9.85,6.558 -8.378,7.093 -6.558,7.093 -3.158,7.093 0,4.203 0,0 m -3.427,0 c 0,2.462 -1.606,4.015 -3.747,4.015 -1.9,0 -3.801,-1.553 -3.801,-4.015 0,-2.463 1.901,-3.987 3.801,-3.987 2.142,-0.002 3.747,1.524 3.747,3.987"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path602" />
|
||||
</g>
|
||||
<g
|
||||
id="g604"
|
||||
transform="translate(507.4006,186.7197)">
|
||||
<path
|
||||
d="m 0,0 h -10.172 c 0.348,-1.928 1.713,-3.105 3.346,-3.105 1.044,0 2.355,0.133 3.319,1.766 l 3.159,-0.669 c -1.178,-2.784 -3.56,-4.122 -6.479,-4.122 -3.774,0 -6.852,2.864 -6.852,7.067 0,4.202 3.078,7.092 6.906,7.092 3.56,0 6.638,-2.758 6.772,-6.826 z m -10.065,2.489 h 6.453 c -0.455,1.714 -1.74,2.463 -3.159,2.463 -1.34,0 -2.866,-0.803 -3.294,-2.463"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path606" />
|
||||
</g>
|
||||
<g
|
||||
id="g608"
|
||||
transform="translate(521.8176,189.1284)">
|
||||
<path
|
||||
d="m 0,0 v -8.138 h -3.533 v 7.388 c 0,1.874 -1.071,3.132 -2.704,3.132 -2.007,0 -3.319,-1.338 -3.319,-4.604 v -5.916 h -3.533 V 5.22 h 3.532 V 4.015 c 1.044,1.044 2.436,1.606 4.203,1.606 C -2.141,5.621 0,3.319 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path610" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g612"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,560.99821,305.04931)">
|
||||
<path
|
||||
d="M 0,0 H -2.837 L -7.816,13.197 -12.822,0 h -2.81 l -6.666,20.344 h 3.8 l 4.471,-13.438 5.113,13.438 h 2.168 l 5.113,-13.438 4.47,13.438 h 3.827 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path614" />
|
||||
</g>
|
||||
<g
|
||||
id="g616"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,-1224.4529,899.56869)">
|
||||
<g
|
||||
id="g618"
|
||||
clip-path="url(#clipPath622)">
|
||||
<g
|
||||
id="g624"
|
||||
transform="translate(558.9077,194.4282)">
|
||||
<path
|
||||
d="m 0,0 -0.187,-3.399 h -0.777 c -3.265,0 -4.765,-2.008 -4.765,-5.729 v -4.31 H -9.262 V -0.08 h 3.533 v -2.329 c 0.991,1.553 2.543,2.516 4.792,2.516 0.348,0 0.616,0 0.937,-0.107"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path626" />
|
||||
</g>
|
||||
<g
|
||||
id="g628"
|
||||
transform="translate(566.4221,185.916)">
|
||||
<path
|
||||
d="m 0,0 c 0,-1.312 0.616,-2.035 1.687,-2.035 0.615,0 1.525,0.269 2.223,0.643 l 1.017,-2.944 c -1.392,-0.75 -2.355,-0.991 -3.479,-0.991 -3.186,0 -4.979,1.821 -4.979,5.06 v 5.809 h -2.865 v 2.89 h 2.864 v 4.845 l 3.533,1.071 V 8.432 H 5.168 V 5.542 H 0 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path630" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g632"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,383.96624,329.4222)">
|
||||
<path
|
||||
d="M 0,0 H -0.795 L -1.542,2.05 -2.293,0 h -0.791 l -1.219,3.781 h 1.015 l 0.632,-2.039 0.791,2.039 h 0.647 L -0.432,1.742 0.205,3.781 H 1.22 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path634" />
|
||||
</g>
|
||||
<g
|
||||
id="g636"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,400.41254,326.72602)">
|
||||
<path
|
||||
d="M 0,0 H 0.781 V -0.821 H -1.737 V 0 h 0.781 V 2.135 H -1.737 V 2.96 H 0.781 V 2.135 H 0 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path638" />
|
||||
</g>
|
||||
<g
|
||||
id="g640"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,-1224.4529,899.56869)">
|
||||
<g
|
||||
id="g642"
|
||||
clip-path="url(#clipPath646)">
|
||||
<g
|
||||
id="g648"
|
||||
transform="translate(500.3777,173.5708)">
|
||||
<path
|
||||
d="M 0,0 -0.697,0.821 H -1.442 V 0 h -0.956 v 3.781 h 1.762 C 0.359,3.781 0.961,3.194 0.961,2.319 0.961,1.756 0.707,1.303 0.269,1.05 L 1.199,0 Z m -0.672,1.642 c 0.398,0 0.726,0.269 0.726,0.677 0,0.398 -0.328,0.643 -0.726,0.643 h -0.77 V 1.644 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path650" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g652"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,439.08752,329.4222)">
|
||||
<path
|
||||
d="M 0,0 H -2.886 V 3.781 H -0.03 V 2.96 h -1.9 V 2.313 h 1.87 V 1.493 H -1.93 V 0.821 h 1.931 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path654" />
|
||||
</g>
|
||||
<g
|
||||
id="g656"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,456.59196,329.4222)">
|
||||
<path
|
||||
d="m 0,0 h -2.791 v 3.781 h 0.955 V 0.821 H 0 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path658" />
|
||||
</g>
|
||||
<g
|
||||
id="g660"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,474.36148,329.4222)">
|
||||
<path
|
||||
d="M 0,0 H -2.886 V 3.781 H -0.03 V 2.96 H -1.931 V 2.313 H -0.06 V 1.493 H -1.931 V 0.821 H 0 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path662" />
|
||||
</g>
|
||||
<g
|
||||
id="g664"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,-1224.4529,899.56869)">
|
||||
<g
|
||||
id="g666"
|
||||
clip-path="url(#clipPath670)">
|
||||
<g
|
||||
id="g672"
|
||||
transform="translate(522.7458,176.3374)">
|
||||
<path
|
||||
d="m 0,0 -0.935,-0.189 c -0.08,0.383 -0.339,0.492 -0.563,0.492 -0.223,0 -0.408,-0.114 -0.408,-0.324 0,-0.148 0.08,-0.243 0.244,-0.293 l 0.737,-0.234 c 0.621,-0.203 0.96,-0.492 0.96,-1.084 0,-0.851 -0.746,-1.21 -1.488,-1.21 -0.821,0 -1.488,0.433 -1.582,1.155 l 0.98,0.199 c 0.079,-0.373 0.303,-0.533 0.632,-0.533 0.279,0 0.448,0.129 0.448,0.329 0,0.149 -0.08,0.254 -0.289,0.308 l -0.701,0.204 c -0.573,0.164 -0.961,0.458 -0.961,1.07 0,0.771 0.606,1.194 1.433,1.194 C -0.707,1.084 -0.125,0.707 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path674" />
|
||||
</g>
|
||||
<g
|
||||
id="g676"
|
||||
transform="translate(527.7451,176.3374)">
|
||||
<path
|
||||
d="m 0,0 -0.936,-0.189 c -0.079,0.383 -0.338,0.492 -0.562,0.492 -0.223,0 -0.408,-0.114 -0.408,-0.324 0,-0.148 0.08,-0.243 0.244,-0.293 l 0.737,-0.234 c 0.621,-0.203 0.96,-0.492 0.96,-1.084 0,-0.851 -0.746,-1.21 -1.488,-1.21 -0.821,0 -1.488,0.433 -1.582,1.155 l 0.98,0.199 c 0.079,-0.373 0.303,-0.533 0.632,-0.533 0.279,0 0.448,0.129 0.448,0.329 0,0.149 -0.08,0.254 -0.289,0.308 l -0.702,0.205 c -0.572,0.164 -0.96,0.458 -0.96,1.07 0,0.771 0.606,1.194 1.433,1.194 C -0.707,1.084 -0.125,0.707 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path678" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g680"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,531.81272,321.82281)">
|
||||
<path
|
||||
d="M 0,0 H 1.776 V -0.821 H 0 V -2.313 H -0.956 V 1.468 H 1.906 V 0.647 H 0 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path682" />
|
||||
</g>
|
||||
<g
|
||||
id="g684"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,-1224.4529,899.56869)">
|
||||
<g
|
||||
id="g686"
|
||||
clip-path="url(#clipPath690)">
|
||||
<g
|
||||
id="g692"
|
||||
transform="translate(541.5046,173.5708)">
|
||||
<path
|
||||
d="M 0,0 -0.696,0.821 H -1.443 V 0 h -0.955 v 3.781 h 1.761 C 0.358,3.781 0.96,3.194 0.96,2.319 0.96,1.756 0.707,1.303 0.269,1.05 L 1.199,0 Z m -0.672,1.642 c 0.399,0 0.727,0.269 0.727,0.677 0,0.398 -0.328,0.643 -0.727,0.643 H -1.443 V 1.644 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path694" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g696"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,574.18343,329.4222)">
|
||||
<path
|
||||
d="M 0,0 H -2.886 V 3.781 H -0.03 V 2.96 H -1.931 V 2.313 H -0.06 V 1.493 H -1.931 V 0.821 H 0 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path698" />
|
||||
</g>
|
||||
<g
|
||||
id="g700"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,591.99727,329.4222)">
|
||||
<path
|
||||
d="M 0,0 H -2.886 V 3.781 H -0.03 V 2.96 h -1.9 V 2.313 h 1.871 V 1.493 H -1.93 V 0.821 h 1.931 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path702" />
|
||||
</g>
|
||||
<g
|
||||
id="g704"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,-1224.4529,899.56869)">
|
||||
<g
|
||||
id="g706"
|
||||
clip-path="url(#clipPath710)">
|
||||
<g
|
||||
id="g712"
|
||||
transform="translate(557.21,177.3521)">
|
||||
<path
|
||||
d="M 0,0 C 1.204,0 2,-0.757 2,-1.891 2,-3.024 1.205,-3.781 0,-3.781 H -1.687 V 0 Z m -0.01,-2.96 c 0.652,0 1.05,0.428 1.05,1.069 0,0.642 -0.398,1.07 -1.05,1.07 H -0.73 V -2.96 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path714" />
|
||||
</g>
|
||||
<g
|
||||
id="g716"
|
||||
transform="translate(565.2275,175.4565)">
|
||||
<path
|
||||
d="m 0,0 c 0,-1.104 -0.906,-1.96 -2.02,-1.96 -1.115,0 -2.025,0.856 -2.025,1.96 0,1.104 0.905,1.965 2.025,1.965 C -0.901,1.965 0,1.1 0,0 m -0.96,0 c 0,0.622 -0.468,1.104 -1.061,1.104 -0.592,0 -1.06,-0.482 -1.06,-1.104 0,-0.622 0.468,-1.104 1.06,-1.104 0.593,0 1.061,0.477 1.061,1.104 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path718" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g720"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,653.10448,329.4222)">
|
||||
<path
|
||||
d="M 0,0 H -0.935 V 1.796 L -2.05,0.262 H -2.339 L -3.453,1.794 V -0.001 H -4.389 V 3.78 h 0.613 L -2.194,1.556 -0.612,3.78 H 0 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path722" />
|
||||
</g>
|
||||
<g
|
||||
id="g724"
|
||||
transform="matrix(3.2848066,0,0,-3.2848066,-1224.4529,899.56869)">
|
||||
<g
|
||||
id="g726"
|
||||
clip-path="url(#clipPath730)">
|
||||
<g
|
||||
id="g732"
|
||||
transform="translate(574.8005,200.6079)">
|
||||
<path
|
||||
d="M 0,0 -0.985,1.069 H -1.391 V 0 h -0.453 v 2.53 h 0.945 c 0.531,0 0.852,-0.303 0.852,-0.729 C -0.039,1.51 -0.215,1.247 -0.486,1.142 L 0.566,0 Z m -0.899,1.478 c 0.266,0 0.403,0.14 0.403,0.323 0,0.182 -0.139,0.318 -0.403,0.318 H -1.391 V 1.477 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path734" />
|
||||
</g>
|
||||
<g
|
||||
id="g736"
|
||||
transform="translate(573.9438,199.3813)">
|
||||
<path
|
||||
d="m 0,0 c -1.301,0 -2.355,1.054 -2.355,2.354 -10e-4,1.301 1.053,2.355 2.354,2.355 1.3,0.001 2.355,-1.053 2.355,-2.354 v 0 C 2.353,1.055 1.3,0.002 0,0 m 0,4.375 c -1.116,0 -2.021,-0.904 -2.021,-2.02 0,-1.116 0.905,-2.021 2.021,-2.021 1.116,0 2.021,0.905 2.021,2.021 C 2.02,3.471 1.116,4.375 0,4.376 Z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path738" />
|
||||
</g>
|
||||
<g
|
||||
id="g740"
|
||||
transform="translate(434.1643,199.1333)">
|
||||
<path
|
||||
d="m 0,0 c -1.705,0 -3.087,-1.382 -3.087,-3.087 0,-1.705 1.382,-3.086 3.087,-3.086 1.705,0 3.087,1.381 3.087,3.086 C 3.084,-1.383 1.704,-0.002 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path742" />
|
||||
</g>
|
||||
<g
|
||||
id="g744"
|
||||
transform="translate(415.2021,215.0088)">
|
||||
<path
|
||||
d="m 0,0 3.213,-3.213 c 4.032,4.032 9.606,6.52 15.749,6.52 6.143,0 11.718,-2.489 15.75,-6.52 L 37.925,0 C 33.074,4.851 26.365,7.875 18.962,7.875 11.56,7.875 4.851,4.851 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path746" />
|
||||
</g>
|
||||
<g
|
||||
id="g748"
|
||||
transform="translate(420.998,209.2129)">
|
||||
<path
|
||||
d="m 0,0 3.213,-3.213 c 2.551,2.552 6.079,4.127 9.952,4.127 3.873,0 7.404,-1.575 9.955,-4.127 L 26.333,0 C 22.963,3.371 18.301,5.482 13.167,5.482 8.033,5.482 3.371,3.372 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path750" />
|
||||
</g>
|
||||
<g
|
||||
id="g752"
|
||||
transform="translate(426.7622,203.4482)">
|
||||
<path
|
||||
d="m 0,0 3.213,-3.213 c 2.315,2.31 6.063,2.31 8.379,0 L 14.804,0 C 12.842,1.963 10.178,3.063 7.402,3.055 4.536,3.055 1.92,1.89 0,0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path754" />
|
||||
</g>
|
||||
<g
|
||||
id="g756"
|
||||
transform="translate(445.5669,204.3306)">
|
||||
<path
|
||||
d="m 0,0 c 1.701,-2.331 2.709,-5.197 2.709,-8.284 0,-7.78 -6.331,-14.112 -14.112,-14.112 -7.78,0 -14.111,6.332 -14.111,14.112 0,3.087 1.008,5.953 2.709,8.284 l -3.244,3.245 c -2.52,-3.182 -4.001,-7.182 -4.001,-11.529 0,-10.269 8.379,-18.647 18.647,-18.647 10.269,0 18.648,8.378 18.648,18.647 0,4.347 -1.512,8.347 -4.001,11.529 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path758" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -1,14 +1,14 @@
|
|||
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
/* eslint-disable max-len */
|
||||
/* exported translations */
|
||||
|
||||
const translations = {
|
||||
ca: {
|
||||
'tr-load': 'Descarregueu el microprogramari OpenWrt per al vostre dispositiu',
|
||||
'tr-title': 'Selector de microprogramari OpenWrt',
|
||||
'tr-title': 'Selector de microprogramari',
|
||||
'tr-message':
|
||||
'Introduïu el nom o el model del vostre dispositiu i seleccioneu la versió estable (per defecte) o la darrera imatge compilada ("snapshot")',
|
||||
'tr-version-build': 'Compilació',
|
||||
|
|
@ -35,7 +36,7 @@ const translations = {
|
|||
'tr-server-link': 'Files',
|
||||
'tr-notfound': 'No model found!',
|
||||
'tr-load': 'Download OpenWrt Firmware for your Device',
|
||||
'tr-title': 'OpenWrt Firmware Selector',
|
||||
'tr-title': 'Firmware Selector',
|
||||
'tr-message':
|
||||
'Type the name or model of your device, then select the recommended build or some other.',
|
||||
'tr-version-build': 'About this build',
|
||||
|
|
@ -65,7 +66,7 @@ const translations = {
|
|||
es: {
|
||||
'tr-notfound': '¡Modelo no encontrado!',
|
||||
'tr-load': 'Descargue el firmware OpenWrt para su dispositivo',
|
||||
'tr-title': 'Selector de firmware OpenWrt',
|
||||
'tr-title': 'Selector de firmware',
|
||||
'tr-message':
|
||||
'Escriba el nombre o modelo de su dispositivo, luego seleccione la versión recomendada o alguna otra.',
|
||||
'tr-version-build': 'Acerca de esta compilación',
|
||||
|
|
@ -95,7 +96,7 @@ const translations = {
|
|||
},
|
||||
no: {
|
||||
'tr-load': 'Last ned OpenWrt fastvare for din enhet!',
|
||||
'tr-title': 'OpenWrt fastvare utvelger',
|
||||
'tr-title': 'fastvare utvelger',
|
||||
'tr-message': 'Bruk feltene nedenfor for å laste ned fastvare til enheten din!',
|
||||
'tr-version-build': 'Sammensetning',
|
||||
'tr-custom-build': 'Tilpasset sammensetning',
|
||||
|
|
@ -126,7 +127,7 @@ const translations = {
|
|||
'tr-server-link': 'Dateien',
|
||||
'tr-notfound': 'Kein Model gefunden!',
|
||||
'tr-load': 'Lade die OpenWrt Firmware für dein Gerät!',
|
||||
'tr-title': 'OpenWrt Firmware Selector',
|
||||
'tr-title': 'Firmware Selector',
|
||||
'tr-message': 'Bitte benutze die Eingabe um die passende Firmware zu finden!',
|
||||
'tr-version-build': 'Release Build',
|
||||
'tr-custom-build': 'Custom Build',
|
||||
|
|
@ -185,7 +186,7 @@ const translations = {
|
|||
},
|
||||
it: {
|
||||
'tr-load': 'Scarica il firmware OpenWrt per il tuo dispositivo!',
|
||||
'tr-title': 'OpenWrt Firmware Selector',
|
||||
'tr-title': 'Firmware Selector',
|
||||
'tr-message': 'Usa la casella sottostante per scaricare il firmware per il tuo dispositivo!',
|
||||
'tr-version-build': 'Build',
|
||||
'tr-custom-build': 'Custom Build',
|
||||
|
|
@ -216,7 +217,7 @@ const translations = {
|
|||
'tr-server-link': 'Pliki',
|
||||
'tr-notfound': 'Nie znaleziono modelu!',
|
||||
'tr-load': 'Pobieranie oprogramowania OpenWrt',
|
||||
'tr-title': 'OpenWrt Firmware Selector',
|
||||
'tr-title': 'Firmware Selector',
|
||||
'tr-message':
|
||||
'Wprowadź nazwę lub model swojego urządzenia, a następnie wybierz wersję zalecaną lub inną.',
|
||||
'tr-version-build': 'Informacje o obrazie',
|
||||
|
|
@ -246,7 +247,7 @@ const translations = {
|
|||
},
|
||||
tr: {
|
||||
'tr-load': 'Cihazınız için OpenWrt yazılımını indirin!',
|
||||
'tr-title': 'OpenWrt Yazılım Seçicisi',
|
||||
'tr-title': 'Yazılım Seçicisi',
|
||||
'tr-message':
|
||||
'Cihazınızın adını/modelini girin, ardından Stabil sürümü(varsayılan) veya nightly "snapshot" imajini seçin.',
|
||||
'tr-version-build': 'Sürüm',
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
11
src/react-app-env.d.ts
vendored
|
|
@ -1 +1,12 @@
|
|||
/// <reference types="react-scripts" />
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
NODE_ENV: 'development' | 'production';
|
||||
PUBLIC_URL: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
|
|
|||
34
src/types/asu.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
export interface GetBuildResponse {
|
||||
arch_packages: string;
|
||||
bin_dir: string;
|
||||
build_at: string;
|
||||
default_packages?: string[];
|
||||
device_packages?: string[];
|
||||
enqueued_at: string;
|
||||
id: string;
|
||||
image_prefix: string;
|
||||
images?: ImagesEntity[];
|
||||
manifest: Record<string, string>;
|
||||
metadata_version: number;
|
||||
request_hash: string;
|
||||
stderr: string;
|
||||
stdout: string;
|
||||
supported_devices?: string[];
|
||||
target: string;
|
||||
titles?: TitlesEntity[];
|
||||
version_code: string;
|
||||
version_number: string;
|
||||
status?: 'queued' | 'started';
|
||||
queue_position?: number;
|
||||
}
|
||||
|
||||
export interface ImagesEntity {
|
||||
filesystem: string;
|
||||
name: string;
|
||||
sha256: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface TitlesEntity {
|
||||
title: string;
|
||||
}
|
||||
17
src/utils/api.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import axios from 'axios';
|
||||
import config from '../config';
|
||||
import { GetBuildResponse } from '../types/asu';
|
||||
|
||||
const asu = {
|
||||
buildNew: (packages: string[], profile: string, version: string) =>
|
||||
axios.post<GetBuildResponse>(`${config.asu_url}/api/build`, {
|
||||
version,
|
||||
profile,
|
||||
packages,
|
||||
diff_packages: true,
|
||||
}),
|
||||
checkBuild: (request_hash: string) =>
|
||||
axios.get<GetBuildResponse>(`${config.asu_url}/api/build/${request_hash}`),
|
||||
};
|
||||
|
||||
export default { asu };
|
||||
31
src/utils/asu.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import api from './api';
|
||||
import { sleep } from './common';
|
||||
|
||||
const build = async (
|
||||
packages: string[],
|
||||
profile: string,
|
||||
version: string,
|
||||
buildStatusCallback: (status: string) => void
|
||||
) => {
|
||||
const buildResponse = await api.asu.buildNew(packages, profile, version);
|
||||
if (buildResponse.status === 202) {
|
||||
buildStatusCallback(`#${buildResponse} in queue`);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const checkBuildResponse = await api.asu.checkBuild(buildResponse.data.request_hash);
|
||||
if (checkBuildResponse.status === 200) {
|
||||
return checkBuildResponse.data;
|
||||
} else if (checkBuildResponse.status === 202) {
|
||||
if (checkBuildResponse.data.status === 'queued') {
|
||||
buildStatusCallback(`#${buildResponse} in queue`);
|
||||
} else if (checkBuildResponse.data.status === 'started') {
|
||||
buildStatusCallback(`Building the image`);
|
||||
}
|
||||
}
|
||||
|
||||
await sleep(5000);
|
||||
}
|
||||
};
|
||||
|
||||
export default { build };
|
||||
3
src/utils/common.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||