Skip to content

Commit b08d045

Browse files
authored
Fix #3585 date-time and time support (#3651) (#3710)
Fix #3585 added date-time and time support (#3651) * Add utc enhancer to the dateTimePicker components + tests * Fix tests for date time * tentative fix for date time tests * remove timezone test * fix timeutils test * update var names and tests * Fix date or time values used in cql filter * fix utcDateWrapper test * Fix date problem with firefox * fix failing test on firefox
1 parent 77a8e10 commit b08d045

13 files changed

Lines changed: 526 additions & 118 deletions

File tree

web/client/components/data/featuregrid/filterRenderers/BaseDateTimeFilter.jsx

Lines changed: 28 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,20 @@
88

99
const React = require('react');
1010
const PropTypes = require('prop-types');
11-
const LocaleUtils = require('../../../../utils/LocaleUtils');
12-
1311
require('react-widgets/lib/less/react-widgets.less');
14-
1512
const {DateTimePicker} = require('react-widgets');
1613

14+
const LocaleUtils = require('../../../../utils/LocaleUtils');
15+
const {getDateTimeFormat} = require('../../../../utils/TimeUtils');
1716
const AttributeFilter = require('./AttributeFilter');
17+
const utcDateWrapper = require('../../../misc/enhancers/utcDateWrapper');
18+
const UTCDateTimePicker = utcDateWrapper({
19+
dateProp: "value",
20+
dateTypeProp: "type",
21+
setDateProp: "onChange"
22+
})(DateTimePicker);
1823

1924
class DateFilter extends AttributeFilter {
20-
static defaultProps = {
21-
value: null,
22-
type: "datetime",
23-
column: {},
24-
placeholderMsgId: "featuregrid.filter.placeholders.default"
25-
};
2625
static propTypes = {
2726
type: PropTypes.string,
2827
disabled: PropTypes.boolean,
@@ -32,71 +31,38 @@ class DateFilter extends AttributeFilter {
3231
messages: PropTypes.object,
3332
locale: PropTypes.string
3433
};
35-
getDateValue = (val) => {
36-
if (this.props.type === "time" && val) {
37-
return new Date(`1970-01-01T${val}`);
38-
} else if (this.props.type === "date" && val) {
39-
let dateParts = val.split("Z");
40-
if (dateParts.length > 1) {
41-
return new Date(`${dateParts[0]}T00:00:00Z`);
42-
}
43-
return new Date(`${dateParts[0]}T00:00:00`);
44-
} else if (val) {
45-
return new Date(val);
46-
}
47-
return null;
48-
}
49-
getFormat = () => {
50-
const dateFormat = LocaleUtils.getDateFormat(this.context.locale);
51-
const timeFormat = "HH:MM:SS";
52-
switch (this.props.type) {
53-
case "time":
54-
return timeFormat;
55-
case "date":
56-
return dateFormat;
57-
default:
58-
return dateFormat + " " + timeFormat;
59-
60-
}
61-
}
34+
static defaultProps = {
35+
value: null,
36+
type: "date-time",
37+
column: {},
38+
placeholderMsgId: "featuregrid.filter.placeholders.default"
39+
};
6240
renderInput = () => {
6341
if (this.props.column.filterable === false) {
6442
return <span/>;
6543
}
6644
const placeholder = LocaleUtils.getMessageById(this.context.messages, this.props.placeholderMsgId) || "Insert date";
67-
let inputKey = 'header-filter-' + this.props.column.key;
68-
const val = this.props.value && this.props.value.startDate || this.props.value;
69-
const dateValue = this.props.value ? this.getDateValue(val) : null;
70-
return (<DateTimePicker
45+
const inputKey = 'header-filter-' + this.props.column.key;
46+
let val;
47+
// reset correctly the value; if it is null or startDate is null then reset
48+
if (this.props.value && this.props.value.startDate === null || !this.props.value) {
49+
val = null;
50+
} else {
51+
val = this.props.value && this.props.value.startDate || this.props.value;
52+
}
53+
const dateValue = this.props.value ? val : null;
54+
return (<UTCDateTimePicker
7155
key={inputKey}
7256
disabled={this.props.disabled}
73-
format={this.getFormat()}
57+
format={getDateTimeFormat(this.context.locale, this.props.type)}
7458
placeholder={placeholder}
7559
value={dateValue}
60+
type={this.props.type}
7661
time={this.props.type === 'date-time' || this.props.type === 'time'}
7762
calendar={this.props.type === 'date-time' || this.props.type === 'date'}
78-
format={this.props.dateFormat}
79-
onChange={(date, stringDate) => this.handleChange(date, stringDate)}/>);
63+
onChange={date => this.handleChange(date)}/>);
8064
}
81-
handleChange = (date, stringDate) => {
82-
var tzoffset = (new Date()).getTimezoneOffset() * 60000; // offset in milliseconds
83-
let value = (date && date.toISOString) ? (date).toISOString() : stringDate;
84-
switch (this.props.type) {
85-
case "date":
86-
value = (date && date.toISOString) ? (new Date(date.getTime() - tzoffset)).toISOString() : stringDate;
87-
if (value) {
88-
value = value.split("T")[0] + "Z";
89-
}
90-
break;
91-
case "time":
92-
if (value) {
93-
value = value.split("T")[1];
94-
}
95-
break;
96-
default:
97-
}
98-
99-
65+
handleChange = (value) => {
10066
this.props.onChange({value, attribute: this.props.column && this.props.column.name});
10167
}
10268
}

web/client/components/data/featuregrid/filterRenderers/__tests__/BaseDateTimeFilter-test.jsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,26 @@ describe('Test for BaseDateTimeFilter component', () => {
3030
expect(el).toExist();
3131
});
3232
it('render with value', () => {
33-
ReactDOM.render(<BaseDateTimeFilter type="date" value={"2017-01-05Z"}/>, document.getElementById("container"));
33+
ReactDOM.render(<BaseDateTimeFilter type="date" value="2017-01-05Z"/>, document.getElementById("container"));
3434
const el = document.getElementsByTagName("input")[0];
3535
expect(el).toExist();
3636
const input = document.getElementsByTagName("input")[0];
3737
expect(input.value.indexOf(5) > 0).toBe(true);
38-
ReactDOM.render(<BaseDateTimeFilter type="time" value={"04:04:04Z"}/>, document.getElementById("container"));
38+
ReactDOM.render(<BaseDateTimeFilter type="time" value="04:04:04Z"/>, document.getElementById("container"));
3939
expect(el).toExist();
40-
ReactDOM.render(<BaseDateTimeFilter type="datetime" value={"2017-01-05T04:04:04Z"}/>, document.getElementById("container"));
40+
ReactDOM.render(<BaseDateTimeFilter type="date-time" value="2017-01-05T04:04:04Z"/>, document.getElementById("container"));
41+
expect(el).toExist();
42+
43+
});
44+
it('render with value as startDate', () => {
45+
ReactDOM.render(<BaseDateTimeFilter type="date" value={{startDate: "2017-01-05Z"}}/>, document.getElementById("container"));
46+
const el = document.getElementsByTagName("input")[0];
47+
expect(el).toExist();
48+
const input = document.getElementsByTagName("input")[0];
49+
expect(input.value.indexOf(5) > 0).toBe(true);
50+
ReactDOM.render(<BaseDateTimeFilter type="time" value={{startDate: "04:04:04Z"}}/>, document.getElementById("container"));
51+
expect(el).toExist();
52+
ReactDOM.render(<BaseDateTimeFilter type="date-time" value={{startDate: "2017-01-05T04:04:04Z"}}/>, document.getElementById("container"));
4153
expect(el).toExist();
4254

4355
});

web/client/components/data/featuregrid/filterRenderers/__tests__/DateTimeFilter-test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('Test for DateTimeFilter component', () => {
3030
expect(el).toExist();
3131
});
3232
it('render with value', () => {
33-
ReactDOM.render(<DateTimeFilter type="date" value={"2017-01-05Z"}/>, document.getElementById("container"));
33+
ReactDOM.render(<DateTimeFilter type="date" value="2017-01-05Z"/>, document.getElementById("container"));
3434
const el = document.getElementsByTagName("input")[0];
3535
expect(el).toExist();
3636
const input = document.getElementsByTagName("input")[0];
Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
const PropTypes = require('prop-types');
21
/**
32
* Copyright 2016, GeoSolutions Sas.
43
* All rights reserved.
@@ -7,21 +6,34 @@ const PropTypes = require('prop-types');
76
* LICENSE file in the root directory of this source tree.
87
*/
98
const React = require('react');
10-
11-
const Moment = require('moment');
9+
const PropTypes = require('prop-types');
10+
const moment = require('moment');
1211
const momentLocalizer = require('react-widgets/lib/localizers/moment');
13-
14-
momentLocalizer(Moment);
15-
12+
momentLocalizer(moment);
13+
const utcDateWrapper = require('../../misc/enhancers/utcDateWrapper');
14+
const {getDateTimeFormat} = require('../../../utils/TimeUtils');
1615
const {DateTimePicker} = require('react-widgets');
1716
const {Row, Col} = require('react-bootstrap');
17+
/**
18+
* Date time picker enhanced with UTC and timezone offset
19+
* it takes the localized date in input and it translates to UTC
20+
* for the DateTimePicker tool
21+
*/
22+
const UTCDateTimePicker = utcDateWrapper({
23+
dateProp: "value",
24+
dateTypeProp: "type",
25+
setDateProp: "onChange"
26+
})(DateTimePicker);
1827

1928
require('react-widgets/lib/less/react-widgets.less');
2029

30+
/**
31+
* This enhanced Component is used for supporting "date", "time" or "date-time" attribute types
32+
*/
2133
class DateField extends React.Component {
2234
static propTypes = {
2335
timeEnabled: PropTypes.bool,
24-
dateFormat: PropTypes.string,
36+
dateEnabled: PropTypes.bool,
2537
operator: PropTypes.string,
2638
fieldName: PropTypes.string,
2739
fieldRowId: PropTypes.number,
@@ -32,9 +44,13 @@ class DateField extends React.Component {
3244
onUpdateExceptionField: PropTypes.func
3345
};
3446

47+
static contextTypes = {
48+
locale: PropTypes.string
49+
};
50+
3551
static defaultProps = {
3652
timeEnabled: false,
37-
dateFormat: "L",
53+
dateEnabled: true,
3854
operator: null,
3955
fieldName: null,
4056
fieldRowId: null,
@@ -44,39 +60,53 @@ class DateField extends React.Component {
4460
onUpdateField: () => {},
4561
onUpdateExceptionField: () => {}
4662
};
47-
4863
render() {
64+
// these values are already parsed by the enhancer
65+
const startdate = this.props.fieldValue && this.props.fieldValue.startDate || null;
66+
const enddate = this.props.fieldValue && this.props.fieldValue.endDate || null;
67+
68+
// needed to initialize the time parts to 00:00:00
69+
4970
let dateRow = this.props.operator === "><" ?
5071
(<div>
5172
<Row>
5273
<Col xs={6}>
53-
<DateTimePicker
54-
defaultValue={this.props.fieldValue ? this.props.fieldValue.startDate : null}
74+
<UTCDateTimePicker
75+
type={this.props.attType}
76+
defaultValue={startdate}
77+
value={startdate}
78+
calendar={this.props.dateEnabled}
5579
time={this.props.timeEnabled}
56-
format={this.props.dateFormat}
57-
onChange={(date) => this.updateValueState({startDate: date, endDate: this.props.fieldValue ? this.props.fieldValue.endDate : null})}/>
80+
format={getDateTimeFormat(this.context.locale, this.props.attType)}
81+
onChange={(date) => this.updateValueState({startDate: date, endDate: enddate})}/>
5882
</Col>
5983
<Col xs={6}>
60-
<DateTimePicker
61-
defaultValue={this.props.fieldValue ? this.props.fieldValue.endDate : null}
84+
<UTCDateTimePicker
85+
type={this.props.attType}
86+
defaultValue={enddate}
87+
value={enddate}
88+
calendar={this.props.dateEnabled}
6289
time={this.props.timeEnabled}
63-
format={this.props.dateFormat}
64-
onChange={(date) => this.updateValueState({startDate: this.props.fieldValue ? this.props.fieldValue.startDate : null, endDate: date})}/>
90+
format={getDateTimeFormat(this.context.locale, this.props.attType)}
91+
onChange={(date) => this.updateValueState({startDate: startdate, endDate: date})}/>
6592
</Col>
6693
</Row>
6794
</div>)
6895
:
6996
(<Row>
7097
<Col xs={12}>
71-
<DateTimePicker
72-
defaultValue={this.props.fieldValue ? this.props.fieldValue.startDate : null}
98+
<UTCDateTimePicker
99+
type={this.props.attType}
100+
defaultValue={startdate}
101+
value={startdate}
73102
time={this.props.timeEnabled}
74-
format={this.props.dateFormat}
75-
onChange={(date) => this.updateValueState({startDate: date, endDate: null})}/>
103+
calendar={this.props.dateEnabled}
104+
format={getDateTimeFormat(this.context.locale, this.props.attType)}
105+
onChange={(date) => {
106+
this.updateValueState({startDate: date, endDate: null});
107+
}}/>
76108
</Col>
77-
</Row>)
78-
;
79-
109+
</Row>);
80110
return (
81111
dateRow
82112
);
@@ -88,9 +118,7 @@ class DateField extends React.Component {
88118
} else {
89119
this.props.onUpdateExceptionField(this.props.fieldRowId, null);
90120
}
91-
92121
this.props.onUpdateField(this.props.fieldRowId, this.props.fieldName, value, this.props.attType);
93122
};
94123
}
95-
96124
module.exports = DateField;

web/client/components/data/query/GroupField.jsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,17 @@ class GroupField extends React.Component {
151151
comboFilter={"contains"}/>
152152
<DateField
153153
attType="date"
154+
dateEnabled
155+
operator={filterField.operator}/>
156+
<DateField
157+
attType="date-time"
158+
timeEnabled
159+
dateEnabled
160+
operator={filterField.operator}/>
161+
<DateField
162+
attType="time"
163+
timeEnabled
164+
dateEnabled={false}
154165
operator={filterField.operator}/>
155166
<NumberField
156167
operator={filterField.operator}

0 commit comments

Comments
 (0)