@iobroker/gui-components 10.3.15 → 10.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +21 -1
  2. package/build/Components/AnimatedIcons/IconCopyToClipboard.d.ts +25 -0
  3. package/build/Components/AnimatedIcons/IconCopyToClipboard.js +84 -0
  4. package/build/Components/AnimatedIcons/IconCopyToClipboard.js.map +1 -0
  5. package/build/Components/AnimatedIcons/IconFilter.d.ts +23 -0
  6. package/build/Components/AnimatedIcons/IconFilter.js +26 -0
  7. package/build/Components/AnimatedIcons/IconFilter.js.map +1 -0
  8. package/build/Components/AnimatedIcons/IconFolder.d.ts +6 -0
  9. package/build/Components/AnimatedIcons/IconFolder.js +2 -1
  10. package/build/Components/AnimatedIcons/IconFolder.js.map +1 -1
  11. package/build/Components/AnimatedIcons/IconThemeMode.d.ts +22 -0
  12. package/build/Components/AnimatedIcons/IconThemeMode.js +32 -0
  13. package/build/Components/AnimatedIcons/IconThemeMode.js.map +1 -0
  14. package/build/Components/AnimatedIcons/IconUpload.d.ts +24 -0
  15. package/build/Components/AnimatedIcons/IconUpload.js +37 -0
  16. package/build/Components/AnimatedIcons/IconUpload.js.map +1 -0
  17. package/build/Components/AnimatedIcons/common.d.ts +2 -0
  18. package/build/Components/AnimatedIcons/common.js +64 -5
  19. package/build/Components/AnimatedIcons/common.js.map +1 -1
  20. package/build/Components/ColorPicker.js +4 -3
  21. package/build/Components/ColorPicker.js.map +1 -1
  22. package/build/Components/FileBrowser.d.ts +6 -0
  23. package/build/Components/FileBrowser.js +54 -12
  24. package/build/Components/FileBrowser.js.map +1 -1
  25. package/build/Components/FileViewer.js +3 -2
  26. package/build/Components/FileViewer.js.map +1 -1
  27. package/build/Components/ObjectBrowser/ObjectBrowserClass.d.ts +15 -0
  28. package/build/Components/ObjectBrowser/ObjectBrowserClass.js +134 -6
  29. package/build/Components/ObjectBrowser/ObjectBrowserClass.js.map +1 -1
  30. package/build/Components/ObjectBrowser/contextMenu.js +3 -2
  31. package/build/Components/ObjectBrowser/contextMenu.js.map +1 -1
  32. package/build/Components/ObjectBrowser/renderLeaf.js +78 -59
  33. package/build/Components/ObjectBrowser/renderLeaf.js.map +1 -1
  34. package/build/Components/ObjectBrowser/rowAnimation.d.ts +25 -1
  35. package/build/Components/ObjectBrowser/rowAnimation.js +46 -19
  36. package/build/Components/ObjectBrowser/rowAnimation.js.map +1 -1
  37. package/build/Components/ObjectBrowser/skeleton.d.ts +15 -0
  38. package/build/Components/ObjectBrowser/skeleton.js +106 -0
  39. package/build/Components/ObjectBrowser/skeleton.js.map +1 -0
  40. package/build/Components/ObjectBrowser/styles.js +16 -11
  41. package/build/Components/ObjectBrowser/styles.js.map +1 -1
  42. package/build/Components/ObjectBrowser/toolbar.js +18 -14
  43. package/build/Components/ObjectBrowser/toolbar.js.map +1 -1
  44. package/build/Components/ObjectBrowser/utils.d.ts +4 -0
  45. package/build/Components/ObjectBrowser/utils.js +4 -0
  46. package/build/Components/ObjectBrowser/utils.js.map +1 -1
  47. package/build/Components/SaveCloseButtons.d.ts +12 -1
  48. package/build/Components/SaveCloseButtons.js +38 -2
  49. package/build/Components/SaveCloseButtons.js.map +1 -1
  50. package/build/Components/ToggleThemeMenu.js +11 -8
  51. package/build/Components/ToggleThemeMenu.js.map +1 -1
  52. package/build/Components/TreeTable.d.ts +16 -0
  53. package/build/Components/TreeTable.js +106 -18
  54. package/build/Components/TreeTable.js.map +1 -1
  55. package/build/Dialogs/ComplexCron.js +3 -2
  56. package/build/Dialogs/ComplexCron.js.map +1 -1
  57. package/build/Dialogs/Error.js +3 -2
  58. package/build/Dialogs/Error.js.map +1 -1
  59. package/build/index.d.ts +4 -0
  60. package/build/index.js +4 -0
  61. package/build/index.js.map +1 -1
  62. package/package.json +5 -5
@@ -3,11 +3,12 @@
3
3
  import React, { Component } from 'react';
4
4
  import { TextField, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton } from '@mui/material';
5
5
  // Icons
6
- import { Close as CloseIcon, Save as SaveIcon, Brightness6 as Brightness5Icon, ContentCopy as CopyIcon, } from '@mui/icons-material';
6
+ import { Close as CloseIcon, Save as SaveIcon, Brightness6 as Brightness5Icon } from '@mui/icons-material';
7
7
  import { IconNoIcon } from '../icons/IconNoIcon';
8
8
  import { withWidth } from './withWidth';
9
9
  import { Utils } from './Utils';
10
10
  import { Icon } from './Icon';
11
+ import { IconCopyToClipboard } from './AnimatedIcons/IconCopyToClipboard';
11
12
  const styles = {
12
13
  dialog: {
13
14
  height: '100%',
@@ -235,7 +236,7 @@ export class FileViewerClass extends Component {
235
236
  e.stopPropagation();
236
237
  e.preventDefault();
237
238
  Utils.copyToClipboard(this.state.text || this.state.code || '');
238
- }, startIcon: React.createElement(CopyIcon, null) }, this.props.t('Copy content'))) : null,
239
+ }, startIcon: React.createElement(IconCopyToClipboard, null) }, this.props.t('Copy content'))) : null,
239
240
  this.state.editing ? (React.createElement(Button, { color: "grey", disabled: this.state.editingValue === this.state.code ||
240
241
  this.state.editingValue === this.state.text, variant: "contained", onClick: () => this.onSave(), startIcon: React.createElement(SaveIcon, null) }, this.props.t('Save'))) : null,
241
242
  React.createElement(Button, { variant: "contained", onClick: () => this.props.onClose(), color: "primary", startIcon: React.createElement(CloseIcon, null) }, this.props.t('Close')))));
@@ -1 +1 @@
1
- {"version":3,"file":"FileViewer.js","sourceRoot":"./src/","sources":["Components/FileViewer.tsx"],"names":[],"mappings":"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","sourcesContent":["// File viewer in adapter-react does not support write\n// import { Buffer } from 'buffer';\nimport React, { Component, type JSX } from 'react';\n\nimport { TextField, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton } from '@mui/material';\n\n// Icons\nimport {\n Close as CloseIcon,\n Save as SaveIcon,\n Brightness6 as Brightness5Icon,\n ContentCopy as CopyIcon,\n} from '@mui/icons-material';\n\nimport type { Connection } from '@iobroker/socket-client';\n\nimport { IconNoIcon } from '../icons/IconNoIcon';\nimport { withWidth } from './withWidth';\nimport { Utils } from './Utils';\nimport type { ThemeType, Translate } from '../types';\nimport { Icon } from './Icon';\n\nconst styles: Record<string, React.CSSProperties> = {\n dialog: {\n height: '100%',\n },\n paper: {\n height: 'calc(100% - 64px)',\n },\n content: {\n textAlign: 'center',\n },\n textarea: {\n width: '100%',\n height: '100%',\n },\n img: {\n width: 'auto',\n height: 'calc(100% - 5px)',\n objectFit: 'contain',\n },\n dialogTitle: {\n justifyContent: 'space-between',\n display: 'flex',\n },\n};\n\nexport const EXTENSIONS = {\n images: ['png', 'jpg', 'svg', 'jpeg', 'bmp', 'gif', 'apng', 'avif', 'webp', 'ico'],\n code: ['js', 'json', 'json5', 'md'],\n txt: ['log', 'txt', 'html', 'css', 'xml', 'ics', 'csv'],\n audio: ['mp3', 'wav', 'ogg', 'acc'],\n video: ['mp4', 'mov', 'avi'],\n};\n\nfunction bufferToBase64(buffer: Buffer, isFull?: boolean): string {\n let binary = '';\n const bytes = new Uint8Array((buffer as unknown as { data: number[]; type: 'Buffer' })?.data || buffer);\n const len = bytes.byteLength;\n for (let i = 0; i < len && (isFull || i < 50); i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window.btoa(binary);\n}\n\nexport interface FileViewerProps {\n /** Translation function */\n t: Translate;\n /** Callback when the viewer is closed. */\n onClose: () => void;\n /** The URL (file path) to the file to be displayed. */\n href: string;\n formatEditFile?: string;\n socket: Connection;\n setStateBackgroundImage: () => void;\n themeType: ThemeType;\n getStyleBackgroundImage: () => React.CSSProperties | null;\n /** Flag is the js-controller support subscribe on file */\n supportSubscribes?: boolean;\n}\n\nexport interface FileViewerState {\n text: string | null;\n code: string | null;\n ext: string | null;\n editing: boolean;\n editingValue: string | null;\n copyPossible: boolean;\n forceUpdate: number;\n changed: boolean;\n imgError: boolean;\n}\n\nexport class FileViewerClass extends Component<FileViewerProps, FileViewerState> {\n private timeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(props: FileViewerProps) {\n super(props);\n const ext = Utils.getFileExtension(props.href);\n\n this.state = {\n text: null,\n code: null,\n ext,\n // File viewer in adapter-react does not support write\n editing: /* !!this.props.formatEditFile || */ false,\n editingValue: null,\n copyPossible: !!ext && (EXTENSIONS.code.includes(ext) || EXTENSIONS.txt.includes(ext)),\n forceUpdate: Date.now(),\n changed: false,\n imgError: false,\n };\n }\n\n readFile(): void {\n if (this.props.href) {\n const parts = this.props.href.split('/');\n parts.splice(0, 2);\n const adapter = parts[0];\n const name = parts.splice(1).join('/');\n\n this.props.socket\n .readFile(adapter, name)\n .then((data: { file: string | Buffer; mimeType: string }) => {\n let fileData: string | Buffer = '';\n if (data.file !== undefined) {\n fileData = (data as { file: string; mimeType: string }).file;\n }\n\n const newState: Partial<FileViewerState> = {\n copyPossible: this.state.copyPossible,\n ext: this.state.ext,\n };\n // try to detect valid extension\n if ((fileData as unknown as { data: Buffer; type: string }).type === 'Buffer') {\n if (name.toLowerCase().endsWith('.json5')) {\n newState.ext = 'json5';\n newState.copyPossible = true;\n try {\n fileData = atob(bufferToBase64(fileData as unknown as Buffer, true));\n } catch {\n console.error('Cannot convert base64 to string');\n fileData = '';\n }\n } else {\n const ext = Utils.detectMimeType(bufferToBase64(fileData as unknown as Buffer));\n if (ext) {\n newState.ext = ext;\n newState.copyPossible = EXTENSIONS.code.includes(ext) || EXTENSIONS.txt.includes(ext);\n }\n }\n }\n\n if (newState.copyPossible) {\n if (newState.ext && EXTENSIONS.txt.includes(newState.ext)) {\n newState.text = fileData;\n newState.editingValue = fileData;\n } else if (newState.ext && EXTENSIONS.code.includes(newState.ext)) {\n newState.code = fileData;\n newState.editingValue = fileData;\n }\n }\n\n this.setState(newState as FileViewerState);\n })\n .catch(e => window.alert(`Cannot read file: ${e}`));\n }\n }\n\n componentDidMount(): void {\n this.readFile();\n\n const parts = this.props.href.split('/');\n parts.splice(0, 2);\n const adapter = parts[0];\n const name = parts.splice(1).join('/');\n\n if (this.props.supportSubscribes) {\n this.props.socket\n .subscribeFiles(adapter, name, this.onFileChanged)\n .catch(e => window.alert(`Cannot subscribe on file: ${e}`));\n }\n }\n\n componentWillUnmount(): void {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n const parts = this.props.href.split('/');\n parts.splice(0, 2);\n const adapter = parts[0];\n const name = parts.splice(1).join('/');\n if (this.props.supportSubscribes) {\n this.props.socket.unsubscribeFiles(adapter, name, this.onFileChanged);\n }\n }\n\n onFileChanged = (_id: string, _fileName: string, size: number | null): void => {\n if (!this.state.changed) {\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n this.timeout = setTimeout(() => {\n this.timeout = null;\n if (size === null) {\n window.alert('Show file was deleted!');\n } else if (this.state.text !== null || this.state.code !== null) {\n this.readFile();\n } else {\n this.setState({ forceUpdate: Date.now() });\n }\n }, 300);\n }\n };\n\n getEditorOrViewer(): JSX.Element {\n return (\n <TextField\n variant=\"standard\"\n style={styles.textarea}\n multiline\n value={this.state.editingValue || this.state.code || this.state.text}\n // onChange={newValue => this.setState({ editingValue: newValue, changed: true })}\n slotProps={{\n htmlInput: {\n readOnly: !this.state.editing,\n },\n }}\n />\n );\n }\n\n getContent(): React.JSX.Element | null {\n if (this.state.ext && EXTENSIONS.images.includes(this.state.ext)) {\n if (this.state.imgError) {\n return <IconNoIcon style={{ ...styles.img, ...this.props.getStyleBackgroundImage() }} />;\n }\n return (\n <Icon\n onError={e => {\n (e.target as HTMLImageElement).onerror = null;\n this.setState({ imgError: true });\n }}\n style={{ ...styles.img, ...this.props.getStyleBackgroundImage() }}\n src={`${this.props.href}?ts=${this.state.forceUpdate}`}\n alt={this.props.href}\n />\n );\n }\n if (this.state.ext && EXTENSIONS.audio.includes(this.state.ext)) {\n return (\n <div\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n >\n <audio\n style={{ width: '100%' }}\n src={this.props.href}\n controls\n ></audio>\n </div>\n );\n }\n if (this.state.ext && EXTENSIONS.video.includes(this.state.ext)) {\n return (\n <div\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n >\n <video\n style={{ width: '100%', height: '100%' }}\n controls\n >\n <source\n src={this.props.href}\n type={`video/${this.state.ext}`}\n />\n </video>\n </div>\n );\n }\n if (this.state.code !== null || this.state.text !== null || this.state.editing) {\n // File viewer in adapter-react does not support write\n // return <Editor\n // mode={this.getEditFile(this.props.formatEditFile)}\n // themeType={this.props.themeType}\n // value={this.state.editingValue || this.state.code || this.state.text}\n // onChange={this.state.editing ? newValue => this.setState({ editingValue: newValue, changed: true }) : undefined}\n // />;\n return this.getEditorOrViewer();\n }\n return null;\n }\n\n // eslint-disable-next-line class-methods-use-this\n onSave(): void {\n // Do nothing as the file viewer in adapter-react does not support writing\n }\n\n render(): JSX.Element {\n return (\n <Dialog\n sx={{\n '&.MuiDialog-scrollPaper': styles.dialog,\n '& .MuiDialog-paper': styles.paper,\n }}\n scroll=\"paper\"\n open={!!this.props.href}\n onClose={() => this.props.onClose()}\n fullWidth\n maxWidth=\"xl\"\n aria-labelledby=\"ar_dialog_file_view_title\"\n >\n <div style={styles.dialogTitle}>\n <DialogTitle id=\"ar_dialog_file_view_title\">{`${this.props.t(this.state.editing ? 'Edit' : 'View')}: ${this.props.href}`}</DialogTitle>\n {this.state.ext && EXTENSIONS.images.includes(this.state.ext) && (\n <div>\n <IconButton\n size=\"large\"\n color=\"inherit\"\n onClick={this.props.setStateBackgroundImage}\n >\n <Brightness5Icon />\n </IconButton>\n </div>\n )}\n </div>\n <DialogContent style={styles.content}>{this.getContent()}</DialogContent>\n <DialogActions>\n {this.state.copyPossible ? (\n <Button\n color=\"grey\"\n onClick={e => {\n e.stopPropagation();\n e.preventDefault();\n Utils.copyToClipboard(this.state.text || this.state.code || '');\n }}\n startIcon={<CopyIcon />}\n >\n {this.props.t('Copy content')}\n </Button>\n ) : null}\n {this.state.editing ? (\n <Button\n color=\"grey\"\n disabled={\n this.state.editingValue === this.state.code ||\n this.state.editingValue === this.state.text\n }\n variant=\"contained\"\n onClick={() => this.onSave()}\n startIcon={<SaveIcon />}\n >\n {this.props.t('Save')}\n </Button>\n ) : null}\n <Button\n variant=\"contained\"\n onClick={() => this.props.onClose()}\n color=\"primary\"\n startIcon={<CloseIcon />}\n >\n {this.props.t('Close')}\n </Button>\n </DialogActions>\n </Dialog>\n );\n }\n}\nexport const FileViewer = withWidth()(FileViewerClass);\n"]}
1
+ {"version":3,"file":"FileViewer.js","sourceRoot":"./src/","sources":["Components/FileViewer.tsx"],"names":[],"mappings":"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","sourcesContent":["// File viewer in adapter-react does not support write\n// import { Buffer } from 'buffer';\nimport React, { Component, type JSX } from 'react';\n\nimport { TextField, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton } from '@mui/material';\n\n// Icons\nimport { Close as CloseIcon, Save as SaveIcon, Brightness6 as Brightness5Icon } from '@mui/icons-material';\n\nimport type { Connection } from '@iobroker/socket-client';\n\nimport { IconNoIcon } from '../icons/IconNoIcon';\nimport { withWidth } from './withWidth';\nimport { Utils } from './Utils';\nimport type { ThemeType, Translate } from '../types';\nimport { Icon } from './Icon';\nimport { IconCopyToClipboard } from './AnimatedIcons/IconCopyToClipboard';\n\nconst styles: Record<string, React.CSSProperties> = {\n dialog: {\n height: '100%',\n },\n paper: {\n height: 'calc(100% - 64px)',\n },\n content: {\n textAlign: 'center',\n },\n textarea: {\n width: '100%',\n height: '100%',\n },\n img: {\n width: 'auto',\n height: 'calc(100% - 5px)',\n objectFit: 'contain',\n },\n dialogTitle: {\n justifyContent: 'space-between',\n display: 'flex',\n },\n};\n\nexport const EXTENSIONS = {\n images: ['png', 'jpg', 'svg', 'jpeg', 'bmp', 'gif', 'apng', 'avif', 'webp', 'ico'],\n code: ['js', 'json', 'json5', 'md'],\n txt: ['log', 'txt', 'html', 'css', 'xml', 'ics', 'csv'],\n audio: ['mp3', 'wav', 'ogg', 'acc'],\n video: ['mp4', 'mov', 'avi'],\n};\n\nfunction bufferToBase64(buffer: Buffer, isFull?: boolean): string {\n let binary = '';\n const bytes = new Uint8Array((buffer as unknown as { data: number[]; type: 'Buffer' })?.data || buffer);\n const len = bytes.byteLength;\n for (let i = 0; i < len && (isFull || i < 50); i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window.btoa(binary);\n}\n\nexport interface FileViewerProps {\n /** Translation function */\n t: Translate;\n /** Callback when the viewer is closed. */\n onClose: () => void;\n /** The URL (file path) to the file to be displayed. */\n href: string;\n formatEditFile?: string;\n socket: Connection;\n setStateBackgroundImage: () => void;\n themeType: ThemeType;\n getStyleBackgroundImage: () => React.CSSProperties | null;\n /** Flag is the js-controller support subscribe on file */\n supportSubscribes?: boolean;\n}\n\nexport interface FileViewerState {\n text: string | null;\n code: string | null;\n ext: string | null;\n editing: boolean;\n editingValue: string | null;\n copyPossible: boolean;\n forceUpdate: number;\n changed: boolean;\n imgError: boolean;\n}\n\nexport class FileViewerClass extends Component<FileViewerProps, FileViewerState> {\n private timeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(props: FileViewerProps) {\n super(props);\n const ext = Utils.getFileExtension(props.href);\n\n this.state = {\n text: null,\n code: null,\n ext,\n // File viewer in adapter-react does not support write\n editing: /* !!this.props.formatEditFile || */ false,\n editingValue: null,\n copyPossible: !!ext && (EXTENSIONS.code.includes(ext) || EXTENSIONS.txt.includes(ext)),\n forceUpdate: Date.now(),\n changed: false,\n imgError: false,\n };\n }\n\n readFile(): void {\n if (this.props.href) {\n const parts = this.props.href.split('/');\n parts.splice(0, 2);\n const adapter = parts[0];\n const name = parts.splice(1).join('/');\n\n this.props.socket\n .readFile(adapter, name)\n .then((data: { file: string | Buffer; mimeType: string }) => {\n let fileData: string | Buffer = '';\n if (data.file !== undefined) {\n fileData = (data as { file: string; mimeType: string }).file;\n }\n\n const newState: Partial<FileViewerState> = {\n copyPossible: this.state.copyPossible,\n ext: this.state.ext,\n };\n // try to detect valid extension\n if ((fileData as unknown as { data: Buffer; type: string }).type === 'Buffer') {\n if (name.toLowerCase().endsWith('.json5')) {\n newState.ext = 'json5';\n newState.copyPossible = true;\n try {\n fileData = atob(bufferToBase64(fileData as unknown as Buffer, true));\n } catch {\n console.error('Cannot convert base64 to string');\n fileData = '';\n }\n } else {\n const ext = Utils.detectMimeType(bufferToBase64(fileData as unknown as Buffer));\n if (ext) {\n newState.ext = ext;\n newState.copyPossible = EXTENSIONS.code.includes(ext) || EXTENSIONS.txt.includes(ext);\n }\n }\n }\n\n if (newState.copyPossible) {\n if (newState.ext && EXTENSIONS.txt.includes(newState.ext)) {\n newState.text = fileData;\n newState.editingValue = fileData;\n } else if (newState.ext && EXTENSIONS.code.includes(newState.ext)) {\n newState.code = fileData;\n newState.editingValue = fileData;\n }\n }\n\n this.setState(newState as FileViewerState);\n })\n .catch(e => window.alert(`Cannot read file: ${e}`));\n }\n }\n\n componentDidMount(): void {\n this.readFile();\n\n const parts = this.props.href.split('/');\n parts.splice(0, 2);\n const adapter = parts[0];\n const name = parts.splice(1).join('/');\n\n if (this.props.supportSubscribes) {\n this.props.socket\n .subscribeFiles(adapter, name, this.onFileChanged)\n .catch(e => window.alert(`Cannot subscribe on file: ${e}`));\n }\n }\n\n componentWillUnmount(): void {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n const parts = this.props.href.split('/');\n parts.splice(0, 2);\n const adapter = parts[0];\n const name = parts.splice(1).join('/');\n if (this.props.supportSubscribes) {\n this.props.socket.unsubscribeFiles(adapter, name, this.onFileChanged);\n }\n }\n\n onFileChanged = (_id: string, _fileName: string, size: number | null): void => {\n if (!this.state.changed) {\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n this.timeout = setTimeout(() => {\n this.timeout = null;\n if (size === null) {\n window.alert('Show file was deleted!');\n } else if (this.state.text !== null || this.state.code !== null) {\n this.readFile();\n } else {\n this.setState({ forceUpdate: Date.now() });\n }\n }, 300);\n }\n };\n\n getEditorOrViewer(): JSX.Element {\n return (\n <TextField\n variant=\"standard\"\n style={styles.textarea}\n multiline\n value={this.state.editingValue || this.state.code || this.state.text}\n // onChange={newValue => this.setState({ editingValue: newValue, changed: true })}\n slotProps={{\n htmlInput: {\n readOnly: !this.state.editing,\n },\n }}\n />\n );\n }\n\n getContent(): React.JSX.Element | null {\n if (this.state.ext && EXTENSIONS.images.includes(this.state.ext)) {\n if (this.state.imgError) {\n return <IconNoIcon style={{ ...styles.img, ...this.props.getStyleBackgroundImage() }} />;\n }\n return (\n <Icon\n onError={e => {\n (e.target as HTMLImageElement).onerror = null;\n this.setState({ imgError: true });\n }}\n style={{ ...styles.img, ...this.props.getStyleBackgroundImage() }}\n src={`${this.props.href}?ts=${this.state.forceUpdate}`}\n alt={this.props.href}\n />\n );\n }\n if (this.state.ext && EXTENSIONS.audio.includes(this.state.ext)) {\n return (\n <div\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n >\n <audio\n style={{ width: '100%' }}\n src={this.props.href}\n controls\n ></audio>\n </div>\n );\n }\n if (this.state.ext && EXTENSIONS.video.includes(this.state.ext)) {\n return (\n <div\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n >\n <video\n style={{ width: '100%', height: '100%' }}\n controls\n >\n <source\n src={this.props.href}\n type={`video/${this.state.ext}`}\n />\n </video>\n </div>\n );\n }\n if (this.state.code !== null || this.state.text !== null || this.state.editing) {\n // File viewer in adapter-react does not support write\n // return <Editor\n // mode={this.getEditFile(this.props.formatEditFile)}\n // themeType={this.props.themeType}\n // value={this.state.editingValue || this.state.code || this.state.text}\n // onChange={this.state.editing ? newValue => this.setState({ editingValue: newValue, changed: true }) : undefined}\n // />;\n return this.getEditorOrViewer();\n }\n return null;\n }\n\n // eslint-disable-next-line class-methods-use-this\n onSave(): void {\n // Do nothing as the file viewer in adapter-react does not support writing\n }\n\n render(): JSX.Element {\n return (\n <Dialog\n sx={{\n '&.MuiDialog-scrollPaper': styles.dialog,\n '& .MuiDialog-paper': styles.paper,\n }}\n scroll=\"paper\"\n open={!!this.props.href}\n onClose={() => this.props.onClose()}\n fullWidth\n maxWidth=\"xl\"\n aria-labelledby=\"ar_dialog_file_view_title\"\n >\n <div style={styles.dialogTitle}>\n <DialogTitle id=\"ar_dialog_file_view_title\">{`${this.props.t(this.state.editing ? 'Edit' : 'View')}: ${this.props.href}`}</DialogTitle>\n {this.state.ext && EXTENSIONS.images.includes(this.state.ext) && (\n <div>\n <IconButton\n size=\"large\"\n color=\"inherit\"\n onClick={this.props.setStateBackgroundImage}\n >\n <Brightness5Icon />\n </IconButton>\n </div>\n )}\n </div>\n <DialogContent style={styles.content}>{this.getContent()}</DialogContent>\n <DialogActions>\n {this.state.copyPossible ? (\n <Button\n color=\"grey\"\n onClick={e => {\n e.stopPropagation();\n e.preventDefault();\n Utils.copyToClipboard(this.state.text || this.state.code || '');\n }}\n startIcon={<IconCopyToClipboard />}\n >\n {this.props.t('Copy content')}\n </Button>\n ) : null}\n {this.state.editing ? (\n <Button\n color=\"grey\"\n disabled={\n this.state.editingValue === this.state.code ||\n this.state.editingValue === this.state.text\n }\n variant=\"contained\"\n onClick={() => this.onSave()}\n startIcon={<SaveIcon />}\n >\n {this.props.t('Save')}\n </Button>\n ) : null}\n <Button\n variant=\"contained\"\n onClick={() => this.props.onClose()}\n color=\"primary\"\n startIcon={<CloseIcon />}\n >\n {this.props.t('Close')}\n </Button>\n </DialogActions>\n </Dialog>\n );\n }\n}\nexport const FileViewer = withWidth()(FileViewerClass);\n"]}
@@ -97,6 +97,20 @@ export declare class ObjectBrowserClass extends Component<ObjectBrowserProps, Ob
97
97
  private windowLast;
98
98
  /** id -> how often the state of this row has changed. Part of the memo key of the row */
99
99
  readonly rowStateVersion: Record<string, number>;
100
+ /**
101
+ * id -> last change of a number (arrow up or down) or of a boolean (the value flips), see `renderColumnValue`.
102
+ * `shown` is the time the row showed it first, so a row that is rendered again continues the animation.
103
+ */
104
+ readonly valueTrends: Record<string, {
105
+ dir: 'up' | 'down' | 'toggle';
106
+ ts: number;
107
+ shown?: number;
108
+ }>;
109
+ /** id -> last confirmation of a command: the state was written with ack=false and then got ack=true */
110
+ readonly valueAcks: Record<string, {
111
+ ts: number;
112
+ shown?: number;
113
+ }>;
100
114
  /** The running animations of an unfolded or folding node (see `rowAnimation.ts`) */
101
115
  private rowAnimations;
102
116
  /** The node whose children slide under its row at the moment; they are removed when that ends */
@@ -313,6 +327,7 @@ export declare class ObjectBrowserClass extends Component<ObjectBrowserProps, Ob
313
327
  unsubscribe(id: string): void;
314
328
  pauseSubscribe(isPause: boolean): void;
315
329
  clearFilter(): void;
330
+ /** True if no filter is set */
316
331
  isFilterEmpty(): boolean;
317
332
  onExpandAll(root?: TreeItem, expanded?: string[]): void;
318
333
  onCollapseAll(): void;
@@ -10,14 +10,14 @@
10
10
  */
11
11
  /* eslint-disable react/no-unused-class-component-methods -- the members are used by the sibling modules of this directory */
12
12
  import React, { Component, createRef } from 'react';
13
- import { Box, LinearProgress } from '@mui/material';
13
+ import { Box } from '@mui/material';
14
14
  // own
15
15
  import { Connection } from '../../Connection';
16
16
  import { Utils } from '../Utils'; // @iobroker/gui-components/Components/Utils
17
17
  import { TabContainer } from '../TabContainer';
18
18
  import { TabContent } from '../TabContent';
19
19
  import { TabHeader } from '../TabHeader';
20
- import { ROW_HEIGHT, applyFilter, buildTree, findNode, formatValue, generateFile, getName, colVar, widthFromContainer, growVar, getSelectIdIconFromObjects, setCustomValue, } from './utils';
20
+ import { ROW_HEIGHT, TREND_DURATION, ACK_DURATION, applyFilter, buildTree, findNode, formatValue, generateFile, getName, colVar, widthFromContainer, growVar, getSelectIdIconFromObjects, setCustomValue, } from './utils';
21
21
  import { HistoryChart } from './HistoryChart';
22
22
  import { styles } from './styles';
23
23
  import * as dialogs from './dialogs';
@@ -25,6 +25,7 @@ import * as toolbar from './toolbar';
25
25
  import * as leaf from './renderLeaf';
26
26
  import * as contextMenu from './contextMenu';
27
27
  import * as rowAnimation from './rowAnimation';
28
+ import { renderSkeleton } from './skeleton';
28
29
  import { DEFAULT_DATE_FORMAT, DEFAULT_FILTER, ITEM_LEVEL, MIN_COLUMN_WIDTHS, SCREEN_WIDTHS, } from './constants';
29
30
  export { getSelectIdIconFromObjects };
30
31
  let objectsAlreadyLoaded = false;
@@ -124,6 +125,13 @@ export class ObjectBrowserClass extends Component {
124
125
  windowLast = 0;
125
126
  /** id -> how often the state of this row has changed. Part of the memo key of the row */
126
127
  rowStateVersion = {};
128
+ /**
129
+ * id -> last change of a number (arrow up or down) or of a boolean (the value flips), see `renderColumnValue`.
130
+ * `shown` is the time the row showed it first, so a row that is rendered again continues the animation.
131
+ */
132
+ valueTrends = {};
133
+ /** id -> last confirmation of a command: the state was written with ack=false and then got ack=true */
134
+ valueAcks = {};
127
135
  /** The running animations of an unfolded or folding node (see `rowAnimation.ts`) */
128
136
  rowAnimations = [];
129
137
  /** The node whose children slide under its row at the moment; they are removed when that ends */
@@ -208,6 +216,17 @@ export class ObjectBrowserClass extends Component {
208
216
  catch {
209
217
  expanded = [];
210
218
  }
219
+ // the way down to the root is open: above it, there is nothing to choose
220
+ if (props.root) {
221
+ const parts = props.root.split('.');
222
+ for (let i = 1; i <= parts.length; i++) {
223
+ const id = parts.slice(0, i).join('.');
224
+ if (!expanded.includes(id)) {
225
+ expanded.push(id);
226
+ }
227
+ }
228
+ expanded.sort();
229
+ }
211
230
  let filter;
212
231
  const filterStr = props.defaultFilters
213
232
  ? ''
@@ -496,8 +515,15 @@ export class ObjectBrowserClass extends Component {
496
515
  props.types[i] === 'enum') {
497
516
  continue;
498
517
  }
499
- const moreObjects = await props.socket.getObjectViewSystem(props.types[i]);
500
- Object.assign(objects || {}, moreObjects);
518
+ // Only below the root, if there is one. Else from ' ': with an empty start key the view brings
519
+ // the objects under `system.` only.
520
+ const moreObjects = await props.socket.getObjectViewSystem(props.types[i], props.root || ' ', props.root ? `${props.root}.\u9999` : '\u9999');
521
+ // The views `config`, `user` and `group` are keyed by the name of the object, not by its ID
522
+ for (const obj of Object.values(moreObjects)) {
523
+ if (obj?._id) {
524
+ objects[obj._id] = obj;
525
+ }
526
+ }
501
527
  }
502
528
  }
503
529
  this.systemConfig ||=
@@ -1073,6 +1099,20 @@ export class ObjectBrowserClass extends Component {
1073
1099
  item.data.state = undefined;
1074
1100
  }
1075
1101
  }
1102
+ const oldVal = oldState?.val;
1103
+ const newVal = state?.val;
1104
+ if (typeof oldVal === 'number' && typeof newVal === 'number' && oldVal !== newVal) {
1105
+ if (!Number.isNaN(oldVal) && !Number.isNaN(newVal)) {
1106
+ this.valueTrends[id] = { dir: newVal > oldVal ? 'up' : 'down', ts: Date.now() };
1107
+ }
1108
+ }
1109
+ else if (typeof oldVal === 'boolean' && typeof newVal === 'boolean' && oldVal !== newVal) {
1110
+ this.valueTrends[id] = { dir: 'toggle', ts: Date.now() };
1111
+ }
1112
+ // the placeholder of a state that is not loaded yet has no `ack`, so only a real command counts
1113
+ if (oldState?.ack === false && state?.ack === true) {
1114
+ this.valueAcks[id] = { ts: Date.now() };
1115
+ }
1076
1116
  if (state) {
1077
1117
  this.states[id] = state;
1078
1118
  }
@@ -1354,8 +1394,9 @@ export class ObjectBrowserClass extends Component {
1354
1394
  });
1355
1395
  }
1356
1396
  }
1397
+ /** True if no filter is set */
1357
1398
  isFilterEmpty() {
1358
- return (!!this.state.filter.id ||
1399
+ return !(!!this.state.filter.id ||
1359
1400
  !!this.state.filter.name ||
1360
1401
  !!this.state.filter.room?.length ||
1361
1402
  !!this.state.filter.func?.length ||
@@ -2833,7 +2874,7 @@ export class ObjectBrowserClass extends Component {
2833
2874
  this.doFilter(true);
2834
2875
  }
2835
2876
  if (!this.state.loaded) {
2836
- return React.createElement(LinearProgress, { key: `${this.props.dialogName}_c` });
2877
+ return renderSkeleton(this);
2837
2878
  }
2838
2879
  // the container was resized into another width class => other columns are visible, and the
2839
2880
  // stored widths have to be written into the defaults of the new class.
@@ -2892,6 +2933,93 @@ export class ObjectBrowserClass extends Component {
2892
2933
  .newValueBrowser-light {
2893
2934
  animation: newValueAnimation-light 2s ease-in-out;
2894
2935
  }
2936
+ .iob-ob-trend {
2937
+ display: inline-flex;
2938
+ align-self: center;
2939
+ flex-shrink: 0;
2940
+ width: 0.85em;
2941
+ height: 0.85em;
2942
+ margin-left: 4px;
2943
+ opacity: 0;
2944
+ animation: iob-ob-trend-up ${TREND_DURATION}ms ease-out forwards;
2945
+ }
2946
+ .iob-ob-trend svg {
2947
+ width: 100%;
2948
+ height: 100%;
2949
+ fill: currentColor;
2950
+ }
2951
+ .iob-ob-trend-up {
2952
+ color: ${this.props.themeType === 'dark' ? '#66bb6a' : '#2e7d32'};
2953
+ }
2954
+ .iob-ob-trend-down {
2955
+ color: ${this.props.themeType === 'dark' ? '#ef5350' : '#c62828'};
2956
+ animation-name: iob-ob-trend-down;
2957
+ }
2958
+ @keyframes iob-ob-trend-up {
2959
+ 0% { opacity: 0; transform: translateY(45%); }
2960
+ 12% { opacity: 1; transform: none; }
2961
+ 80% { opacity: 1; }
2962
+ 100% { opacity: 0; }
2963
+ }
2964
+ @keyframes iob-ob-trend-down {
2965
+ 0% { opacity: 0; transform: translateY(-45%); }
2966
+ 12% { opacity: 1; transform: none; }
2967
+ 80% { opacity: 1; }
2968
+ 100% { opacity: 0; }
2969
+ }
2970
+ .newValueBrowser-dark.iob-ob-flip {
2971
+ animation: iob-ob-flip 0.32s cubic-bezier(0.3, 1.4, 0.5, 1), newValueAnimation-dark 2s ease-in-out;
2972
+ }
2973
+ .newValueBrowser-light.iob-ob-flip {
2974
+ animation: iob-ob-flip 0.32s cubic-bezier(0.3, 1.4, 0.5, 1), newValueAnimation-light 2s ease-in-out;
2975
+ }
2976
+ @keyframes iob-ob-flip {
2977
+ 0% { transform: perspective(60px) rotateX(90deg); opacity: 0.3; }
2978
+ 100% { transform: none; opacity: 1; }
2979
+ }
2980
+ .iob-ob-ack {
2981
+ display: inline-flex;
2982
+ align-self: center;
2983
+ flex-shrink: 0;
2984
+ width: 0.9em;
2985
+ height: 0.9em;
2986
+ margin-left: 4px;
2987
+ color: ${this.props.themeType === 'dark' ? '#66bb6a' : '#2e7d32'};
2988
+ animation: iob-ob-ack ${ACK_DURATION}ms ease-out forwards;
2989
+ }
2990
+ .iob-ob-ack svg {
2991
+ width: 100%;
2992
+ height: 100%;
2993
+ fill: none;
2994
+ stroke: currentColor;
2995
+ stroke-width: 3;
2996
+ stroke-linecap: round;
2997
+ stroke-linejoin: round;
2998
+ }
2999
+ .iob-ob-ack path {
3000
+ stroke-dasharray: 1 1;
3001
+ stroke-dashoffset: 1;
3002
+ animation: iob-ob-ack-draw 0.35s cubic-bezier(0.65, 0, 0.35, 1) forwards;
3003
+ /* a row that is mounted again continues the drawing too, see continueTrendAnimation */
3004
+ animation-delay: inherit;
3005
+ }
3006
+ @keyframes iob-ob-ack {
3007
+ 0%, 75% { opacity: 1; }
3008
+ 100% { opacity: 0; }
3009
+ }
3010
+ @keyframes iob-ob-ack-draw {
3011
+ to { stroke-dashoffset: 0; }
3012
+ }
3013
+ @media (prefers-reduced-motion: reduce) {
3014
+ .iob-ob-ack path { animation: none; stroke-dashoffset: 0; }
3015
+ .iob-ob-trend { animation-name: iob-ob-trend-fade; }
3016
+ .newValueBrowser-dark.iob-ob-flip { animation: newValueAnimation-dark 2s ease-in-out; }
3017
+ .newValueBrowser-light.iob-ob-flip { animation: newValueAnimation-light 2s ease-in-out; }
3018
+ @keyframes iob-ob-trend-fade {
3019
+ 0%, 80% { opacity: 1; }
3020
+ 100% { opacity: 0; }
3021
+ }
3022
+ }
2895
3023
  .highlight-link .iob-link {
2896
3024
  text-decoration: underline;
2897
3025
  cursor: pointer;