From 4f494e5abccfe4e1fcde5b59745188f384a27652 Mon Sep 17 00:00:00 2001 From: mwplay Date: Fri, 13 Dec 2024 15:53:31 +0800 Subject: [PATCH 1/2] add timezone change button --- .../BrowserCell/BrowserCell.react.js | 11 ++- src/components/BrowserRow/BrowserRow.react.js | 14 ++++ .../DateTimeEditor/DateTimeEditor.react.js | 71 +++++++------------ .../TimeZoneToggle/TimeZoneToggle.react.js | 20 ++++++ .../TimeZoneToggle/TimeZoneToggle.scss | 49 +++++++++++++ .../Data/Browser/BrowserTable.react.js | 4 ++ .../Data/Browser/BrowserToolbar.react.js | 11 ++- .../Data/Browser/DataBrowser.react.js | 52 ++++++++++++-- src/lib/DateUtils.js | 38 +++++++--- 9 files changed, 207 insertions(+), 63 deletions(-) create mode 100644 src/components/TimeZoneToggle/TimeZoneToggle.react.js create mode 100644 src/components/TimeZoneToggle/TimeZoneToggle.scss diff --git a/src/components/BrowserCell/BrowserCell.react.js b/src/components/BrowserCell/BrowserCell.react.js index 74614feb69..072bc3c98b 100644 --- a/src/components/BrowserCell/BrowserCell.react.js +++ b/src/components/BrowserCell/BrowserCell.react.js @@ -7,7 +7,7 @@ */ import * as Filters from 'lib/Filters'; import { List, Map } from 'immutable'; -import { dateStringUTC } from 'lib/DateUtils'; +import { yearMonthDayTimeFormatter } from 'lib/DateUtils'; import getFileName from 'lib/getFileName'; import Parse from 'parse'; import Pill from 'components/Pill/Pill.react'; @@ -152,7 +152,11 @@ export default class BrowserCell extends Component { } else if (typeof value === 'string') { this.props.value = new Date(this.props.value); } - this.copyableValue = content = dateStringUTC(this.props.value); + if (this.props.useLocalTime) { + this.copyableValue = content = yearMonthDayTimeFormatter(this.props.value, false); + } else { + this.copyableValue = content = this.props.value.toISOString(); + } } else if (this.props.type === 'Boolean') { this.copyableValue = content = this.props.value ? 'True' : 'False'; } else if (this.props.type === 'Object' || this.props.type === 'Bytes') { @@ -222,6 +226,9 @@ export default class BrowserCell extends Component { ?.then(() => this.renderCellContent()) ?.catch(err => console.log(err)); } + if (this.props.useLocalTime !== prevProps.useLocalTime && this.props.type === 'Date') { + this.renderCellContent(); + } if (this.props.current) { if (prevProps.selectedCells === this.props.selectedCells) { const node = this.cellRef.current; diff --git a/src/components/BrowserRow/BrowserRow.react.js b/src/components/BrowserRow/BrowserRow.react.js index 0e6f40a694..7a0fc776d3 100644 --- a/src/components/BrowserRow/BrowserRow.react.js +++ b/src/components/BrowserRow/BrowserRow.react.js @@ -1,6 +1,7 @@ import Parse from 'parse'; import encode from 'parse/lib/browser/encode'; import React, { Component } from 'react'; +import { formatDateTime } from 'lib/DateUtils'; import BrowserCell from 'components/BrowserCell/BrowserCell.react'; import styles from 'dashboard/Data/Browser/Browser.scss'; @@ -19,6 +20,18 @@ export default class BrowserRow extends Component { return isRefDifferent ? JSON.stringify(obj) !== JSON.stringify(nextObj) : isRefDifferent; } + renderField(name, type, value, targetClass) { + if (!value) { + return ''; + } + + switch(type) { + case 'Date': + return formatDateTime(value, this.props.useLocalTime); + // ... 其他 case + } + } + render() { const { className, @@ -159,6 +172,7 @@ export default class BrowserRow extends Component { setShowAggregatedData={this.props.setShowAggregatedData} setErrorAggregatedData={this.props.setErrorAggregatedData} firstSelectedCell={this.props.firstSelectedCell} + useLocalTime={this.props.useLocalTime} /> ); })} diff --git a/src/components/DateTimeEditor/DateTimeEditor.react.js b/src/components/DateTimeEditor/DateTimeEditor.react.js index 3799d845e0..dac706af9e 100644 --- a/src/components/DateTimeEditor/DateTimeEditor.react.js +++ b/src/components/DateTimeEditor/DateTimeEditor.react.js @@ -9,42 +9,23 @@ import DateTimePicker from 'components/DateTimePicker/DateTimePicker.react'; import hasAncestor from 'lib/hasAncestor'; import React from 'react'; import styles from 'components/DateTimeEditor/DateTimeEditor.scss'; +import { yearMonthDayTimeFormatter } from 'lib/DateUtils'; export default class DateTimeEditor extends React.Component { constructor(props) { - super(); - + super(props); this.state = { - open: false, - position: null, value: props.value, text: props.value.toISOString(), + open: false }; - - this.checkExternalClick = this.checkExternalClick.bind(this); - this.handleKey = this.handleKey.bind(this); - this.inputRef = React.createRef(); this.editorRef = React.createRef(); - } - - componentWillReceiveProps(props) { - this.setState({ value: props.value, text: props.value.toISOString() }); + this.inputRef = React.createRef(); } componentDidMount() { - document.body.addEventListener('click', this.checkExternalClick); - this.inputRef.current.addEventListener('keypress', this.handleKey); - } - - componentWillUnmount() { - document.body.removeEventListener('click', this.checkExternalClick); - this.inputRef.current.removeEventListener('keypress', this.handleKey); - } - - checkExternalClick(e) { - if (!hasAncestor(e.target, this.editorRef.current)) { - this.props.onCommit(this.state.value); - } + this.inputRef.current.focus(); + this.inputRef.current.select(); } handleKey(e) { @@ -70,25 +51,21 @@ export default class DateTimeEditor extends React.Component { if (isNaN(date.getTime())) { this.setState({ value: this.props.value, - text: this.props.value.toISOString(), + text: this.props.value.toISOString() }); } else { - if (this.state.text.endsWith('Z')) { - this.setState({ value: date }); - } else { - const utc = new Date( - Date.UTC( - date.getFullYear(), - date.getMonth(), - date.getDate(), - date.getHours(), - date.getMinutes(), - date.getSeconds(), - date.getMilliseconds() - ) - ); - this.setState({ value: utc }); - } + const utc = new Date( + Date.UTC( + date.getFullYear(), + date.getMonth(), + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + date.getMilliseconds() + ) + ); + this.setState({ value: utc }); } } @@ -100,10 +77,11 @@ export default class DateTimeEditor extends React.Component { this.setState({ value: value, text: value.toISOString() })} - close={() => - this.setState({ open: false }, () => this.props.onCommit(this.state.value)) - } + local={false} + onChange={value => this.setState({ value, text: value.toISOString() })} + close={() => { + this.setState({ open: false }, () => this.props.onCommit(this.state.value)); + }} /> ); @@ -120,6 +98,7 @@ export default class DateTimeEditor extends React.Component { onClick={this.toggle.bind(this)} onChange={this.inputDate.bind(this)} onBlur={this.commitDate.bind(this)} + onKeyDown={this.handleKey.bind(this)} /> {popover} diff --git a/src/components/TimeZoneToggle/TimeZoneToggle.react.js b/src/components/TimeZoneToggle/TimeZoneToggle.react.js new file mode 100644 index 0000000000..3f01234053 --- /dev/null +++ b/src/components/TimeZoneToggle/TimeZoneToggle.react.js @@ -0,0 +1,20 @@ +import React from 'react'; +import styles from './TimeZoneToggle.scss'; + +const TimeZoneToggle = ({ value, onChange }) => { + const switchStyle = { + backgroundColor: value ? 'rgb(0, 219, 124)' : 'rgb(204, 204, 204)', + transition: 'background-color 0.15s ease-out' + }; + + return ( +
onChange(!value)}> +
+ {value ? 'Local' : 'UTC'} + +
+
+ ); +}; + +export default TimeZoneToggle; \ No newline at end of file diff --git a/src/components/TimeZoneToggle/TimeZoneToggle.scss b/src/components/TimeZoneToggle/TimeZoneToggle.scss new file mode 100644 index 0000000000..05aa6e31c0 --- /dev/null +++ b/src/components/TimeZoneToggle/TimeZoneToggle.scss @@ -0,0 +1,49 @@ +.container { + display: inline-block; + cursor: pointer; + height: 30px; + line-height: 30px; +} + +.switch { + position: relative; + display: flex; + align-items: center; + width: 50px; + height: 18px; + border-radius: 12px; + margin: 6px 8px 0 8px; +} + +.option { + position: absolute; + width: 30px; + text-align: center; + color: white; + font-size: 10px; + z-index: 1; + line-height: 18px; +} + +.left .option { + left: 18px; +} + +.right .option { + left: 2px; +} + +.slider { + position: absolute; + width: 16px; + height: 16px; + background: white; + border-radius: 50%; + left: 2px; + transition: transform 0.15s ease-out; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); +} + +.right .slider { + transform: translateX(30px); +} \ No newline at end of file diff --git a/src/dashboard/Data/Browser/BrowserTable.react.js b/src/dashboard/Data/Browser/BrowserTable.react.js index 59dc53d5da..f8699d96ea 100644 --- a/src/dashboard/Data/Browser/BrowserTable.react.js +++ b/src/dashboard/Data/Browser/BrowserTable.react.js @@ -16,6 +16,7 @@ import React from 'react'; import styles from 'dashboard/Data/Browser/Browser.scss'; import Button from 'components/Button/Button.react'; import { CurrentApp } from 'context/currentApp'; +import { formatDateTime } from 'lib/DateUtils'; const MAX_ROWS = 200; // Number of rows to render at any time const ROWS_OFFSET = 160; @@ -218,6 +219,7 @@ export default class BrowserTable extends React.Component { setShowAggregatedData={this.props.setShowAggregatedData} setErrorAggregatedData={this.props.setErrorAggregatedData} firstSelectedCell={this.props.firstSelectedCell} + useLocalTime={this.props.useLocalTime} />