diff --git a/.eslintrc.json b/.eslintrc.json index 6efbca4..7e45b26 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,6 +5,7 @@ "mocha": true }, "extends": "eslint:recommended", + "ignorePatterns": ["src/**/*.*", "gulpfile.js"], "rules": { "indent": [ "error", diff --git a/.gitignore b/.gitignore index 72f06f0..912921d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ admin/i18n/*/flat.txt system.config.json *.code-workspace package-lock.json +/src/build +/admin/custom diff --git a/.releaseconfig.json b/.releaseconfig.json index ec98e71..450e512 100644 --- a/.releaseconfig.json +++ b/.releaseconfig.json @@ -1,4 +1,7 @@ { "dry": false, - "plugins": ["iobroker", "license"] + "plugins": ["iobroker", "license"], + "exec": { + "before_commit": "npm run build" + } } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5357396..0000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -os: - - linux - - osx - - windows -language: node_js -node_js: - - '12' - - '14' - - '16' -env: - - CXX=g++-6 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 -before_install: - - 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then CC=gcc-6; fi' - - 'if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then CC=g++-6; fi' -before_script: - - export NPMVERSION=$(echo "$($(which npm) -v)"|cut -c1) - - 'if [[ $NPMVERSION == 5 ]]; then npm install -g npm; fi' - - npm -v -script: - - 'npm run test:package' - - 'npm run test:unit' - - 'export DEBUG=testing:*' - - 'npm run test:integration' diff --git a/admin/jsonCustom.json b/admin/jsonCustom.json index c64919a..a6c48e5 100644 --- a/admin/jsonCustom.json +++ b/admin/jsonCustom.json @@ -6,58 +6,12 @@ "hidden": "data.isLinked !== undefined", "type": "panel", "items": { - "_prefixId": { - "type": "autocompleteSendTo", - "label": "prefix for id of linked object", - "sm": 8, - "noMultiEdit": true, - "freeSolo": true, - "noTranslation": true, - "command": "suggestions_prefixId", - "maxLength": 255, - "defaultFunc": { - "func": "(data.linkedId || '').includes('.') ? data.linkedId.substring(0, data.linkedId.lastIndexOf('.')) : ''", - "alsoDependsOn": [ - "linkedId" - ] - }, - "validator": "data._prefixId && data._prefixId.length > 0 && !(/[*?\"'`´,;:<>#/{}ß\\[\\]\\s]/).test(data._prefixId) || data._prefixId === ''", - "help": "${data._prefixId && data._prefixId.length > 0 && !(/[*?\"'`´,;:<>#/{}ß\\[\\]\\s]/).test(data._prefixId) || data._prefixId === '' ? '' : 'the following chars are not allowed \\'*?\"\\'`´,;:<>#/{}ß[] \\''}" - }, - "_stateId": { - "type": "autocompleteSendTo", - "label": "id of linked object", - "sm": 4, - "noMultiEdit": true, - "freeSolo": true, - "noTranslation": true, - "command": "suggestions_stateId", - "maxLength": 255, - "defaultFunc": { - "func": "(data.linkedId || '').split('.').pop()", - "alsoDependsOn": [ - "linkedId" - ] - }, - "validator": "data._stateId && data._stateId.length > 0 && !(/[*?\"'`´,;:<>#/{}ß\\[\\]\\s]/).test(data._stateId)", - "help": "${data._stateId && data._stateId.length > 0 && !(/[*?\"'`´,;:<>#/{}ß\\[\\]\\s]/).test(data._stateId) ? '' : 'please enter a valid id, the following chars are not allowed \\'*?\"\\'`´,;:<>#/{}ß[] \\''}" - }, "linkedId": { - "type": "text", - "label": "composite id of linked object", - "sm": 12, - "noMultiEdit": true, - "maxLength": 255, - "disabled": "true", - "defaultFunc": "data.linkedId || customObj._id.substring(customObj._id.lastIndexOf('.') + 1)", - "onChange": { - "alsoDependsOn": [ - "_prefixId", - "_stateId" - ], - "calculateFunc": "data._prefixId.length > 0 && data._stateId.length > 0 ? (data._prefixId || '') + '.' + (data._stateId || '') : (data._stateId || '')", - "ignoreOwnChanges": true - } + "type": "custom", + "name": "AdminComponentLinkedDevicesSet/Components/LinkedIdComponent", + "i18n": false, + "url": "custom/customComponents.js", + "sm": 12 }, "name": { "type": "autocompleteSendTo", diff --git a/gulpfile.js b/gulpfile.js index 3e2be2b..7876143 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,3 +1,88 @@ -"use strict"; +const gulp = require('gulp'); +const fs = require('fs'); +const cp = require('child_process'); +const del = require('del'); +const src = `${__dirname}/src/`; -module.exports = require("@iobroker/adapter-dev/gulp")(); \ No newline at end of file +function npmInstall() { + return new Promise((resolve, reject) => { + // Install node modules + const cwd = src.replace(/\\/g, '/'); + + const cmd = `npm install -f`; + console.log(`"${cmd} in ${cwd}`); + + // System call used for update of js-controller itself, + // because during installation npm packet will be deleted too, but some files must be loaded even during the install process. + const exec = cp.exec; + const child = exec(cmd, {cwd}); + + child.stderr.pipe(process.stderr); + child.stdout.pipe(process.stdout); + + child.on('exit', (code /* , signal */) => { + // code 1 is strange error that cannot be explained. Everything is installed but error :( + if (code && code !== 1) { + reject('Cannot install: ' + code); + } else { + console.log(`"${cmd} in ${cwd} finished.`); + // command succeeded + resolve(); + } + }); + }); +} + +function build() { + const version = JSON.parse(fs.readFileSync(__dirname + '/package.json').toString('utf8')).version; + const data = JSON.parse(fs.readFileSync(src + 'package.json').toString('utf8')); + + data.version = version; + + fs.writeFileSync(src + 'package.json', JSON.stringify(data, null, 4)); + + return new Promise((resolve, reject) => { + const options = { + stdio: 'pipe', + cwd: src + }; + + console.log(options.cwd); + + let script = src + 'node_modules/@craco/craco/bin/craco.js'; + if (!fs.existsSync(script)) { + script = __dirname + '/node_modules/@craco/craco/bin/craco.js'; + } + if (!fs.existsSync(script)) { + console.error('Cannot find execution file: ' + script); + reject('Cannot find execution file: ' + script); + } else { + const child = cp.fork(script, ['build'], options); + child.stdout.on('data', data => console.log(data.toString())); + child.stderr.on('data', data => console.log(data.toString())); + child.on('close', code => { + console.log(`child process exited with code ${code}`); + code ? reject(`Exit code: ${code}`) : resolve(); + }); + } + }); +} + +gulp.task('0-clean', () => del(['admin/custom/*', 'admin/custom/**/*', 'src/build/**/*'])); + +gulp.task('1-npm', async () => npmInstall()); +gulp.task('2-compile', async () => build()); + +gulp.task('3-copy', () => Promise.all([ + gulp.src(['src/build/static/js/*.js']).pipe(gulp.dest('admin/custom/static/js')), + gulp.src(['src/build/static/js/*.map']).pipe(gulp.dest('admin/custom/static/js')), + gulp.src(['src/build/customComponents.js']).pipe(gulp.dest('admin/custom')), + gulp.src(['src/build/customComponents.js.map']).pipe(gulp.dest('admin/custom')), + gulp.src(['src/src/i18n/*.json']).pipe(gulp.dest('admin/custom/i18n')), +])); + +gulp.task('build', gulp.series(['0-clean', '1-npm', '2-compile', '3-copy'])); + +gulp.task('default', gulp.series(['build'])); + +// gulp.task('translate', async () => require('@iobroker/adapter-dev').translate()); \ No newline at end of file diff --git a/package.json b/package.json index 8d484fb..6a15f86 100644 --- a/package.json +++ b/package.json @@ -45,12 +45,14 @@ "chai": "^4.3.6", "eslint": "^7.32.0", "gulp": "^4.0.2", - "mocha": "^9.2.2" + "mocha": "^9.2.2", + "del": "^6.1.1" }, "main": "main.js", "scripts": { "test": "node node_modules/mocha/bin/mocha --exit", "translate": "node node_modules/gulp/bin/gulp.js adminWords2languages", + "build": "gulp", "release": "release-script", "release-patch": "release-script patch --c .releaseconfig.json --all", "release-minor": "release-script minor --c .releaseconfig.json --all", diff --git a/src/craco.config.js b/src/craco.config.js new file mode 100644 index 0000000..407996d --- /dev/null +++ b/src/craco.config.js @@ -0,0 +1,33 @@ +const CracoEsbuildPlugin = require('craco-esbuild'); +const { ProvidePlugin } = require('webpack'); +const cracoModuleFederation = require('craco-module-federation'); + +module.exports = { + plugins: [ + { plugin: CracoEsbuildPlugin }, + { plugin: cracoModuleFederation, options: { useNamedChunkIds: true } } + ], + devServer: { + proxy: { + '/files': 'http://localhost:8081', + '/adapter': 'http://localhost:8081', + '/session': 'http://localhost:8081', + '/log': 'http://localhost:8081', + '/lib': 'http://localhost:8081', + } + }, + webpack: { + output: { + publicPath: './', + }, + plugins: [ + new ProvidePlugin({ + React: 'react', + }), + ], + configure: webpackConfig => { + webpackConfig.output.publicPath = './'; + return webpackConfig; + }, + }, +}; diff --git a/src/modulefederation.config.js b/src/modulefederation.config.js new file mode 100644 index 0000000..0597eea --- /dev/null +++ b/src/modulefederation.config.js @@ -0,0 +1,21 @@ +const makeShared = pkgs => { + const result = {}; + pkgs.forEach( + packageName => { + result[packageName] = { + requiredVersion: '*', + singleton: true, + }; + }, + ); + return result; +}; + +module.exports = { + name: 'AdminComponentLinkedDevicesSet', + filename: 'customComponents.js', + exposes: { + './Components': './src/Components.jsx', + }, + shared: makeShared(['@mui/material', '@mui/styles', '@iobroker/adapter-react-v5', 'react', 'react-dom', 'prop-types']) +}; diff --git a/src/package.json b/src/package.json new file mode 100644 index 0000000..e585ee9 --- /dev/null +++ b/src/package.json @@ -0,0 +1,45 @@ +{ + "name": "iobroker-admin-component-easy-access", + "private": true, + "version": "1.5.5", + "scripts": { + "start": "set PORT=4173 && craco start", + "build": "craco build" + }, + "dependencies": {}, + "devDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@iobroker/adapter-react-v5": "^3.0.14", + "@mui/material": "^5.8.1", + "@mui/styles": "^5.8.0", + "prop-types": "^15.8.1", + "react": "^18.1.0", + "react-ace": "^10.1.0", + "react-dom": "^18.1.0", + "react-scripts": "^5.0.1", + "react-refresh": "^0.14.0", + "@originjs/vite-plugin-federation": "^1.1.6", + "@rollup/plugin-babel": "^5.3.1", + "@rollup/plugin-commonjs": "^22.0.0", + "@rollup/plugin-node-resolve": "^13.3.0", + "@rollup/plugin-replace": "^4.0.0", + "@types/react": "^18.0.9", + "@types/react-dom": "^18.0.5", + "@craco/craco": "^6.4.3", + "craco-esbuild": "^0.5.1", + "craco-module-federation": "^1.1.0" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/src/public/index.html b/src/public/index.html new file mode 100644 index 0000000..56783b2 --- /dev/null +++ b/src/public/index.html @@ -0,0 +1,25 @@ + + + + + + + Admin App + + + +
+ + + diff --git a/src/src/App.jsx b/src/src/App.jsx new file mode 100644 index 0000000..9ccf778 --- /dev/null +++ b/src/src/App.jsx @@ -0,0 +1,78 @@ +// this file used only for simulation and not used in end build + +import React from 'react'; +import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles'; + +import withStyles from '@mui/styles/withStyles'; + +import GenericApp from '@iobroker/adapter-react-v5/GenericApp'; +import I18n from '@iobroker/adapter-react-v5/i18n'; +import Loader from '@iobroker/adapter-react-v5/Components/Loader'; + +import LinkedIdComponent from './LinkedIdComponent'; + +const styles = theme => ({ + app: { + backgroundColor: theme.palette.background.default, + color: theme.palette.text.primary, + height: '100%', + }, + item: { + padding: 50, + width: 400, + } +}); + +class App extends GenericApp { + constructor(props) { + const extendedProps = { ...props }; + super(props, extendedProps); + + this.state = { + data: { myCustomAttribute: 'prefix1.prefix2.state' }, + theme: this.createTheme(), + }; + + I18n.setLanguage((navigator.language || navigator.userLanguage || 'en').substring(0, 2).toLowerCase()); + } + + render() { + if (!this.state.loaded) { + return + + + + ; + } + + return + +
+
+ {}} + customObj={{ _id: 'test.0.myPrefix.myState' }} + alive + adapterName="linkeddevices" + instance="0" + schema={{ + name: 'AdminComponentLinkedDevicesSet/Components/LinkedIdComponent', + type: 'custom', + }} + onChange={data => { + this.setState({ data }); + }} + /> +
+
+
+
; + } +} + +export default withStyles(styles)(App); \ No newline at end of file diff --git a/src/src/Components.jsx b/src/src/Components.jsx new file mode 100644 index 0000000..d2c6f05 --- /dev/null +++ b/src/src/Components.jsx @@ -0,0 +1,3 @@ +import LinkedIdComponent from './LinkedIdComponent'; + +export default { LinkedIdComponent }; \ No newline at end of file diff --git a/src/src/LinkedIdComponent.jsx b/src/src/LinkedIdComponent.jsx new file mode 100644 index 0000000..0f8b05f --- /dev/null +++ b/src/src/LinkedIdComponent.jsx @@ -0,0 +1,203 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@mui/styles'; + +import { Autocomplete, TextField, Grid } from '@mui/material'; + +// important to make from package and not from some children. +// invalid +// import ConfigGeneric from '@iobroker/adapter-react-v5/ConfigGeneric'; +// valid +import { ConfigGeneric, I18n } from '@iobroker/adapter-react-v5'; + +const styles = theme => ({ + table: { + minWidth: 400 + }, + header: { + fontSize: 16, + fontWeight: 'bold' + } +}); + +class LinkedIdComponent extends ConfigGeneric { + componentDidMount() { + super.componentDidMount(); + let value = ConfigGeneric.getValue(this.props.data, this.props.attr); + value = value || this.props.customObj._id.substring(this.props.customObj._id.lastIndexOf('.') + 1); + + this.setState({ value, suggestions_stateId: [], suggestions_prefixId: [] }); + + // Send request to instance + this.askInstance('suggestions_stateId') + .then(() => this.askInstance('suggestions_prefixId')); + } + + askInstance(command) { + if (this.props.alive) { + return this.props.socket.sendTo(`${this.props.adapterName}.${this.props.instance}`, command, null) + .then(list => { + const options = []; + if (list && Array.isArray(list)) { + list.forEach(item => + options.push({label: item, value: item})); + } + this.setState({[command]: options}); + }); + } else { + return Promise.resolve(null); + } + } + + renderPrefixId() { + let prefixId = (this.state.value || '').includes('.') ? this.state.value.substring(0, this.state.value.lastIndexOf('.')) : ''; + let options = JSON.parse(JSON.stringify(this.state.suggestions_prefixId || [])); + let item = prefixId !== null && prefixId !== undefined && + //eslint-disable-next-line + options.find(item => item.value === prefixId); // let "==" be and not === + + if (prefixId !== null && prefixId !== undefined && !item) { + item = {value: prefixId, label: prefixId}; + options.push(item); + } + item = item || null; + + const noError = (prefixId && prefixId.length > 0 && !(/[*?"'`´,;:<>#/{}ß\[\]\s]/).test(prefixId)) || prefixId === ''; + + return + (option && option.label) || ''} + className={this.props.classes.indeterminate} + onInputChange={e => { + if (e) { + const val = e.target.value; + let prefixId = (this.state.value || '').includes('.') ? this.state.value.substring(0, this.state.value.lastIndexOf('.')) : ''; + if (val !== prefixId) { + let stateId = (this.state.value || '').split('.').pop(); + const value = LinkedIdComponent.calcValue(val, stateId); + this.setState({ value }, () => this.onChange(this.props.attr, value)); + } + } + }} + onChange={(_, value) => { + const val = typeof value === 'object' ? (value ? value.value : '') : value; + let prefixId = (this.state.value || '').includes('.') ? this.state.value.substring(0, this.state.value.lastIndexOf('.')) : ''; + if (val !== prefixId) { + let stateId = (this.state.value || '').split('.').pop(); + const value = LinkedIdComponent.calcValue(val, stateId); + this.setState({ value }, () => + this.onChange(this.props.attr, value)); + } + }} + renderInput={(params) => + } + /> + ; + } + + static calcValue(prefix, stateId) { + return prefix && stateId ? `${prefix}.${stateId}` : (stateId || ''); + } + + renderStateId() { + let stateId = (this.state.value || '').split('.').pop(); + let options = JSON.parse(JSON.stringify(this.state.suggestions_stateId || [])); + let item = stateId !== null && stateId !== undefined && + //eslint-disable-next-line + options.find(item => item.value === stateId); // let "==" be and not === + + if (stateId !== null && stateId !== undefined && !item) { + item = {value: stateId, label: stateId}; + options.push(item); + } + item = item || null; + + const noError = stateId && stateId.length > 0 && !(/[*?"'`´,;:<>#/{}ß\[\]\s]/).test(stateId); + + return + (option && option.label) || ''} + className={this.props.classes.indeterminate} + onInputChange={e => { + if (e) { + const val = e.target.value; + let stateId = (this.state.value || '').split('.').pop(); + if (val !== stateId) { + let prefixId = (this.state.value || '').includes('.') ? this.state.value.substring(0, this.state.value.lastIndexOf('.')) : ''; + const value = LinkedIdComponent.calcValue(prefixId, val); + this.setState({ value }, () => this.onChange(this.props.attr, value)); + } + } + }} + onChange={(_, value) => { + const val = typeof value === 'object' ? (value ? value.value : '') : value; + let stateId = (this.state.value || '').split('.').pop(); + if (val !== stateId) { + let prefixId = (this.state.value || '').includes('.') ? this.state.value.substring(0, this.state.value.lastIndexOf('.')) : ''; + const value = LinkedIdComponent.calcValue(prefixId, val); + this.setState({ value }, () => this.onChange(this.props.attr, value)); + } + }} + renderInput={(params) => + } + /> + ; + } + + renderItem() { + return + {this.renderPrefixId()} + {this.renderStateId()} + + + + ; + } +} + +LinkedIdComponent.propTypes = { + socket: PropTypes.object.isRequired, + themeType: PropTypes.string, + themeName: PropTypes.string, + style: PropTypes.object, + className: PropTypes.string, + data: PropTypes.object.isRequired, + attr: PropTypes.string, + schema: PropTypes.object, + onError: PropTypes.func, + onChange: PropTypes.func, +}; + +export default withStyles(styles)(LinkedIdComponent); \ No newline at end of file diff --git a/src/src/bootstrap.jsx b/src/src/bootstrap.jsx new file mode 100644 index 0000000..d8e9845 --- /dev/null +++ b/src/src/bootstrap.jsx @@ -0,0 +1,32 @@ +// this file used only for simulation and not used in end build + +/* eslint-disable */ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles'; +import Utils from '@iobroker/adapter-react-v5/Components/Utils'; +import App from './App'; +import theme from './theme'; + +window.adapterName = 'adapter-component-linked-devices'; +let themeName = Utils.getThemeName(); + +function build() { + const container = document.getElementById('root'); + const root = createRoot(container); + return root.render( + + + { + themeName = _theme; + build(); + }} + /> + + + ); +} + +build(); \ No newline at end of file diff --git a/src/src/i18n/de.json b/src/src/i18n/de.json new file mode 100644 index 0000000..e8dbd1c --- /dev/null +++ b/src/src/i18n/de.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Präfix für die ID des verknüpften Objekts", + "error_prefix": "folgende Zeichen sind nicht erlaubt '*?\"`´,;:<>#/{}ß[] und Leerzeichen", + "ID of linked object": "ID des verknüpften Objekts", + "error_stateId": "Bitte geben Sie eine gültige ID ein, die folgenden Zeichen sind nicht erlaubt *?\"'`´,;:<>#/{}ß[] und Leerzeichen", + "Composite id of linked object": "Zusammengesetzte ID des verknüpften Objekts" +} \ No newline at end of file diff --git a/src/src/i18n/en.json b/src/src/i18n/en.json new file mode 100644 index 0000000..c11bada --- /dev/null +++ b/src/src/i18n/en.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Prefix for ID of linked object", + "error_prefix": "the following chars are not allowed '*?\"`´,;:<>#/{}ß[] and spaces", + "ID of linked object": "ID of linked object", + "error_stateId": "please enter a valid id, the following chars are not allowed *?\"'`´,;:<>#/{}ß[] and spaces", + "Composite id of linked object": "Composite id of linked object" +} \ No newline at end of file diff --git a/src/src/i18n/es.json b/src/src/i18n/es.json new file mode 100644 index 0000000..839aa70 --- /dev/null +++ b/src/src/i18n/es.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Prefijo para ID de objeto vinculado", + "error_prefix": "los siguientes caracteres no están permitidos '*?\"`´,;:<>#/{}ß[] y espacios", + "ID of linked object": "ID del objeto vinculado", + "error_stateId": "ingrese una identificación válida, los siguientes caracteres no están permitidos *?\"'`´,;:<>#/{}ß[] y espacios", + "Composite id of linked object": "ID compuesto del objeto vinculado" +} \ No newline at end of file diff --git a/src/src/i18n/fr.json b/src/src/i18n/fr.json new file mode 100644 index 0000000..82d27bf --- /dev/null +++ b/src/src/i18n/fr.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Préfixe pour l'ID de l'objet lié", + "error_prefix": "les caractères suivants ne sont pas autorisés '*?\"`´,;:<>#/{}ß[] et espaces", + "ID of linked object": "ID de l'objet lié", + "error_stateId": "veuillez saisir un identifiant valide, les caractères suivants ne sont pas autorisés *?\"'`´,;:<>#/{}ß[] et espaces", + "Composite id of linked object": "ID composite de l'objet lié" +} \ No newline at end of file diff --git a/src/src/i18n/it.json b/src/src/i18n/it.json new file mode 100644 index 0000000..1f106e6 --- /dev/null +++ b/src/src/i18n/it.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Prefisso per l'ID dell'oggetto collegato", + "error_prefix": "i seguenti caratteri non sono consentiti '*?\"`´,;:<>#/{}ß[] e spazi", + "ID of linked object": "ID dell'oggetto collegato", + "error_stateId": "inserisci un ID valido, i seguenti caratteri non sono consentiti *?\"'`´,;:<>#/{}ß[] e spazi", + "Composite id of linked object": "ID composito dell'oggetto collegato" +} \ No newline at end of file diff --git a/src/src/i18n/nl.json b/src/src/i18n/nl.json new file mode 100644 index 0000000..3621eb4 --- /dev/null +++ b/src/src/i18n/nl.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Prefix voor ID van gekoppeld object", + "error_prefix": "de volgende tekens zijn niet toegestaan '*?\"`´,;:<>#/{}ß[] en spaties", + "ID of linked object": "ID van gekoppeld object", + "error_stateId": "voer een geldige id in, de volgende tekens zijn niet toegestaan *?\"''´,;:<>#/{}ß[] en spaties", + "Composite id of linked object": "Samengestelde id van gekoppeld object" +} \ No newline at end of file diff --git a/src/src/i18n/pl.json b/src/src/i18n/pl.json new file mode 100644 index 0000000..e17ce39 --- /dev/null +++ b/src/src/i18n/pl.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Prefiks dla identyfikatora połączonego obiektu", + "error_prefix": "następujące znaki nie są dozwolone '*?\"`',;:<>#/{}ß[] i spacje", + "ID of linked object": "Identyfikator połączonego obiektu", + "error_stateId": "proszę podać poprawny identyfikator, następujące znaki nie są dozwolone *?\"'`´,;:<>#/{}ß[] i spacje", + "Composite id of linked object": "Złożony identyfikator połączonego obiektu" +} \ No newline at end of file diff --git a/src/src/i18n/pt.json b/src/src/i18n/pt.json new file mode 100644 index 0000000..ea9426b --- /dev/null +++ b/src/src/i18n/pt.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Prefixo para ID do objeto vinculado", + "error_prefix": "os seguintes caracteres não são permitidos '*?\"`´,;:<>#/{}ß[] e espaços", + "ID of linked object": "ID do objeto vinculado", + "error_stateId": "digite um id válido, os seguintes caracteres não são permitidos *?\"'`´,;:<>#/{}ß[] e espaços", + "Composite id of linked object": "ID composto do objeto vinculado" +} \ No newline at end of file diff --git a/src/src/i18n/ru.json b/src/src/i18n/ru.json new file mode 100644 index 0000000..b863bec --- /dev/null +++ b/src/src/i18n/ru.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "Префикс для идентификатора связанного объекта", + "error_prefix": "следующие символы не допускаются '*?\"`´,;:<>#/{}ß[] и пробелы", + "ID of linked object": "ID связанного объекта", + "error_stateId": "пожалуйста, введите действительный идентификатор, следующие символы не допускаются *?\"'`´,;:<>#/{}ß[] и пробелы", + "Composite id of linked object": "Составной идентификатор связанного объекта" +} \ No newline at end of file diff --git a/src/src/i18n/zh-cn.json b/src/src/i18n/zh-cn.json new file mode 100644 index 0000000..6c2fc66 --- /dev/null +++ b/src/src/i18n/zh-cn.json @@ -0,0 +1,7 @@ +{ + "Prefix for ID of linked object": "链接对象的 ID 前缀", + "error_prefix": "不允许使用以下字符 '*?\"`´,;:<>#/{}ß[] 和空格", + "ID of linked object": "链接对象的 ID", + "error_stateId": "请输入有效的 id,不允许使用以下字符 *?\"'`´,;:<>#/{}ß[] 和空格", + "Composite id of linked object": "链接对象的复合 id" +} \ No newline at end of file diff --git a/src/src/index.jsx b/src/src/index.jsx new file mode 100644 index 0000000..cebfcab --- /dev/null +++ b/src/src/index.jsx @@ -0,0 +1,3 @@ +// this file used only for simulation and not used in end build + +import('./bootstrap'); diff --git a/src/src/theme.js b/src/src/theme.js new file mode 100644 index 0000000..7fc8612 --- /dev/null +++ b/src/src/theme.js @@ -0,0 +1,19 @@ +// this file used only for simulation and not used in end build +import Theme from '@iobroker/adapter-react-v5/Theme'; + +export default type => { + const danger = '#dd5325'; + const success = '#73b6a8'; + const theme = { ...Theme(type) }; + if (!theme) { + return theme; + } + theme.palette.text.danger = { + color: danger, + }; + theme.palette.text.success = { + color: success, + }; + + return theme; +}; \ No newline at end of file