diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 19c359b..0000000
--- a/.eslintignore
+++ /dev/null
@@ -1,4 +0,0 @@
-**/.eslintrc.js
-doc/
-frontend/
-scripts/
\ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 6e461e9..0000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "root": true,
- "env": {
- "es6": true,
- "node": true,
- "mocha": true
- },
- "extends": [
- "eslint:recommended"
- ],
- "plugins": [],
- "rules": {
- "indent": [
- "error",
- 4,
- {
- "SwitchCase": 1
- }
- ],
- "no-console": "off",
- "no-unused-vars": [
- "error",
- {
- "ignoreRestSiblings": true,
- "argsIgnorePattern": "^_"
- }
- ],
- "no-var": "error",
- "no-trailing-spaces": "error",
- "prefer-const": "error",
- "quotes": [
- "error",
- "single",
- {
- "avoidEscape": true,
- "allowTemplateLiterals": true
- }
- ],
- "semi": [
- "error",
- "always"
- ]
- },
- "parserOptions": {
- "ecmaVersion": "latest"
- }
-}
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
deleted file mode 100644
index 515bcd4..0000000
--- a/.prettierignore
+++ /dev/null
@@ -1,2 +0,0 @@
-package.json
-package-lock.json
\ No newline at end of file
diff --git a/.prettierrc.js b/.prettierrc.js
deleted file mode 100644
index 164ee34..0000000
--- a/.prettierrc.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- semi: true,
- trailingComma: 'all',
- singleQuote: true,
- printWidth: 120,
- useTabs: false,
- tabWidth: 4,
- endOfLine: 'lf',
-};
diff --git a/DEBUGGING.md b/DEBUGGING.md
index f5b5303..a2a5e26 100644
--- a/DEBUGGING.md
+++ b/DEBUGGING.md
@@ -2,19 +2,19 @@
## Local Debugging
-To test the repochecker and debug into the script under vscode:
+To test the adapter-checker and debug into the script under vscode:
1. Clone the repository to your local machine.\
- Best is that the directory is on the same level than your adapter repository.
+ Best is that the directory is on the same level as your adapter repository.
-2. run npm install in the repochecker directory.
+2. run npm install in the adapter-checker directory.
3. switch to your adapter repository and create a new launch configuration:
```json5
{
"name": "Launch Program",
- "program": "../iobroker.repochecker/index.js", // path to the repochecker repo
+ "program": "../iobroker.repochecker/index.js", // path to the adapter checker repo
// args as entered on the commandline, arguments as a array
"args": ["https://github.com/klein0r/ioBroker.luftdaten","--local"],
"request": "launch",
@@ -29,12 +29,12 @@ To test the repochecker and debug into the script under vscode:
## Local Testing without debugging
-To test the repochecker under vscode:
+To test the adapter checker under vscode:
1. Clone the repository to your local machine.\
- Best is that the directory is on the same level than your adapter repository.
+ Best is that the directory is on the same level as your adapter repository.
-2. run npm install in the repochecker directory.
+2. run npm install in the adapter checker directory.
3. switch to your adapter repository and enter the following commandline in a new terminal
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..e026127
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,27 @@
+import config from '@iobroker/eslint-config';
+
+export default [
+ ...config,
+ {
+ languageOptions: {
+ parserOptions: {
+ allowDefaultProject: {
+ allow: ['*.js', '*.mjs'],
+ },
+ tsconfigRootDir: import.meta.dirname,
+ project: './tsconfig.json',
+ // projectService: true,
+ },
+ },
+ },
+ {
+ // disable temporary the rule 'jsdoc/require-param' and enable 'jsdoc/require-jsdoc'
+ rules: {
+ 'jsdoc/require-jsdoc': 'off',
+ 'jsdoc/require-param': 'off',
+ },
+ },
+ {
+ ignores: ['build-backend/**/*', 'lib/**/*'],
+ },
+];
diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs
new file mode 100644
index 0000000..ea48839
--- /dev/null
+++ b/frontend/eslint.config.mjs
@@ -0,0 +1,34 @@
+import config, { reactConfig } from '@iobroker/eslint-config';
+
+export default [
+ ...config,
+ ...reactConfig,
+ {
+ rules: {
+ 'no-new-func': 'warn',
+ 'no-extend-native': 'warn',
+ 'no-eval': 'warn',
+ },
+ },
+ {
+ languageOptions: {
+ parserOptions: {
+ projectService: {
+ allowDefaultProject: ['*.mjs'],
+ },
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+ {
+ // disable temporary the rule 'jsdoc/require-param' and enable 'jsdoc/require-jsdoc'
+ rules: {
+ 'jsdoc/require-jsdoc': 'off',
+ 'jsdoc/require-param': 'off',
+ '@/no-duplicate-imports': 'error',
+ },
+ },
+ {
+ ignores: ['build/**/*', 'node_modules/**/*', 'src/serviceWorker.js', 'vite.config.mjs'],
+ },
+];
diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 0000000..850eae7
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+ ioBroker Adapter checker
+
+
+
+
+
+
+
diff --git a/frontend/package.json b/frontend/package.json
index 01d8be2..bffb1c0 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,32 +1,30 @@
{
- "name": "frontend-user",
- "version": "0.1.0",
- "private": true,
- "dependencies": {
- "@iobroker/adapter-react-v5": "^4.0.2",
- "@mui/material": "^5.10.17",
- "@mui/icons-material": "^5.10.16",
- "@mui/styles": "^5.10.16",
- "babel-eslint": "^10.1.0",
- "react-moment": "^1.1.2",
- "moment": "^2.29.4",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-scripts": "^5.0.1"
- },
- "scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject"
- },
- "eslintConfig": {
- "extends": "react-app"
- },
- "browserslist": [
- ">0.2%",
- "not dead",
- "not ie <= 11",
- "not op_mini all"
- ]
+ "name": "frontend-user",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@iobroker/adapter-react-v5": "^7.4.14",
+ "@mui/material": "^6.4.0",
+ "@mui/icons-material": "^6.4.0",
+ "@vitejs/plugin-react": "^4.3.4",
+ "react-moment": "^1.1.3",
+ "moment": "^2.30.1",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ },
+ "scripts": {
+ "start": "vite",
+ "build": "vite build",
+ "lint": "eslint -c eslint.config.mjs",
+ "npm": "npm i --force"
+ },
+ "eslintConfig": {
+ "extends": "react-app"
+ },
+ "browserslist": [
+ ">0.2%",
+ "not dead",
+ "not ie <= 11",
+ "not op_mini all"
+ ]
}
diff --git a/frontend/public/index.html b/frontend/public/index.html
deleted file mode 100644
index 49b24ff..0000000
--- a/frontend/public/index.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
- ioBroker Adapter checker
-
-
-
-
-
-
diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json
index bea54e1..b501703 100644
--- a/frontend/public/manifest.json
+++ b/frontend/public/manifest.json
@@ -1,15 +1,15 @@
{
- "short_name": "Repo checker",
- "name": "Create React App Sample",
- "icons": [
- {
- "src": "favicon.ico",
- "sizes": "64x64 32x32 24x24 16x16",
- "type": "image/x-icon"
- }
- ],
- "start_url": ".",
- "display": "standalone",
- "theme_color": "#000000",
- "background_color": "#ffffff"
+ "short_name": "Adapter checker",
+ "name": "ioBroker Adapter checker",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
}
diff --git a/frontend/src/App.css b/frontend/src/App.css
deleted file mode 100644
index 748abd5..0000000
--- a/frontend/src/App.css
+++ /dev/null
@@ -1,2 +0,0 @@
-.App {
-}
diff --git a/frontend/src/App.js b/frontend/src/App.js
deleted file mode 100644
index 5a51ef7..0000000
--- a/frontend/src/App.js
+++ /dev/null
@@ -1,343 +0,0 @@
-import React, {Component} from 'react';
-import { withStyles } from '@mui/styles';
-import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
-
-import './App.css';
-import AppBar from '@mui/material/AppBar';
-import Toolbar from '@mui/material/Toolbar';
-import Input from '@mui/material/Input';
-import Fab from '@mui/material/Fab';
-import List from '@mui/material/List';
-import ListItem from '@mui/material/ListItem';
-import ListItemIcon from '@mui/material/ListItemIcon';
-import ListItemText from '@mui/material/ListItemText';
-import Button from '@mui/material/Button';
-import CircularProgress from '@mui/material/CircularProgress';
-
-import CheckIcon from '@mui/icons-material/DoneOutlined';
-import ErrorIcon from '@mui/icons-material/Cancel';
-import WarningIcon from '@mui/icons-material/Announcement';
-
-import Comm from './Comm';
-import ToggleThemeMenu from './ToggleThemeMenu';
-import Utils from '@iobroker/adapter-react-v5/Components/Utils';
-import theme from '@iobroker/adapter-react-v5/Theme';
-import MessageDialog from '@iobroker/adapter-react-v5/Dialogs/Message';
-import I18n from '@iobroker/adapter-react-v5/i18n';
-
-const NARROW_WIDTH = 500;
-
-const styles = theme => ({
- toolbarTitle: {
- //position: 'absolute',
- top: 0,
- right: 20,
- whiteSpace: 'nowrap'
- },
- urlInput: {
- color: 'white'
- },
- branchInput: {
- width: 100,
- marginLeft: 10,
- color: 'white'
- },
- attrTitle: {
- display: 'inline-block',
- width: 160,
- fontWeight: 'bold',
- paddingLeft: 10
- },
- title: {
- background: '#faff7c',
- padding: 5,
- marginTop: 10,
- marginBottom: 0
- },
- buttonCheck: {
- marginLeft: 10,
- marginRight: 20,
- },
- body: {
- width: '100%',
- height: '100%',
- overflow: 'hidden',
- },
- info: {
- padding: 20,
- overflow: 'auto',
- height: 'calc(100% - 104px)'
- },
- ok: {
- color: '#111',
- },
- error: {
- color: '#bf0000'
- },
- warning: {
- color: '#bf9100'
- },
-});
-
-class App extends Component {
- constructor(props) {
- super(props);
-
- const _theme = theme(Utils.getThemeName());
-
- const translations = {
- 'en': require('@iobroker/adapter-react-v5/i18n/en'),
- 'de': require('@iobroker/adapter-react-v5/i18n/de'),
- 'ru': require('@iobroker/adapter-react-v5/i18n/ru'),
- 'pt': require('@iobroker/adapter-react-v5/i18n/pt'),
- 'nl': require('@iobroker/adapter-react-v5/i18n/nl'),
- 'fr': require('@iobroker/adapter-react-v5/i18n/fr'),
- 'it': require('@iobroker/adapter-react-v5/i18n/it'),
- 'es': require('@iobroker/adapter-react-v5/i18n/es'),
- 'pl': require('@iobroker/adapter-react-v5/i18n/pl'),
- 'zh-cn': require('@iobroker/adapter-react-v5/i18n/zh-cn'),
- };
-
- I18n.setTranslations(translations);
- I18n.setLanguage((navigator.language || navigator.userLanguage || 'en').substring(0, 2).toLowerCase());
-
- this.state = {
- url: window.localStorage.getItem('url') || '',
- requesting: false,
- errors: [],
- warnings: [],
- result: [],
- screenWidth: window.innerWidth,
- version: 'Adapter checker',
- branch: window.localStorage.getItem('branch') || '',
- theme: _theme,
- themeName: _theme.name,
- themeType: _theme.palette.type,
- hasTravis: false,
- globalError: null,
- };
-
- if (window.document.location.search) {
- const query = window.document.location.search.replace(/^\?/, '');
- const pairs = query.split('&');
- pairs.forEach(pair => {
- const parts = pair.split('=');
- if (parts[0] === 'q' && parts[1]) {
- this.state.url = decodeURIComponent(parts[1]);
- }
- });
-
- setTimeout(() => this.onCheck(), 500);
- }
-
- this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
- }
-
- componentDidMount() {
- window.addEventListener('resize', this.updateWindowDimensions());
- }
-
- componentWillUnmount() {
- window.removeEventListener('resize', this.updateWindowDimensions)
- }
-
- updateWindowDimensions() {
- this.setState({screenWidth: window.innerWidth});
- }
-
- onCheck() {
- let url = this.state.url;
- if (url.match(/\/$/, '')) {
- url = url.substring(0, url.length - 1);
- }
-
- this.setState({errors: [], result: [], warnings:[], requesting: true});
-
- Comm.check(url, this.state.branch.trim(), (err, data) => {
- if (err) {
- this.setState({
- errors: data.errors || [],
- globalError: err,
- warnings: (data && data.warnings) || [],
- result: (data && data.checks) || [],
- requesting: false,
- hasTravis: (data && data.hasTravis) || false,
- });
- } else {
- this.setState({
- errors: data.errors || [],
- warnings: data.warnings || [],
- result: data.checks || [],
- version: 'v' + data.version,
- requesting: false,
- hasTravis: data.hasTravis || false,
- });
- }
- });
- }
-
- renderResult() {
- return
- {this.state.result.map((line, i) =>
-
-
-
-
- )}
-
;
- }
-
- renderError() {
- return
- {this.state.errors.length ?
: null}
- {this.state.errors.map((line, i) =>
-
-
-
-
- )}
-
;
- }
-
- renderWarnings() {
- return
- {this.state.warnings.map((line, i) =>
-
-
-
-
- )}
-
;
- }
-
- onOpen(path) {
- let url = this.state.url.replace('https://raw.githubusercontent.com/', 'https://github.com/');
- url = url.replace(/\/$/, '') + path;
- const win = window.open(url, '_blank');
- win.focus();
- }
-
- onOpenLink(href) {
- const win = window.open(href, '_blank');
- win.focus();
- }
-
- onOpenTravis() {
- let url = this.state.url.replace('https://raw.githubusercontent.com/', 'https://travis-ci.org/');
- url = url.replace(/\/$/, '');
- const win = window.open(url, '_blank');
- win.focus();
- }
-
- toggleTheme() {
- const themeName = this.state.themeName;
-
- // dark => blue => colored => light => dark
- let newThemeName = themeName === 'dark' ? 'blue' :
- (themeName === 'blue' ? 'colored' :
- (themeName === 'colored' ? 'light' : 'dark'));
-
- Utils.setThemeName(newThemeName);
-
- const _theme = theme(newThemeName);
-
- this.setState({
- theme: _theme,
- themeName: _theme.name,
- themeType: _theme.palette.type
- });
- }
-
- showError() {
- if (this.state.globalError) {
- return this.setState({globalError: null})}
- title={this.state.globalError}
- />;
- } else {
- return null;
- }
- }
-
- render() {
- const narrowScreen = this.state.screenWidth <= NARROW_WIDTH;
-
- return
-
-
-
- ;
- }
-}
-
-export default withStyles(styles)(App);
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
new file mode 100644
index 0000000..661a981
--- /dev/null
+++ b/frontend/src/App.jsx
@@ -0,0 +1,450 @@
+import React, { Component } from 'react';
+import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
+
+import {
+ AppBar,
+ Toolbar,
+ Input,
+ Fab,
+ List,
+ ListItem,
+ ListItemIcon,
+ ListItemText,
+ Button,
+ CircularProgress,
+} from '@mui/material';
+
+import { DoneOutlined as CheckIcon, Cancel as ErrorIcon, Announcement as WarningIcon } from '@mui/icons-material';
+
+import { Utils, Theme, DialogMessage, I18n } from '@iobroker/adapter-react-v5';
+
+import Comm from './Comm';
+import ToggleThemeMenu from './ToggleThemeMenu';
+
+import en from '@iobroker/adapter-react-v5/i18n/en';
+import de from '@iobroker/adapter-react-v5/i18n/de';
+import ru from '@iobroker/adapter-react-v5/i18n/ru';
+import pt from '@iobroker/adapter-react-v5/i18n/pt';
+import nl from '@iobroker/adapter-react-v5/i18n/nl';
+import fr from '@iobroker/adapter-react-v5/i18n/fr';
+import it from '@iobroker/adapter-react-v5/i18n/it';
+import es from '@iobroker/adapter-react-v5/i18n/es';
+import pl from '@iobroker/adapter-react-v5/i18n/pl';
+import zhCN from '@iobroker/adapter-react-v5/i18n/zh-cn';
+
+const NARROW_WIDTH = 500;
+
+const styles = {
+ toolbarTitle: {
+ top: 0,
+ right: 20,
+ whiteSpace: 'nowrap',
+ },
+ urlInput: {
+ color: 'white',
+ },
+ branchInput: {
+ width: 100,
+ marginLeft: 10,
+ color: 'white',
+ },
+ attrTitle: {
+ display: 'inline-block',
+ width: 160,
+ fontWeight: 'bold',
+ paddingLeft: 10,
+ },
+ title: {
+ background: '#faff7c',
+ padding: 5,
+ marginTop: 10,
+ marginBottom: 0,
+ },
+ buttonCheck: {
+ marginLeft: 10,
+ marginRight: 20,
+ },
+ body: {
+ width: '100%',
+ height: '100%',
+ overflow: 'hidden',
+ },
+ info: {
+ padding: 20,
+ overflow: 'auto',
+ height: 'calc(100% - 104px)',
+ },
+ ok: {
+ color: '#111',
+ },
+ error: {
+ color: '#bf0000',
+ },
+ warning: {
+ color: '#bf9100',
+ },
+};
+
+class App extends Component {
+ constructor(props) {
+ super(props);
+
+ const theme = Theme(Utils.getThemeName());
+
+ const translations = {
+ en,
+ de,
+ ru,
+ pt,
+ nl,
+ fr,
+ it,
+ es,
+ pl,
+ 'zh-cn': zhCN,
+ };
+
+ I18n.setTranslations(translations);
+ I18n.setLanguage((navigator.language || navigator.userLanguage || 'en').substring(0, 2).toLowerCase());
+
+ this.state = {
+ url: window.localStorage.getItem('url') || '',
+ requesting: false,
+ errors: [],
+ warnings: [],
+ result: [],
+ screenWidth: window.innerWidth,
+ version: 'Adapter checker',
+ branch: window.localStorage.getItem('branch') || '',
+ theme,
+ themeName: theme.name,
+ themeType: theme.palette.mode,
+ hasTravis: false,
+ globalError: null,
+ };
+
+ if (window.document.location.search) {
+ const query = window.document.location.search.replace(/^\?/, '');
+ const pairs = query.split('&');
+ pairs.forEach(pair => {
+ const parts = pair.split('=');
+ if (parts[0] === 'q' && parts[1]) {
+ this.state.url = decodeURIComponent(parts[1]);
+ }
+ });
+
+ setTimeout(() => this.onCheck(), 500);
+ }
+
+ this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
+ if (theme.palette.mode === 'dark') {
+ window.document.body.style.background = '#111';
+ }
+ }
+
+ componentDidMount() {
+ window.addEventListener('resize', this.updateWindowDimensions());
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.updateWindowDimensions);
+ }
+
+ updateWindowDimensions() {
+ this.setState({ screenWidth: window.innerWidth });
+ }
+
+ onCheck() {
+ let url = this.state.url;
+ if (url.match(/\/$/, '')) {
+ url = url.substring(0, url.length - 1);
+ }
+
+ this.setState({ errors: [], result: [], warnings: [], requesting: true });
+
+ Comm.check(url, this.state.branch.trim(), (err, data) => {
+ if (err) {
+ this.setState({
+ errors: data.errors || [],
+ globalError: err,
+ warnings: (data && data.warnings) || [],
+ result: (data && data.checks) || [],
+ requesting: false,
+ hasTravis: (data && data.hasTravis) || false,
+ });
+ } else {
+ this.setState({
+ errors: data.errors || [],
+ warnings: data.warnings || [],
+ result: data.checks || [],
+ version: 'v' + data.version,
+ requesting: false,
+ hasTravis: data.hasTravis || false,
+ });
+ }
+ });
+ }
+
+ renderResult() {
+ return (
+
+ {this.state.result.map((line, i) => (
+
+
+
+
+
+
+ ))}
+
+ );
+ }
+
+ renderError() {
+ return (
+
+ {this.state.errors.length ?
: null}
+ {this.state.errors.map((line, i) => (
+
+
+
+
+
+
+ ))}
+
+ );
+ }
+
+ renderWarnings() {
+ return (
+
+ {this.state.warnings.map((line, i) => (
+
+
+
+
+
+
+ ))}
+
+ );
+ }
+
+ onOpen(path) {
+ let url = this.state.url.replace('https://raw.githubusercontent.com/', 'https://github.com/');
+ url = url.replace(/\/$/, '') + path;
+ const win = window.open(url, '_blank');
+ win.focus();
+ }
+
+ onOpenLink(href) {
+ const win = window.open(href, '_blank');
+ win.focus();
+ }
+
+ onOpenTravis() {
+ let url = this.state.url.replace('https://raw.githubusercontent.com/', 'https://travis-ci.org/');
+ url = url.replace(/\/$/, '');
+ const win = window.open(url, '_blank');
+ win.focus();
+ }
+
+ toggleTheme() {
+ const themeName = this.state.themeName;
+
+ // dark => blue => colored => light => dark
+ let newThemeName = themeName === 'dark' ? 'light' : 'dark';
+
+ Utils.setThemeName(newThemeName);
+
+ const theme = Theme(newThemeName);
+
+ if (theme.palette.mode === 'dark') {
+ window.document.body.style.background = '#111';
+ } else {
+ window.document.body.style.background = '#EEE';
+ }
+ this.setState({
+ theme,
+ themeName: theme.name,
+ themeType: theme.palette.type,
+ });
+ }
+
+ showError() {
+ if (this.state.globalError) {
+ return (
+ this.setState({ globalError: null })}
+ text={this.state.globalError}
+ />
+ );
+ } else {
+ return null;
+ }
+ }
+
+ render() {
+ const narrowScreen = this.state.screenWidth <= NARROW_WIDTH;
+
+ return (
+
+
+
+
+
+ {
+ if (e.key === 'Enter' && this.state.url && !this.state.requesting) {
+ this.onCheck();
+ }
+ }}
+ readOnly={this.state.requesting}
+ style={{
+ ...styles.urlInput,
+ maxWidth: narrowScreen
+ ? this.state.screenWidth - 35
+ : this.state.screenWidth - 250,
+ width: narrowScreen ? 'calc(100% - 35px)' : 'calc(100% - 350px)',
+ }}
+ onChange={e => {
+ window.localStorage.setItem('url', e.target.value);
+ this.setState({ url: e.target.value });
+ }}
+ />
+ {!narrowScreen ? (
+ {
+ if (e.key === 'Enter' && this.state.url && !this.state.requesting) {
+ this.onCheck();
+ }
+ }}
+ readOnly={this.state.requesting}
+ style={styles.branchInput}
+ onChange={e => {
+ window.localStorage.setItem('branch', e.target.value);
+ this.setState({ branch: e.target.value });
+ }}
+ />
+ ) : null}
+ {this.state.requesting ? (
+
+ ) : (
+ this.onCheck()}
+ aria-label="Check"
+ >
+
+
+ )}
+ {!narrowScreen ? {this.state.version}
: null}
+ {!narrowScreen ? (
+ this.toggleTheme()}
+ themeName={this.state.themeName}
+ t={w => w}
+ />
+ ) : null}
+
+
+
+ {this.state.result.length
+ ? [
+ ,
+ ,
+ ,
+ this.state.hasTravis ? (
+
+ ) : null,
+ this.state.errors && this.state.errors.length ? (
+
+ ) : null,
+ ]
+ : null}
+ {this.state.errors ? this.renderError() : null}
+ {this.state.warnings ? this.renderWarnings() : null}
+ {this.state.result ? this.renderResult() : null}
+
+ {this.showError()}
+
+
+
+ );
+ }
+}
+
+export default App;
diff --git a/frontend/src/App.test.js b/frontend/src/App.test.js
deleted file mode 100644
index a754b20..0000000
--- a/frontend/src/App.test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import App from './App';
-
-it('renders without crashing', () => {
- const div = document.createElement('div');
- ReactDOM.render(, div);
- ReactDOM.unmountComponentAtNode(div);
-});
diff --git a/frontend/src/Comm.js b/frontend/src/Comm.js
index 5ea80ba..81d24e8 100644
--- a/frontend/src/Comm.js
+++ b/frontend/src/Comm.js
@@ -1,4 +1,7 @@
-const URL = window.API_URL && window.API_URL !== '${API_URL}' ? `${window.API_URL}` : 'https://3jjxddo33l.execute-api.eu-west-1.amazonaws.com/default/checkAdapter';
+const URL =
+ window.API_URL && window.API_URL !== '${API_URL}'
+ ? `${window.API_URL}`
+ : 'https://3jjxddo33l.execute-api.eu-west-1.amazonaws.com/default/checkAdapter';
class Comm {
static check(repo, branch, cb) {
const url = `${URL}?url=${encodeURIComponent(repo)}${branch ? `&branch=${encodeURIComponent(branch)}` : ''}`;
@@ -7,7 +10,7 @@ class Comm {
.then(res => res.json())
.then(
result => cb && cb(result.error || null, result),
- error => cb && cb(error)
+ error => cb && cb(error),
);
} catch (error) {
cb && cb(error);
@@ -15,4 +18,4 @@ class Comm {
}
}
-export default Comm;
\ No newline at end of file
+export default Comm;
diff --git a/frontend/src/ToggleThemeMenu.js b/frontend/src/ToggleThemeMenu.js
deleted file mode 100644
index a779834..0000000
--- a/frontend/src/ToggleThemeMenu.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import { IconButton, Tooltip } from '@mui/material';
-import Brightness4Icon from '@mui/icons-material/Brightness4';
-import Brightness5Icon from '@mui/icons-material/Brightness5';
-import Brightness6Icon from '@mui/icons-material/Brightness6';
-import Brightness7Icon from '@mui/icons-material/Brightness7';
-
-export default function ToggleThemeMenu({ themeName, toggleTheme, t, className, style, size }) {
- return
-
- toggleTheme()} size={size || 'medium'}>
- {themeName === 'dark' && }
- {themeName === 'blue' && }
- {themeName === 'colored' && }
- {themeName === 'light' && }
-
-
-
;
-}
\ No newline at end of file
diff --git a/frontend/src/ToggleThemeMenu.jsx b/frontend/src/ToggleThemeMenu.jsx
new file mode 100644
index 0000000..317eb48
--- /dev/null
+++ b/frontend/src/ToggleThemeMenu.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { IconButton, Tooltip } from '@mui/material';
+import { Brightness4 as Brightness4Icon, Brightness7 as Brightness7Icon } from '@mui/icons-material';
+
+export default function ToggleThemeMenu({ themeName, toggleTheme, t, className, style, size }) {
+ return (
+
+
+ toggleTheme()}
+ size={size || 'medium'}
+ >
+ {themeName === 'dark' && }
+ {themeName === 'light' && }
+
+
+
+ );
+}
diff --git a/frontend/src/assets/alexaLogo.png b/frontend/src/assets/alexaLogo.png
deleted file mode 100644
index 8616b12..0000000
Binary files a/frontend/src/assets/alexaLogo.png and /dev/null differ
diff --git a/frontend/src/assets/knx.png b/frontend/src/assets/knx.png
deleted file mode 100644
index 267ed3f..0000000
Binary files a/frontend/src/assets/knx.png and /dev/null differ
diff --git a/frontend/src/assets/lcn.png b/frontend/src/assets/lcn.png
deleted file mode 100644
index 9f589d4..0000000
Binary files a/frontend/src/assets/lcn.png and /dev/null differ
diff --git a/frontend/src/assets/remote.png b/frontend/src/assets/remote.png
deleted file mode 100644
index 9bfc7ae..0000000
Binary files a/frontend/src/assets/remote.png and /dev/null differ
diff --git a/frontend/src/assets/vis.png b/frontend/src/assets/vis.png
deleted file mode 100644
index f52bcd0..0000000
Binary files a/frontend/src/assets/vis.png and /dev/null differ
diff --git a/frontend/src/index.css b/frontend/src/index.css
index f435003..898e0fe 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -1,19 +1,19 @@
-html, body, #root {
- width: 100%;
- height: 100%;
- overflow: hidden;
+html,
+body,
+#root {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
}
body {
- margin: 0;
- padding: 0;
- font-family: -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;
+ margin: 0;
+ padding: 0;
+ font-family: -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;
}
code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
- monospace;
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
diff --git a/frontend/src/index.js b/frontend/src/index.js
deleted file mode 100644
index 03727e5..0000000
--- a/frontend/src/index.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import { createRoot } from 'react-dom/client';
-import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
-import './index.css';
-import App from './App';
-import * as serviceWorker from './serviceWorker';
-
-import theme from '@iobroker/adapter-react-v5/Theme';
-import Utils from '@iobroker/adapter-react-v5/Components/Utils';
-let themeName = Utils.getThemeName();
-
-function build() {
- const container = document.getElementById('root');
- const root = createRoot(container);
- return root.render(
-
-
- {
- themeName = _theme;
- build();
- }}
- />
-
-
- );
-}
-
-build();
-
-// If you want your app to work offline and load faster, you can change
-// unregister() to register() below. Note this comes with some pitfalls.
-// Learn more about service workers: http://bit.ly/CRA-PWA
-serviceWorker.unregister();
diff --git a/frontend/src/index.jsx b/frontend/src/index.jsx
new file mode 100644
index 0000000..56a4c63
--- /dev/null
+++ b/frontend/src/index.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import './index.css';
+import App from './App';
+import * as serviceWorker from './serviceWorker';
+
+const container = document.getElementById('root');
+const root = createRoot(container);
+root.render();
+
+// If you want your app to work offline and load faster, you can change
+// unregister() to register() below. Note this comes with some pitfalls.
+// Learn more about service workers: http://bit.ly/CRA-PWA
+serviceWorker.unregister();
diff --git a/frontend/src/serviceWorker.js b/frontend/src/serviceWorker.js
index 012c322..86d6b25 100644
--- a/frontend/src/serviceWorker.js
+++ b/frontend/src/serviceWorker.js
@@ -11,121 +11,114 @@
// opt-in, read http://bit.ly/CRA-PWA.
const isLocalhost = Boolean(
- window.location.hostname === 'localhost' ||
- // [::1] is the IPv6 localhost address.
- window.location.hostname === '[::1]' ||
- // 127.0.0.1/8 is considered localhost for IPv4.
- window.location.hostname.match(
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
- )
+ window.location.hostname === 'localhost' ||
+ // [::1] is the IPv6 localhost address.
+ window.location.hostname === '[::1]' ||
+ // 127.0.0.1/8 is considered localhost for IPv4.
+ window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/),
);
export function register(config) {
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
- // The URL constructor is available in all browsers that support SW.
- const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
- if (publicUrl.origin !== window.location.origin) {
- // Our service worker won't work if PUBLIC_URL is on a different origin
- // from what our page is served on. This might happen if a CDN is used to
- // serve assets; see https://github.com/facebook/create-react-app/issues/2374
- return;
- }
+ if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
+ // The URL constructor is available in all browsers that support SW.
+ const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
+ if (publicUrl.origin !== window.location.origin) {
+ // Our service worker won't work if PUBLIC_URL is on a different origin
+ // from what our page is served on. This might happen if a CDN is used to
+ // serve assets; see https://github.com/facebook/create-react-app/issues/2374
+ return;
+ }
- window.addEventListener('load', () => {
- const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
+ window.addEventListener('load', () => {
+ const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
- if (isLocalhost) {
- // This is running on localhost. Let's check if a service worker still exists or not.
- checkValidServiceWorker(swUrl, config);
+ if (isLocalhost) {
+ // This is running on localhost. Let's check if a service worker still exists or not.
+ checkValidServiceWorker(swUrl, config);
- // Add some additional logging to localhost, pointing developers to the
- // service worker/PWA documentation.
- navigator.serviceWorker.ready.then(() => {
- console.log(
- 'This web app is being served cache-first by a service ' +
- 'worker. To learn more, visit http://bit.ly/CRA-PWA'
- );
+ // Add some additional logging to localhost, pointing developers to the
+ // service worker/PWA documentation.
+ navigator.serviceWorker.ready.then(() => {
+ console.log(
+ 'This web app is being served cache-first by a service ' +
+ 'worker. To learn more, visit http://bit.ly/CRA-PWA',
+ );
+ });
+ } else {
+ // Is not localhost. Just register service worker
+ registerValidSW(swUrl, config);
+ }
});
- } else {
- // Is not localhost. Just register service worker
- registerValidSW(swUrl, config);
- }
- });
- }
+ }
}
function registerValidSW(swUrl, config) {
- navigator.serviceWorker
- .register(swUrl)
- .then(registration => {
- registration.onupdatefound = () => {
- const installingWorker = registration.installing;
- installingWorker.onstatechange = () => {
- if (installingWorker.state === 'installed') {
- if (navigator.serviceWorker.controller) {
- // At this point, the updated precached content has been fetched,
- // but the previous service worker will still serve the older
- // content until all client tabs are closed.
- console.log(
- 'New content is available and will be used when all ' +
- 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
- );
+ navigator.serviceWorker
+ .register(swUrl)
+ .then(registration => {
+ registration.onupdatefound = () => {
+ const installingWorker = registration.installing;
+ installingWorker.onstatechange = () => {
+ if (installingWorker.state === 'installed') {
+ if (navigator.serviceWorker.controller) {
+ // At this point, the updated precached content has been fetched,
+ // but the previous service worker will still serve the older
+ // content until all client tabs are closed.
+ console.log(
+ 'New content is available and will be used when all ' +
+ 'tabs for this page are closed. See http://bit.ly/CRA-PWA.',
+ );
- // Execute callback
- if (config && config.onUpdate) {
- config.onUpdate(registration);
- }
- } else {
- // At this point, everything has been precached.
- // It's the perfect time to display a
- // "Content is cached for offline use." message.
- console.log('Content is cached for offline use.');
+ // Execute callback
+ if (config && config.onUpdate) {
+ config.onUpdate(registration);
+ }
+ } else {
+ // At this point, everything has been precached.
+ // It's the perfect time to display a
+ // "Content is cached for offline use." message.
+ console.log('Content is cached for offline use.');
- // Execute callback
- if (config && config.onSuccess) {
- config.onSuccess(registration);
- }
- }
- }
- };
- };
- })
- .catch(error => {
- console.error('Error during service worker registration:', error);
- });
+ // Execute callback
+ if (config && config.onSuccess) {
+ config.onSuccess(registration);
+ }
+ }
+ }
+ };
+ };
+ })
+ .catch(error => {
+ console.error('Error during service worker registration:', error);
+ });
}
function checkValidServiceWorker(swUrl, config) {
- // Check if the service worker can be found. If it can't reload the page.
- fetch(swUrl)
- .then(response => {
- // Ensure service worker exists, and that we really are getting a JS file.
- if (
- response.status === 404 ||
- response.headers.get('content-type').indexOf('javascript') === -1
- ) {
- // No service worker found. Probably a different app. Reload the page.
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister().then(() => {
- window.location.reload();
- });
+ // Check if the service worker can be found. If it can't reload the page.
+ fetch(swUrl)
+ .then(response => {
+ // Ensure service worker exists, and that we really are getting a JS file.
+ if (response.status === 404 || response.headers.get('content-type').indexOf('javascript') === -1) {
+ // No service worker found. Probably a different app. Reload the page.
+ navigator.serviceWorker.ready.then(registration => {
+ registration.unregister().then(() => {
+ window.location.reload();
+ });
+ });
+ } else {
+ // Service worker found. Proceed as normal.
+ registerValidSW(swUrl, config);
+ }
+ })
+ .catch(() => {
+ console.log('No internet connection found. App is running in offline mode.');
});
- } else {
- // Service worker found. Proceed as normal.
- registerValidSW(swUrl, config);
- }
- })
- .catch(() => {
- console.log(
- 'No internet connection found. App is running in offline mode.'
- );
- });
}
export function unregister() {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister();
- });
- }
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.ready.then(registration => {
+ registration.unregister();
+ });
+ }
}
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
new file mode 100644
index 0000000..9596389
--- /dev/null
+++ b/frontend/tsconfig.json
@@ -0,0 +1,36 @@
+// Specialized tsconfig for the admin directory,
+// includes DOM typings and configures the admin build
+{
+ "compilerOptions": {
+ "module": "esnext",
+ "moduleResolution": "node",
+ // check JS files
+ "allowJs": true,
+ // This is necessary for the automatic typing of the adapter config
+ "resolveJsonModule": true,
+ // If you want to disable the stricter type checks (not recommended), uncomment the following line
+ // "strict": false,
+ // And enable some of those features for more fine-grained control
+ "strictNullChecks": true,
+ // "strictPropertyInitialization": true,
+ // "strictBindCallApply": true,
+ // "noUnusedLocals": true,
+ // "noUnusedParameters": true,
+ "useUnknownInCatchVariables": false,
+ "target": "ES2022",
+ "baseUrl": "./",
+ "allowSyntheticDefaultImports": true,
+ "checkJs": false,
+ "noEmit": false,
+ "outDir": "./build",
+ "sourceMap": true,
+ "sourceRoot": "./src",
+ "noImplicitAny": true,
+ "skipLibCheck": true,
+ "verbatimModuleSyntax": true,
+ "lib": ["es2018", "DOM"],
+ "jsx": "react"
+ },
+ "include": ["./src/**/*.ts", "./src/**/*.d.ts", "./src/**/*.tsx", "./src/**/*.json", "./src/**/*.css"],
+ "exclude": ["**/node_modules", "**/dist"]
+}
diff --git a/frontend/vite.config.mjs b/frontend/vite.config.mjs
new file mode 100644
index 0000000..0aebad3
--- /dev/null
+++ b/frontend/vite.config.mjs
@@ -0,0 +1,36 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig(() => {
+ return {
+ build: {
+ outDir: 'build',
+ },
+ plugins: [react()],
+ resolve: {
+ mainFields: [],
+ },
+ base: './',
+ server: {
+ port: 3000,
+ proxy: {
+ '/adapter': {
+ target: 'http://localhost:8081',
+ changeOrigin: true,
+ secure: false,
+ configure: (proxy, _options) => {
+ proxy.on('error', (err, _req, _res) => {
+ console.log('proxy error', err);
+ });
+ proxy.on('proxyReq', (proxyReq, req, _res) => {
+ console.log('Sending Request to the Target:', req.method, req.url);
+ });
+ proxy.on('proxyRes', (proxyRes, req, _res) => {
+ console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
+ });
+ },
+ },
+ },
+ },
+ };
+});
diff --git a/package.json b/package.json
index ce32cb5..0f4da76 100644
--- a/package.json
+++ b/package.json
@@ -1,38 +1,38 @@
{
- "version": "3.2.3",
- "name": "@iobroker/repochecker",
- "dependencies": {
- "axios": "^1.7.9",
- "compare-versions": "^6.1.1",
- "image-size": "^1.2.0",
- "unzipper": "^0.12.3",
- "json5": "^2.2.3"
- },
- "publishConfig": {
- "access": "public"
- },
- "devDependencies": {
- "@alcalzone/release-script": "^3.8.0",
- "eslint": "^8.57.0"
- },
- "files": [
- "lib/",
- "LICENSE",
- "index.js",
- "doc/issues.json"
- ],
- "engines": {
- "node": ">=16"
- },
- "main": "index.js",
- "bin": "index.js",
- "scripts": {
- "prepublishOnly": "node doc/readme.js",
- "start": "node index.js",
- "lint": "eslint",
- "release": "release-script",
- "release-patch": "release-script patch --yes --no-update-lockfile",
- "release-minor": "release-script minor --yes --no-update-lockfile",
- "release-major": "release-script major --yes --no-update-lockfile"
- }
+ "version": "3.2.3",
+ "name": "@iobroker/repochecker",
+ "dependencies": {
+ "axios": "^1.7.9",
+ "compare-versions": "^6.1.1",
+ "image-size": "^1.2.0",
+ "unzipper": "^0.12.3",
+ "json5": "^2.2.3"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "devDependencies": {
+ "@alcalzone/release-script": "^3.8.0",
+ "@iobroker/eslint-config": "^1.0.0"
+ },
+ "files": [
+ "lib/",
+ "LICENSE",
+ "index.js",
+ "doc/issues.json"
+ ],
+ "engines": {
+ "node": ">=16"
+ },
+ "main": "index.js",
+ "bin": "index.js",
+ "scripts": {
+ "prepublishOnly": "node doc/readme.js",
+ "start": "node index.js",
+ "lint": "eslint",
+ "release": "release-script",
+ "release-patch": "release-script patch --yes --no-update-lockfile",
+ "release-minor": "release-script minor --yes --no-update-lockfile",
+ "release-major": "release-script major --yes --no-update-lockfile"
+ }
}
diff --git a/prettier.config.mjs b/prettier.config.mjs
new file mode 100644
index 0000000..2f00708
--- /dev/null
+++ b/prettier.config.mjs
@@ -0,0 +1,3 @@
+import prettierConfig from '@iobroker/eslint-config/prettier.config.mjs';
+
+export default prettierConfig;