Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ This section provides a comprehensive reference for all Parse Dashboard configur
| `supportedPushLocales` | Array<String> | yes | - | - | - | `["en","fr"]` | Supported locales for push notifications. |
| `preventSchemaEdits` | Boolean | yes | `false` | - | - | `true` | Prevent schema modifications through the dashboard. |
| `preventDataExport` | Boolean | yes | `false` | - | - | `true` | Hide all data browser export options (export data, export selected/all rows, export schema). |
| `useLocalTime` | Boolean | yes | `false` | - | - | `true` | Display and edit dates in the viewer's local time zone instead of UTC. Dates are always stored in UTC. |
| `columnPreference` | Object | yes | - | - | - | `{"_User":[...]}` | Column visibility/sorting/filtering preferences. See [column preferences details](#prevent-columns-sorting). |
| `classPreference` | Object | yes | - | - | - | `{"_Role":{...}}` | Persistent filters for all users. See [persistent filters details](#persistent-filters). |
| `enableSecurityChecks` | Boolean | yes | `false` | - | - | `true` | Enable security checks under App Settings > Security. |
Expand Down
5 changes: 4 additions & 1 deletion src/components/BrowserCell/BrowserCell.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import ScriptConfirmationModal from 'components/ScriptConfirmationModal/ScriptCo
import styles from 'components/BrowserCell/BrowserCell.scss';
import baseStyles from 'stylesheets/base.scss';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import { CurrentApp } from 'context/currentApp';

export default class BrowserCell extends Component {
static contextType = CurrentApp;

constructor() {
super();

Expand Down Expand Up @@ -153,7 +156,7 @@ 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);
this.copyableValue = content = dateStringUTC(this.props.value, this.context?.useLocalTime);
} else if (this.props.type === 'Boolean') {
this.copyableValue = content = this.props.value ? 'True' : 'False';
} else if (this.props.type === 'Object' || this.props.type === 'Bytes') {
Expand Down
1 change: 1 addition & 0 deletions src/components/BrowserFilter/BrowserFilter.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ export default class BrowserFilter extends React.Component {
active={this.props.filters.size > 0}
editMode={this.state.editMode}
parentContentId={POPOVER_CONTENT_ID}
useLocalTime={this.context.useLocalTime}
/>
)}
/>
Expand Down
8 changes: 6 additions & 2 deletions src/components/BrowserFilter/FilterRow.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ function compareValue(
setFocus,
currentConstraint,
modifiers,
onChangeModifiers
onChangeModifiers,
useLocalTime
) {
if (currentConstraint === 'containedIn') {
return (
Expand Down Expand Up @@ -279,6 +280,7 @@ function compareValue(
return (
<DateTimeEntry
fixed={true}
local={useLocalTime}
className={styles.date}
value={Parse._decode('date', value)}
onChange={value => onChangeCompareTo(Parse._encode(value))}
Expand Down Expand Up @@ -309,6 +311,7 @@ const FilterRow = ({
active,
parentContentId,
editMode,
useLocalTime,
}) => {
const setFocus = useCallback(input => {
if (input !== null && editMode) {
Expand Down Expand Up @@ -421,7 +424,8 @@ const FilterRow = ({
setFocus,
currentConstraint,
modifiers,
onChangeModifiers
onChangeModifiers,
useLocalTime
)}
<button type="button" className={styles.remove} onClick={onDeleteRow}>
<Icon name="minus-solid" width={14} height={14} fill="rgba(0,0,0,0.4)" />
Expand Down
35 changes: 11 additions & 24 deletions src/components/DateTimeEditor/DateTimeEditor.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* the root directory of this source tree.
*/
import DateTimePicker from 'components/DateTimePicker/DateTimePicker.react';
import { dateInputString, parseDateInput } from 'lib/DateUtils';
import hasAncestor from 'lib/hasAncestor';
import React from 'react';
import styles from 'components/DateTimeEditor/DateTimeEditor.scss';
Expand All @@ -18,7 +19,7 @@ export default class DateTimeEditor extends React.Component {
open: false,
position: null,
value: props.value,
text: props.value.toISOString(),
text: dateInputString(props.value, props.local),
};

this.checkExternalClick = this.checkExternalClick.bind(this);
Expand Down Expand Up @@ -71,34 +72,17 @@ export default class DateTimeEditor extends React.Component {
}

commitDate() {
if (this.state.text === this.props.value.toISOString()) {
if (this.state.text === dateInputString(this.props.value, this.props.local)) {
return;
}
const date = new Date(this.state.text);
if (isNaN(date.getTime())) {
const date = parseDateInput(this.state.text, this.props.local);
if (date === null) {
this.setState({
value: this.props.value,
text: this.props.value.toISOString(),
text: dateInputString(this.props.value, this.props.local),
});
} else {
if (this.state.text.endsWith('Z') || this.state.text.endsWith('UTC')) {
// Timezone is explicit; the parsed Date is already correct.
this.setState({ value: date });
} else {
// No timezone indicator; treat input as local time.
const utc = new Date(
Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
)
);
this.setState({ value: utc });
}
this.setState({ value: date });
}
}

Expand All @@ -109,8 +93,11 @@ export default class DateTimeEditor extends React.Component {
<div style={{ position: 'absolute', top: 30, left: 0 }}>
<DateTimePicker
value={this.state.value}
local={this.props.local}
width={240}
onChange={value => this.setState({ value: value, text: value.toISOString() })}
onChange={value =>
this.setState({ value: value, text: dateInputString(value, this.props.local) })
}
close={() =>
this.setState({ open: false }, () => this.props.onCommit(this.state.value))
}
Expand Down
27 changes: 8 additions & 19 deletions src/components/DateTimeEntry/DateTimeEntry.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* the root directory of this source tree.
*/
import DateTimePicker from 'components/DateTimePicker/DateTimePicker.react';
import { dateInputString, parseDateInput } from 'lib/DateUtils';
import Popover from 'components/Popover/Popover.react';
import Position from 'lib/Position';
import React from 'react';
Expand All @@ -17,7 +18,7 @@ export default class DateTimeEntry extends React.Component {
this.state = {
open: false,
position: null,
value: props.value.toISOString ? props.value.toISOString() : props.value,
value: props.value.toISOString ? dateInputString(props.value, props.local) : props.value,
};

this.rootRef = React.createRef();
Expand All @@ -26,7 +27,7 @@ export default class DateTimeEntry extends React.Component {

componentWillReceiveProps(props) {
this.setState({
value: props.value.toISOString ? props.value.toISOString() : props.value,
value: props.value.toISOString ? dateInputString(props.value, props.local) : props.value,
});
}

Expand Down Expand Up @@ -64,25 +65,12 @@ export default class DateTimeEntry extends React.Component {
}

commitDate() {
if (this.state.value === this.props.value.toISOString()) {
if (this.state.value === dateInputString(this.props.value, this.props.local)) {
return;
}
const date = new Date(this.state.value);
if (isNaN(date.getTime())) {
this.setState({ value: this.props.value.toISOString() });
} else if (!this.state.value.toLowerCase().endsWith('z')) {
const utc = new Date(
Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
)
);
this.props.onChange(utc);
const date = parseDateInput(this.state.value, this.props.local);
if (date === null) {
this.setState({ value: dateInputString(this.props.value, this.props.local) });
} else {
this.props.onChange(date);
}
Expand All @@ -104,6 +92,7 @@ export default class DateTimeEntry extends React.Component {
>
<DateTimePicker
value={this.props.value}
local={this.props.local}
width={Math.max(this.rootRef.current.clientWidth, 240)}
onChange={this.props.onChange}
close={() => this.setState({ open: false })}
Expand Down
4 changes: 2 additions & 2 deletions src/components/PushCerts/CertsTable.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { dateStringUTC } from 'lib/DateUtils';

const MONTH_IN_MS = 1000 * 60 * 60 * 24 * 30;

const CertsTable = ({ certs, onDelete, uploadPending }) => {
const CertsTable = ({ certs, onDelete, uploadPending, useLocalTime }) => {
const tableData = certs.map(c => {
let color = '';
let expiresKeyColor = '';
Expand All @@ -36,7 +36,7 @@ const CertsTable = ({ certs, onDelete, uploadPending }) => {
{
key: isExpired ? 'Expired' : 'Expires',
keyColor: expiresKeyColor,
value: dateStringUTC(new Date(c.expiration)),
value: dateStringUTC(new Date(c.expiration), useLocalTime),
},
],
};
Expand Down
5 changes: 4 additions & 1 deletion src/dashboard/Account/AccountOverview.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ import styles from 'dashboard/Settings/Settings.scss';
import TextInput from 'components/TextInput/TextInput.react';
import Toolbar from 'components/Toolbar/Toolbar.react';
import { dateStringUTC } from 'lib/DateUtils';
import { CurrentApp } from 'context/currentApp';

const DEFAULT_LABEL_WIDTH = 56;
const XHR_KEY = 'AccountOverview';

export default class AccountOverview extends React.Component {
static contextType = CurrentApp;

constructor() {
super();
this.state = {
Expand Down Expand Up @@ -152,7 +155,7 @@ export default class AccountOverview extends React.Component {
},
{
key: 'Expires',
value: dateStringUTC(new Date(key.expiresAt)),
value: dateStringUTC(new Date(key.expiresAt), this.context?.useLocalTime),
},
],
}))}
Expand Down
1 change: 1 addition & 0 deletions src/dashboard/Data/Browser/BrowserTable.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ export default class BrowserTable extends React.Component {
value={value}
readonly={readonly}
width={width}
useLocalTime={this.context.useLocalTime}
onCommit={newValue => {
if (newValue !== value) {
this.props.updateRow(this.props.current.row, name, newValue);
Expand Down
6 changes: 3 additions & 3 deletions src/dashboard/Data/Browser/DataBrowser.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const GRAPH_PANEL_WIDTH = 'graphPanelWidth';
const AGGREGATION_PANEL_AUTO_SCROLL = 'aggregationPanelAutoScroll';
const AGGREGATION_PANEL_AUTO_SCROLL_REQUIRE_HOVER = 'aggregationPanelAutoScrollRequireHover';

function formatValueForCopy(value, type) {
function formatValueForCopy(value, type, useLocalTime) {
if (value === undefined) {
return '';
}
Expand All @@ -62,7 +62,7 @@ function formatValueForCopy(value, type) {
value = new Date(value);
}
if (value instanceof Date && !isNaN(value)) {
return dateStringUTC(value);
return dateStringUTC(value, useLocalTime);
}
break;
case 'File':
Expand Down Expand Up @@ -968,7 +968,7 @@ export default class DataBrowser extends React.Component {
if (typeof value === 'number' && !isNaN(value)) {
rowData.push(String(value));
} else {
rowData.push(formatValueForCopy(value, type));
rowData.push(formatValueForCopy(value, type, this.context.useLocalTime));
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/dashboard/Data/Browser/EditRowDialog.react.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import Parse from 'parse';
import { dateStringUTC } from 'lib/DateUtils';
import { CurrentApp } from 'context/currentApp';
import Modal from 'components/Modal/Modal.react';
import Field from 'components/Field/Field.react';
import Label from 'components/Label/Label.react';
Expand All @@ -17,6 +18,8 @@ import encode from 'parse/lib/browser/encode';
import validateNumeric from 'lib/validateNumeric';

export default class EditRowDialog extends React.Component {
static contextType = CurrentApp;

constructor(props) {
super(props);

Expand Down Expand Up @@ -326,6 +329,7 @@ export default class EditRowDialog extends React.Component {
inputComponent = (
<DateTimeInput
disabled={isDisabled}
local={this.context.useLocalTime}
value={selectedObject[name]}
onChange={newValue => this.handleChange(newValue, name)}
/>
Expand Down Expand Up @@ -485,12 +489,14 @@ export default class EditRowDialog extends React.Component {
<div style={{ paddingTop: '5px', fontSize: '12px' }}>
{selectedObject.createdAt && (
<p>
CreatedAt <strong>{dateStringUTC(selectedObject.createdAt)}</strong>
CreatedAt{' '}
<strong>{dateStringUTC(selectedObject.createdAt, this.context.useLocalTime)}</strong>
</p>
)}
{selectedObject.updatedAt && (
<p>
UpdatedAt <strong>{dateStringUTC(selectedObject.updatedAt)}</strong>
UpdatedAt{' '}
<strong>{dateStringUTC(selectedObject.updatedAt, this.context.useLocalTime)}</strong>
</p>
)}
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/dashboard/Data/Browser/Editor.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import decode from 'parse/lib/browser/decode';
import React from 'react';
import StringEditor from 'components/StringEditor/StringEditor.react';

const Editor = ({ top, left, type, targetClass, value, readonly, width, onCommit, onCancel, setContextMenu, arrayConfigParams, onAddToArrayConfig, getRelatedRecordsMenuItem }) => {
const Editor = ({ top, left, type, targetClass, value, readonly, width, useLocalTime, onCommit, onCancel, setContextMenu, arrayConfigParams, onAddToArrayConfig, getRelatedRecordsMenuItem }) => {
let content = null;
if (type === 'String') {
content = (
Expand Down Expand Up @@ -116,7 +116,7 @@ const Editor = ({ top, left, type, targetClass, value, readonly, width, onCommit
/>
);
} else {
content = <DateTimeEditor value={value || new Date()} width={width} onCommit={onCommit} onCancel={onCancel} />;
content = <DateTimeEditor value={value || new Date()} local={useLocalTime} width={width} onCommit={onCommit} onCancel={onCancel} />;
}
} else if (type === 'Boolean') {
content = <BooleanEditor value={value} width={width} onCommit={onCommit} />;
Expand Down
2 changes: 1 addition & 1 deletion src/dashboard/Data/Config/ConfigDialog.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ export default class ConfigDialog extends React.Component {
<Dropdown value={String(this.state.selectedIndex)} onChange={index => handleIndexChange(Number(index))}>
{configHistory.map((value, i) => (
<Option key={i} value={String(i)}>
{dateStringUTC(new Date(value.time))}
{dateStringUTC(new Date(value.time), this.context.useLocalTime)}
</Option>
))}
</Dropdown>
Expand Down
8 changes: 6 additions & 2 deletions src/dashboard/Data/Jobs/Jobs.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,13 @@ class Jobs extends TableView {
return (
<tr key={data.objectId}>
<td style={{ width: '20%' }}>{data.jobName}</td>
<td style={{ width: '20%' }}>{DateUtils.dateStringUTC(new Date(data.createdAt))}</td>
<td style={{ width: '20%' }}>
{data.finishedAt ? DateUtils.dateStringUTC(new Date(data.finishedAt.iso)) : ''}
{DateUtils.dateStringUTC(new Date(data.createdAt), this.context.useLocalTime)}
</td>
<td style={{ width: '20%' }}>
{data.finishedAt
? DateUtils.dateStringUTC(new Date(data.finishedAt.iso), this.context.useLocalTime)
: ''}
</td>
<td style={{ width: '20%' }}>
<div style={{ fontSize: 12, whiteSpace: 'normal', lineHeight: '16px' }}>
Expand Down
7 changes: 6 additions & 1 deletion src/dashboard/Data/Jobs/JobsForm.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export default class JobsForm extends DashboardView {
input={
<DateTimeInput
disabled={!!this.props.initialFields.job}
local={this.context.useLocalTime}
value={fields.runAt}
onChange={setField.bind(null, 'runAt')}
/>
Expand Down Expand Up @@ -284,7 +285,11 @@ export default class JobsForm extends DashboardView {
if (fields.immediate) {
pieces.push(<strong>immediately</strong>, '.');
} else {
pieces.push('on ', <strong>{dateStringUTC(fields.runAt)}</strong>, '.');
pieces.push(
'on ',
<strong>{dateStringUTC(fields.runAt, this.context.useLocalTime)}</strong>,
'.'
);
}
if (fields.repeat) {
pieces.push(' It will repeat ');
Expand Down
1 change: 1 addition & 0 deletions src/dashboard/Settings/AppleCerts.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export default class AppleCerts extends React.Component {
certs={this.state.certs}
error={this.state.error}
uploadPending={this.state.uploadPending}
useLocalTime={this.context.useLocalTime}
onUpload={this.handleUpload.bind(this)}
onDelete={this.handleDelete.bind(this)}
/>
Expand Down
Loading
Loading