diff --git a/src-editor/src/App.tsx b/src-editor/src/App.tsx index 7e63c5a6..89735de9 100644 --- a/src-editor/src/App.tsx +++ b/src-editor/src/App.tsx @@ -2,7 +2,7 @@ import React from 'react'; import ReactSplit, { SplitDirection } from '@devbookhq/splitter'; import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles'; -import { DragDropContext, type DropResult } from 'react-beautiful-dnd'; +import { DragDropContext, type DropResult, type DragUpdate, DragStart } from 'react-beautiful-dnd'; import { Dialog, DialogTitle, Button, DialogActions, Box } from '@mui/material'; @@ -49,8 +49,6 @@ import type { const styles: Record = { root: (theme: IobTheme): React.CSSProperties => ({ - flexGrow: 1, - display: 'flex', width: '100%', height: '100%', background: theme.palette.background.default, @@ -769,6 +767,7 @@ class App extends GenericApp { this.setState({ autoSave }); } }} + windowWidth={this.state.menuSizes[1]} /> ); } @@ -834,10 +833,11 @@ class App extends GenericApp { onDragEnd = async (result: DropResult): Promise => { const { source, destination, draggableId } = result; + if (destination && draggableId.includes('***') && source.droppableId === 'Lines') { + // Add new line to preset const [instance, stateId] = draggableId.split('***'); try { - // Add new line const obj: ioBroker.StateObject | null | undefined = (await this.socket.getObject(stateId)) as | ioBroker.StateObject | null @@ -891,7 +891,7 @@ class App extends GenericApp { this.onError(e, 'Cannot read object'); } } else if (destination && source.droppableId === destination.droppableId) { - // switch lines order + // switch lines order in the current preset const presetData: ChartConfigMore = JSON.parse(JSON.stringify(this.state.presetData)); // correct commonYAxis @@ -999,31 +999,40 @@ class App extends GenericApp { let splitter: React.JSX.Element | React.JSX.Element[]; if (this.state.menuOpened) { - // @ts-expect-error idk - splitter = - { - this.setState({ resizing: false, menuSizes }); - window.localStorage.setItem('App.echarts.menuSizes', JSON.stringify(menuSizes)); - }} - gutterClassName={this.state.themeType === 'dark' ? 'Dark visGutter' : 'Light visGutter'} + splitter = ( + // @ts-expect-error idk + - {this.renderMenu()} - {this.renderMain()} - - ; + { + this.setState({ resizing: false, menuSizes: [menuSizes[0], 100 - menuSizes[0]] }); + window.localStorage.setItem('App.echarts.menuSizes', JSON.stringify(menuSizes)); + }} + gutterClassName={this.state.themeType === 'dark' ? 'Dark visGutter' : 'Light visGutter'} + > + {this.renderMenu()} + {this.renderMain()} + + + ); } else { - splitter = this.renderMain(); + splitter = splitter = ( + // @ts-expect-error idk + + {this.renderMain()} + ); } return ( diff --git a/src-editor/src/Components/Fields.tsx b/src-editor/src/Components/Fields.tsx index ae29152b..98b99cba 100644 --- a/src-editor/src/Components/Fields.tsx +++ b/src-editor/src/Components/Fields.tsx @@ -27,11 +27,13 @@ const styles: Record = { fontSize: '0.8rem', whiteSpace: 'break-spaces', }, - objectContainer: { display: 'flex' }, + objectContainer: { display: 'flex', alignItems: 'center' }, objectField: { flex: 1 }, objectButton: { marginTop: 'auto', paddingLeft: 0, + maxHeight: 29, + height: 29, }, sliderContainer: { position: 'relative', @@ -165,8 +167,8 @@ export const IOTextField = (props: IOTextFieldProps): React.JSX.Element => ( { name?: boolean; } = {}; - const windowWidth = this.props.width - 95; - const padding = 8; + const windowWidth = (this.props.width || 1024) - 32 - 40 - 20; // 32 is padding, width of folder icon is 40, 20 is drag handle + const padding = 4; - let idWidth: string; if ( windowWidth >= WIDTHS.instance + @@ -370,7 +369,6 @@ class Line extends React.Component { WIDTHS.buttons + padding * 6 ) { - idWidth = `calc(100% - ${WIDTHS.instance + WIDTHS.chartType + WIDTHS.dataType + WIDTHS.color + WIDTHS.name + WIDTHS.buttons + padding * 6}px)`; visible.chartType = true; visible.dataType = true; visible.color = true; @@ -385,7 +383,6 @@ class Line extends React.Component { WIDTHS.buttons + padding * 5 ) { - idWidth = `calc(100% - ${WIDTHS.buttons + WIDTHS.instance + WIDTHS.chartType + WIDTHS.dataType + WIDTHS.color + padding * 5}px)`; visible.chartType = true; visible.dataType = true; visible.color = true; @@ -393,16 +390,10 @@ class Line extends React.Component { windowWidth >= WIDTHS.instance + WIDTHS.id + WIDTHS.chartType + WIDTHS.dataType + WIDTHS.buttons + padding * 4 ) { - idWidth = `calc(100% - ${WIDTHS.buttons + WIDTHS.instance + WIDTHS.chartType + WIDTHS.dataType + padding * 4}px)`; visible.chartType = true; visible.dataType = true; } else if (windowWidth >= WIDTHS.instance + WIDTHS.id + WIDTHS.chartType + WIDTHS.buttons + padding * 3) { - // nothing visible - idWidth = `calc(100% - ${WIDTHS.buttons + WIDTHS.instance + WIDTHS.chartType + padding * 3}px)`; visible.chartType = true; - } else { - // nothing visible - idWidth = `calc(100% - ${WIDTHS.buttons + WIDTHS.instance + padding * 2}px)`; } const hasBarOrPolar = this.props.presetData.l.find( @@ -460,7 +451,7 @@ class Line extends React.Component { )} { const line: ChartLineConfigMore = JSON.parse(JSON.stringify(this.props.line)); line.instance = value; @@ -474,6 +465,9 @@ class Line extends React.Component { instance => (result[instance._id] = instance._id.replace('system.adapter.', '')), ); result.json = 'JSON'; + if (!result[this.props.line.instance]) { + result[this.props.line.instance] = this.props.line.instance.replace('system.adapter.', ''); + } return result; })()} minWidth={WIDTHS.instance} @@ -490,7 +484,6 @@ class Line extends React.Component { value={this.props.line.id} updateValue={this.onIdChanged} theme={this.props.theme} - width={idWidth} name="id" label="ID" customFilter={ @@ -505,7 +498,7 @@ class Line extends React.Component { : null } styles={{ - fieldContainer: { ...styles.shortIdField, ...(this.props.onPaste ? styles.paste : undefined) }, + fieldContainer: { ...styles.shortIdField, ...(this.props.onPaste ? styles.paste : undefined), flexGrow: 1 }, }} socket={this.props.socket} /> @@ -594,7 +587,6 @@ class Line extends React.Component { }} /> ) : null} -
{!this.props.onPaste && this.props.line.chartType !== 'scatterplot' && this.props.line.chartType !== 'bar' && diff --git a/src-editor/src/Components/Mark.tsx b/src-editor/src/Components/Mark.tsx index f73340ce..95ab9618 100644 --- a/src-editor/src/Components/Mark.tsx +++ b/src-editor/src/Components/Mark.tsx @@ -14,16 +14,14 @@ import type { ChartConfigMore, ChartMarkConfig } from '../../../src/types'; const WIDTHS = { lineId: 100, - upperValueOrId: 100, + upperValueOrId: 150, lowerValueOrId: 100, color: 100, fill: 100, - text: 200, - buttons: 100, + text: 150, + buttons: 70, }; -const LINE_HEIGHT = 48; - const styles: Record = { card: (theme: IobTheme): any => ({ borderStyle: 'dashed', @@ -43,9 +41,7 @@ const styles: Record = { m: 0, '&:last-child': { p: 0, - pr: '20px', }, - pr: '20px', }, shortFields: (theme: IobTheme): any => ({ display: 'block', @@ -65,46 +61,33 @@ const styles: Record = { shortLineIdField: { display: 'inline-flex', minWidth: WIDTHS.lineId, - marginLeft: 8, paddingTop: 0, - lineHeight: `${LINE_HEIGHT}px`, verticalAlign: 'top', - paddingRight: 10, + marginTop: 2, }, shortUpperValueOrIdField: { display: 'inline-flex', minWidth: WIDTHS.upperValueOrId, paddingTop: 0, - lineHeight: `${LINE_HEIGHT}px`, verticalAlign: 'top', - paddingRight: 10, }, shortLowerValueOrIdField: { - lineHeight: `${LINE_HEIGHT}px`, display: 'inline-flex', minWidth: WIDTHS.lowerValueOrId, - marginLeft: 8, paddingTop: 0, verticalAlign: 'top', - paddingRight: 10, }, shortColorField: { display: 'inline-flex', minWidth: WIDTHS.color, - marginLeft: 8, paddingTop: 0, - lineHeight: `${LINE_HEIGHT}px`, verticalAlign: 'top', - paddingRight: 10, }, shortFillField: { display: 'inline-flex', width: WIDTHS.fill, - marginLeft: 8, paddingTop: 0, - lineHeight: `${LINE_HEIGHT}px`, verticalAlign: 'top', - paddingRight: 10, }, sliderRoot: { marginTop: 10, @@ -112,18 +95,13 @@ const styles: Record = { shortTextField: { display: 'inline-flex', minWidth: WIDTHS.text, - marginLeft: 8, paddingTop: 0, - lineHeight: `${LINE_HEIGHT}px`, verticalAlign: 'top', - paddingRight: 10, }, shortButtonsField: { display: 'inline-flex', minWidth: WIDTHS.buttons, - marginLeft: 8, paddingTop: 0, - lineHeight: `${LINE_HEIGHT}px`, verticalAlign: 'top', }, lineClosed: { @@ -132,23 +110,15 @@ const styles: Record = { overflow: 'hidden', flexDirection: 'row', flex: 1, - height: LINE_HEIGHT, }, lineClosedContainer: { display: 'flex', + alignItems: 'center', + gap: 4, }, - deleteButton: { - float: 'right', - marginRight: 12, - }, - deleteButtonFull: { - float: 'right', - marginRight: 12, - }, - copyButtonFull: { - float: 'right', - marginRight: 0, - }, + deleteButton: {}, + deleteButtonFull: {}, + copyButtonFull: {}, title: { width: 'inherit', position: 'absolute', @@ -179,6 +149,7 @@ interface MarkProps { onCopy?: (mark: ChartMarkConfig) => void; theme: IobTheme; presetData: ChartConfigMore; + width: number; } interface MarkState { @@ -318,142 +289,201 @@ class Mark extends React.Component { } renderClosedLine(lines: Record, colors: Record): React.JSX.Element { + const visible: { + upper?: boolean; + lower?: boolean; + color?: boolean; + fill?: boolean; + text?: boolean; + } = {}; + const upperVisible = this.props.mark.lineId !== null && this.props.mark.lineId !== undefined ? 1 : 0; + const lowerVisible = + upperVisible && + this.props.mark.upperValueOrId !== null && + this.props.mark.upperValueOrId !== undefined && + this.props.mark.upperValueOrId !== '' + ? 1 + : 0; + const fillVisible = + lowerVisible && + this.props.mark.lowerValueOrId !== null && + this.props.mark.lowerValueOrId !== undefined && + this.props.mark.lowerValueOrId !== '' + ? 1 + : 0; + const windowWidth = (this.props.width || 1024) - 32 - 40; // 32 is padding, width of folder icon is 40 + const padding = 4; + + if ( + windowWidth >= + WIDTHS.lineId + + WIDTHS.upperValueOrId * upperVisible + + WIDTHS.lowerValueOrId * lowerVisible + + WIDTHS.color * lowerVisible + + WIDTHS.fill * fillVisible + + WIDTHS.text * lowerVisible + + WIDTHS.buttons + + padding * 6 + ) { + visible.upper = !!upperVisible; + visible.lower = !!lowerVisible; + visible.color = !!lowerVisible; + visible.fill = !!fillVisible; + visible.text = !!lowerVisible; + } else if ( + windowWidth >= + WIDTHS.lineId + + WIDTHS.upperValueOrId * upperVisible + + WIDTHS.lowerValueOrId * lowerVisible + + WIDTHS.color * lowerVisible + + WIDTHS.fill * fillVisible + + WIDTHS.buttons + + padding * 5 + ) { + visible.upper = !!upperVisible; + visible.lower = !!lowerVisible; + visible.color = !!lowerVisible; + visible.fill = !!fillVisible; + } else if ( + windowWidth >= + WIDTHS.lineId + + WIDTHS.upperValueOrId * upperVisible + + WIDTHS.lowerValueOrId * lowerVisible + + WIDTHS.color * lowerVisible + + WIDTHS.buttons + + padding * 4 + ) { + visible.upper = !!upperVisible; + visible.lower = !!lowerVisible; + visible.color = !!lowerVisible; + } else if ( + windowWidth >= + WIDTHS.lineId + + WIDTHS.upperValueOrId * upperVisible + + WIDTHS.lowerValueOrId * lowerVisible + + WIDTHS.buttons + + padding * 3 + ) { + visible.upper = !!upperVisible; + visible.lower = !!lowerVisible; + } else { + visible.upper = !!upperVisible; + } + return (
-
- {this.props.onPaste ? ( - this.props.onPaste()} - > - - - ) : ( - this.props.markOpenToggle(this.props.index)} - > - - - )} - this.props.onPaste()} + > + + + ) : ( + this.props.markOpenToggle(this.props.index)} + > + + + )} + { + const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); + mark.lineId = value ? parseInt(value, 10) : undefined; + this.props.updateMark(this.props.index, mark); + }} + label="Line ID" + options={lines} + colors={colors} + styles={{ fieldContainer: styles.shortLineIdField }} + minWidth={WIDTHS.lineId} + /> + {visible.upper ? ( + { const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); - mark.lineId = value ? parseInt(value, 10) : undefined; + mark.upperValueOrId = value; this.props.updateMark(this.props.index, mark); }} - label="Line ID" - options={lines} - colors={colors} - styles={{ fieldContainer: styles.shortLineIdField }} - minWidth={WIDTHS.lineId} + name="upperValueOrId" + label="Upper value or ID" + socket={this.props.socket} + styles={{ fieldContainer: styles.shortUpperValueOrIdField }} + minWidth={WIDTHS.upperValueOrId} /> - {this.props.mark.lineId !== null && this.props.mark.lineId !== undefined ? ( - { - const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); - mark.upperValueOrId = value; - this.props.updateMark(this.props.index, mark); - }} - name="upperValueOrId" - label="Upper value or ID" - socket={this.props.socket} - styles={{ fieldContainer: styles.shortUpperValueOrIdField }} - minWidth={WIDTHS.upperValueOrId} - /> - ) : null} - {this.props.mark.lineId !== null && - this.props.mark.lineId !== undefined && - this.props.mark.upperValueOrId !== null && - this.props.mark.upperValueOrId !== undefined && - this.props.mark.upperValueOrId !== '' ? ( - { - const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); - mark.lowerValueOrId = value; - this.props.updateMark(this.props.index, mark); - }} - name="lowerValueOrId" - label="Lower value or ID" - socket={this.props.socket} - styles={{ fieldContainer: styles.shortLowerValueOrIdField }} - minWidth={WIDTHS.lowerValueOrId} - /> - ) : null} - {this.props.mark.lineId !== null && - this.props.mark.lineId !== undefined && - this.props.mark.upperValueOrId !== null && - this.props.mark.upperValueOrId !== undefined && - this.props.mark.upperValueOrId !== '' - ? this.renderColorField(WIDTHS.color, styles.shortColorField) - : null} - {this.props.mark.lineId !== null && - this.props.mark.lineId !== undefined && - this.props.mark.upperValueOrId !== null && - this.props.mark.upperValueOrId !== undefined && - this.props.mark.upperValueOrId !== '' && - this.props.mark.lowerValueOrId !== null && - this.props.mark.lowerValueOrId !== undefined && - this.props.mark.lowerValueOrId !== '' ? ( - { - const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); - mark.fill = value; - this.props.updateMark(this.props.index, mark); - }} - styles={{ fieldContainer: styles.shortFillField, sliderRoot: styles.sliderRoot }} - label="Fill (from 0 to 1)" - min={0} - max={1} - step={0.1} - /> - ) : null} - {this.props.mark.lineId !== null && - this.props.mark.lineId !== undefined && - this.props.mark.upperValueOrId !== null && - this.props.mark.upperValueOrId !== undefined && - this.props.mark.upperValueOrId !== '' ? ( - { - const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); - mark.text = value; - this.props.updateMark(this.props.index, mark); - }} - label="Text" - styles={{ fieldContainer: styles.shortTextField }} - minWidth={WIDTHS.fill} - /> - ) : null} -
+ ) : null} + {visible.lower ? ( + { + const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); + mark.lowerValueOrId = value; + this.props.updateMark(this.props.index, mark); + }} + name="lowerValueOrId" + label="Lower value or ID" + socket={this.props.socket} + styles={{ fieldContainer: styles.shortLowerValueOrIdField }} + minWidth={WIDTHS.lowerValueOrId} + /> + ) : null} + {visible.color ? this.renderColorField(WIDTHS.color, styles.shortColorField) : null} + {visible.fill ? ( + { + const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); + mark.fill = value; + this.props.updateMark(this.props.index, mark); + }} + styles={{ fieldContainer: styles.shortFillField, sliderRoot: styles.sliderRoot }} + label="Fill (from 0 to 1)" + min={0} + max={1} + step={0.1} + /> + ) : null} + {visible.text ? ( + { + const mark: ChartMarkConfig = JSON.parse(JSON.stringify(this.props.mark)); + mark.text = value; + this.props.updateMark(this.props.index, mark); + }} + label="Text" + styles={{ fieldContainer: styles.shortTextField }} + minWidth={WIDTHS.fill} + /> + ) : null} +
this.props.deleteMark(this.props.index)} > +
); } @@ -461,23 +491,16 @@ class Mark extends React.Component { renderOpenedCard(lines: Record, colors: Record): React.JSX.Element { return ( <> -
+
this.props.markOpenToggle(this.props.index)} > {I18n.t('Mark')} {this.props.index + 1} {this.props.mark.text ? ` - ${this.props.mark.text}` : ''} - this.props.deleteMark(this.props.index)} - > - - +
{ > + this.props.deleteMark(this.props.index)} + > + + +
void; autoSave: boolean; + windowWidth: number; } interface PresetTabsState { @@ -197,6 +198,7 @@ interface PresetTabsState { colorDialogValue: string; webInstances: { index: string; link: string }[]; toast: string; + clientWidth: number; legColor: string; legBg: string; @@ -217,9 +219,16 @@ interface PresetTabsState { class PresetTabs extends React.Component { private colorPickerCb: null | ((color: string) => void); + private readonly paperLineRef: React.RefObject; + private readonly paperMarkRef: React.RefObject; + + private windowWidth: number; + constructor(props: PresetTabsProps) { super(props); + this.windowWidth = this.props.windowWidth; + const copiedObjectStr = window.sessionStorage.getItem('echarts.copiedObject'); let copiedObject: | { type: 'line'; line: ChartLineConfigMore } @@ -249,7 +258,13 @@ class PresetTabs extends React.Component { presetData: getDefaultPreset(this.props.systemConfig), selectedTab: window.localStorage.getItem('App.echarts.presetTabs.selectedTab') !== null - ? (window.localStorage.getItem('App.echarts.presetTabs.selectedTab') as 'data') + ? (window.localStorage.getItem('App.echarts.presetTabs.selectedTab') as + | 'data' + | 'markings' + | 'time' + | 'options' + | 'title' + | 'appearance') : 'data', linesOpened: window.localStorage.getItem('App.echarts.Lines.opened') !== null @@ -266,6 +281,7 @@ class PresetTabs extends React.Component { webInstances: [], toast: '', copiedObject, + clientWidth: 0, legColor: '', legBg: '', @@ -292,11 +308,38 @@ class PresetTabs extends React.Component { this.setState({ webInstances }); }); + this.paperLineRef = React.createRef(); + this.paperMarkRef = React.createRef(); + this.colorPickerCb = null; } + componentDidMount() { + window.addEventListener('resize', this.handleResize); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.handleResize); + } + + handleResize = (): void => { + if ( + (!this.state.selectedTab || this.state.selectedTab === 'data') && + this.paperLineRef.current && + this.paperLineRef.current.clientWidth !== this.state.clientWidth + ) { + this.setState({ clientWidth: this.paperLineRef.current.clientWidth }); + } else if ( + this.state.selectedTab === 'markings' && + this.paperMarkRef.current && + this.paperMarkRef.current.clientWidth !== this.state.clientWidth + ) { + this.setState({ clientWidth: this.paperMarkRef.current.clientWidth }); + } + }; + lineOpenToggle = (index: number): void => { - const linesOpened =[...this.state.linesOpened]; + const linesOpened = [...this.state.linesOpened]; linesOpened[index] = !this.state.linesOpened[index]; this.setState({ linesOpened }); window.localStorage.setItem('App.echarts.Lines.opened', JSON.stringify(linesOpened)); @@ -543,6 +586,26 @@ class PresetTabs extends React.Component { ); } + componentDidUpdate(): void { + if ( + (!this.state.selectedTab || this.state.selectedTab === 'data') && + this.paperLineRef.current && + this.paperLineRef.current.clientWidth !== this.state.clientWidth + ) { + // This one is just to trigger the update of component if width of menu changed + this.windowWidth = this.props.windowWidth; + this.setState({ clientWidth: this.paperLineRef.current.clientWidth }); + } else if ( + this.state.selectedTab === 'markings' && + this.paperMarkRef.current && + this.paperMarkRef.current.clientWidth !== this.state.clientWidth + ) { + // This one is just to trigger the update of component if width of menu changed + this.windowWidth = this.props.windowWidth; + this.setState({ clientWidth: this.paperMarkRef.current.clientWidth }); + } + } + renderTabLines(): React.ReactNode { const anyClosed = this.props.presetData.l.length > 1 && this.props.presetData.l.find((l, i) => !this.state.linesOpened[i]); @@ -552,138 +615,147 @@ class PresetTabs extends React.Component { return ( // @ts-expect-error idk - {(provided, snapshot) => ( -
- - this.addLine()} - size="small" - color="secondary" - style={styles.buttonAdd} - title={I18n.t('Add line to chart')} + {(provided, snapshot) => { + return ( +
+ - - - {anyClosed ? ( - - - - ) : null} - {anyOpened ? ( this.addLine()} size="small" - color="default" - style={styles.buttonCollapseAll} - title={I18n.t('Collapse all lines')} + color="secondary" + style={styles.buttonAdd} + title={I18n.t('Add line to chart')} > - + - ) : null} - {this.props.presetData.l.length ? ( - this.props.presetData.l.map((line, index) => ( - // @ts-expect-error idk - - {(_provided, _snapshot) => ( -
- this.setState({ deleteLineDialog: _index })} - index={index} - key={index} - socket={this.props.socket} - opened={ - typeof this.state.linesOpened[index] !== 'undefined' && - this.state.linesOpened[index] === true - } - lineOpenToggle={this.lineOpenToggle} - maxLines={this.props.presetData.l.length} - onSelectColor={(value: string, cb) => - this.showColorPicker(value, cb) - } - onCopy={_line => { - this.setState({ - copiedObject: { - type: 'line', - line: JSON.parse(JSON.stringify(_line)), - }, - }); - window.sessionStorage.setItem( - 'echarts.copiedObject', - JSON.stringify({ type: 'line', line: _line }), - ); - }} - /> -
- )} -
- )) - ) : ( -
- {I18n.t('Create a new line with a "+" on the right.')} + + + ) : null} + {anyOpened ? ( + + + + ) : null} + {this.props.presetData.l.length ? ( + this.props.presetData.l.map((line, index) => ( + // @ts-expect-error idk + + {(_provided, _snapshot) => ( +
+ + this.setState({ deleteLineDialog: _index }) + } + index={index} + key={index} + socket={this.props.socket} + opened={ + typeof this.state.linesOpened[index] !== 'undefined' && + this.state.linesOpened[index] === true + } + lineOpenToggle={this.lineOpenToggle} + maxLines={this.props.presetData.l.length} + onSelectColor={(value: string, cb) => + this.showColorPicker(value, cb) + } + onCopy={_line => { + this.setState({ + copiedObject: { + type: 'line', + line: JSON.parse(JSON.stringify(_line)), + }, + }); + window.sessionStorage.setItem( + 'echarts.copiedObject', + JSON.stringify({ type: 'line', line: _line }), + ); + }} + /> +
+ )} +
+ )) + ) : ( +
+ {I18n.t('Create a new line with a "+" on the right.')} +
+ )} + {this.state.copiedObject?.type === 'line' ? ( + { + window.sessionStorage.removeItem('echarts.copiedObject'); + this.setState({ copiedObject: null }); + }} + key="copiedLine" + socket={this.props.socket} + opened={false} + onPaste={() => + this.state.copiedObject?.type === 'line' && + this.addLine(this.state.copiedObject.line) + } + /> + ) : null} + {provided.placeholder as any} +
+ {I18n.t('You can drag and drop simple lines from the left list.')}
- )} - {this.state.copiedObject?.type === 'line' ? ( - { - window.sessionStorage.removeItem('echarts.copiedObject'); - this.setState({ copiedObject: null }); - }} - key="copiedLine" - socket={this.props.socket} - opened={false} - onPaste={() => - this.state.copiedObject?.type === 'line' && - this.addLine(this.state.copiedObject.line) - } - /> - ) : null} - {provided.placeholder as any} -
- {I18n.t('You can drag and drop simple lines from the left list.')} -
- -
- )} +
+
+ ); + }} ); } @@ -697,7 +769,10 @@ class PresetTabs extends React.Component { this.props.presetData.marks.find((l, i) => this.state.marksOpened[i]); return ( - + this.addMark()} size="small" @@ -742,6 +817,7 @@ class PresetTabs extends React.Component { index={index} key={index} socket={this.props.socket} + width={this.state.clientWidth} opened={ typeof this.state.marksOpened[index] !== 'undefined' && this.state.marksOpened[index] === true @@ -769,6 +845,7 @@ class PresetTabs extends React.Component { presetData={this.props.presetData} mark={this.state.copiedObject.mark} theme={this.props.theme} + width={this.state.clientWidth} deleteMark={() => { window.sessionStorage.removeItem('echarts.copiedObject'); this.setState({ copiedObject: null }); @@ -863,7 +940,11 @@ class PresetTabs extends React.Component { <>

{I18n.t('Start and end')}

{ const presetData: ChartConfigMore = JSON.parse( @@ -876,7 +957,11 @@ class PresetTabs extends React.Component { label="Start" /> { const presetData: ChartConfigMore = JSON.parse( @@ -923,7 +1008,11 @@ class PresetTabs extends React.Component { }} /> { const presetData: ChartConfigMore = JSON.parse( JSON.stringify(this.props.presetData), @@ -1600,7 +1689,9 @@ class PresetTabs extends React.Component { styles={{ fieldContainer: styles.marginTop }} /> { const presetData: ChartConfigMore = JSON.parse(JSON.stringify(this.props.presetData)); if (!value) { @@ -1699,7 +1790,11 @@ class PresetTabs extends React.Component { styles.marginTop, )} { const presetData: ChartConfigMore = JSON.parse(JSON.stringify(this.props.presetData)); if (value.includes('m') || value.includes('y')) { @@ -2072,7 +2167,10 @@ class PresetTabs extends React.Component { ) : null} { + onChange={( + _event, + selectedTab: 'data' | 'markings' | 'time' | 'options' | 'title' | 'appearance', + ) => { window.localStorage.setItem('App.echarts.presetTabs.selectedTab', selectedTab); this.setState({ selectedTab }); }} diff --git a/src-editor/src/SettingsEditor.tsx b/src-editor/src/SettingsEditor.tsx index e8a0e51c..e3204adb 100644 --- a/src-editor/src/SettingsEditor.tsx +++ b/src-editor/src/SettingsEditor.tsx @@ -39,6 +39,7 @@ interface SettingsEditorProps { onAutoSave: (autoSave: boolean) => void; autoSave: boolean; systemConfig: ioBroker.SystemConfigObject; + windowWidth: number; } class SettingsEditor extends React.Component { @@ -62,6 +63,7 @@ class SettingsEditor extends React.Component { theme={this.props.theme} onAutoSave={autoSave => this.props.onAutoSave(autoSave)} autoSave={this.props.autoSave} + windowWidth={this.props.windowWidth} />
diff --git a/src-editor/src/i18n/de.json b/src-editor/src/i18n/de.json index 3da9f58c..e0118928 100644 --- a/src-editor/src/i18n/de.json +++ b/src-editor/src/i18n/de.json @@ -434,6 +434,7 @@ "convert_help": "Hier die Formel wie \"val / 1000 + 3\" eingeben. Diese Formel wird auf alle Werte des ausgewählten Datenpunkts angewendet.", "copied": "kopiert", "copy": "Kopieren", + "count": "zählen", "counts": "Anzahl", "current": "Aktueller Wert", "dashed": "gestrichelt", diff --git a/src-editor/src/i18n/en.json b/src-editor/src/i18n/en.json index 019be46c..31315c7c 100644 --- a/src-editor/src/i18n/en.json +++ b/src-editor/src/i18n/en.json @@ -434,6 +434,7 @@ "convert_help": "Enter the formula like \"val / 1000 + 3\". This formula will be applied to all values of the selected datapoint.", "copied": "copied", "copy": "copy", + "count": "count", "counts": "counts", "current": "Current value", "dashed": "dashed", diff --git a/src-editor/src/i18n/es.json b/src-editor/src/i18n/es.json index 45064c2c..d188fcf4 100644 --- a/src-editor/src/i18n/es.json +++ b/src-editor/src/i18n/es.json @@ -434,6 +434,7 @@ "convert_help": "Ingrese la fórmula como \"val / 1000 + 3\". Esta fórmula se aplicará a todos los valores del punto de datos seleccionado.", "copied": "copiado", "copy": "Copiar", + "count": "contar", "counts": "conteos", "current": "Valor actual", "dashed": "estropeado", diff --git a/src-editor/src/i18n/fr.json b/src-editor/src/i18n/fr.json index 9c16120b..602e7948 100644 --- a/src-editor/src/i18n/fr.json +++ b/src-editor/src/i18n/fr.json @@ -434,6 +434,7 @@ "convert_help": "Entrez la formule comme \"val / 1000 + 3\". Cette formule sera appliquée à toutes les valeurs du point de données sélectionné.", "copied": "copié", "copy": "copie", + "count": "compter", "counts": "compte", "current": "Valeur actuelle", "dashed": "brisé", diff --git a/src-editor/src/i18n/it.json b/src-editor/src/i18n/it.json index f5f16320..863b2288 100644 --- a/src-editor/src/i18n/it.json +++ b/src-editor/src/i18n/it.json @@ -434,6 +434,7 @@ "convert_help": "Inserisci la formula come \"val / 1000 + 3\". Questa formula verrà applicata a tutti i valori del datapoint selezionato.", "copied": "copiato", "copy": "copia", + "count": "contare", "counts": "Conteggi", "current": "Valore corrente", "dashed": "tratteggiata", diff --git a/src-editor/src/i18n/nl.json b/src-editor/src/i18n/nl.json index c7924063..d3f828bc 100644 --- a/src-editor/src/i18n/nl.json +++ b/src-editor/src/i18n/nl.json @@ -434,6 +434,7 @@ "convert_help": "Voer de formule in zoals \"val / 1000 + 3\". Deze formule wordt toegepast op alle waarden van het geselecteerde datapunt.", "copied": "gekopieerd", "copy": "kopiëren", + "count": "graaf", "counts": "tellingen", "current": "Huidige waarde", "dashed": "onderbroken", diff --git a/src-editor/src/i18n/pl.json b/src-editor/src/i18n/pl.json index 69c92a77..9e556fed 100644 --- a/src-editor/src/i18n/pl.json +++ b/src-editor/src/i18n/pl.json @@ -434,6 +434,7 @@ "convert_help": "Wprowadź formułę, np. „val / 1000 + 3”. Ta formuła zostanie zastosowana do wszystkich wartości wybranego punktu danych.", "copied": "skopiowane", "copy": "kopia", + "count": "liczyć", "counts": "liczy", "current": "Aktualna wartość", "dashed": "przerywana", diff --git a/src-editor/src/i18n/pt.json b/src-editor/src/i18n/pt.json index c3e6fbf1..1e0a8188 100644 --- a/src-editor/src/i18n/pt.json +++ b/src-editor/src/i18n/pt.json @@ -434,6 +434,7 @@ "convert_help": "Digite a fórmula como \"val / 1000 + 3\". Esta fórmula será aplicada a todos os valores do ponto de dados selecionado.", "copied": "copiado", "copy": "cópia", + "count": "contar", "counts": "contagens", "current": "Valor atual", "dashed": "tracejadas", diff --git a/src-editor/src/i18n/ru.json b/src-editor/src/i18n/ru.json index 16ca8a90..b58d95de 100644 --- a/src-editor/src/i18n/ru.json +++ b/src-editor/src/i18n/ru.json @@ -434,6 +434,7 @@ "convert_help": "Введите формулу типа «val / 1000 + 3». Эта формула будет применяться ко всем значениям выбранной точки данных.", "copied": "скопировано", "copy": "Скопировать", + "count": "считать", "counts": "кол-во", "current": "Текущая стоимость", "dashed": "пунктирная", diff --git a/src-editor/src/i18n/uk.json b/src-editor/src/i18n/uk.json index 9013d93a..d0b60bcd 100644 --- a/src-editor/src/i18n/uk.json +++ b/src-editor/src/i18n/uk.json @@ -434,6 +434,7 @@ "convert_help": "Введіть формулу на зразок «val / 1000 + 3». Ця формула буде застосована до всіх значень вибраної точки даних.", "copied": "скопійовано", "copy": "копія", + "count": "розраховувати", "counts": "розраховує", "current": "Поточне значення", "dashed": "штриховий", diff --git a/src-editor/src/i18n/zh-cn.json b/src-editor/src/i18n/zh-cn.json index 6071df97..477d5cdd 100644 --- a/src-editor/src/i18n/zh-cn.json +++ b/src-editor/src/i18n/zh-cn.json @@ -434,6 +434,7 @@ "convert_help": "输入公式,如“val / 1000 + 3”。此公式将应用于所选数据点的所有值。", "copied": "复制的", "copy": "复制", + "count": "数数", "counts": "计数", "current": "当前值", "dashed": "虚线",