Minor GitHub bugs (#806)

* text-validation to edit article content

* shows only own department on my account

* add moment and update date

* Update date transformer

* Delete time zone setting.

* Use local date in date range component and utc date in date range filter.

* Fix github comment.

* Fix merge 'Fix filter show bug in ticket search when ordering'.

* Fix merge 'Fix filter show bug in ticket search when ordering' second part.

* Fix getDefaultUTCEndDate function.

Co-authored-by: Ivan Diaz <ivan@opensupports.com>
Co-authored-by: LautaroCesso <lautaro_cesso@hotmail.com>
This commit is contained in:
Guillermo Giuliana 2020-08-28 07:13:34 -03:00 committed by GitHub
parent 5184c31907
commit c00720d6a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 101 additions and 119 deletions

View File

@ -75,6 +75,7 @@
"localStorage": "^1.0.3",
"lodash": "^4.17.15",
"messageformat": "^0.2.2",
"moment": "^2.27.0",
"qs": "^6.5.2",
"query-string": "^6.12.1",
"quill-image-resize-module-react": "^3.0.0",

View File

@ -9,8 +9,6 @@ import API from 'lib-app/api-call';
import history from 'lib-app/history';
import searchTicketsUtils from 'lib-app/search-tickets-utils';
import DateTransformer from 'lib-core/date-transformer';
import Form from 'core-components/form';
import SubmitButton from 'core-components/submit-button';
import FormField from 'core-components/form-field';
@ -19,10 +17,6 @@ import Button from 'core-components/button';
import Loading from 'core-components/loading';
const INITIAL_PAGE = 1;
const DEFAULT_START_DATE = 20170101;
class TicketQueryFilters extends React.Component {
static propTypes = {
@ -59,7 +53,7 @@ class TicketQueryFilters extends React.Component {
<FormField
name="dateRange"
field="date-range"
fieldProps={{defaultValue: this.dateRangeToFormValue(filters.dateRange)}} />
fieldProps={{defaultValue: formState.dateRange}} />
</div>
<div className="ticket-query-filters__row__filter">
<span>{i18n('STATUS')}</span>
@ -207,16 +201,6 @@ class TicketQueryFilters extends React.Component {
this.props.dispatch(SearchFiltersActions.setDefaultFormValues());
}
dateRangeToFormValue(_dateRange) {
const dateRange = JSON.parse(_dateRange);
return {
valid: true,
startDate: dateRange[0]/10000,
endDate: (dateRange[1]-2400)/10000,
};
}
getDepartmentsItems() {
const { departments, } = this.props;
let departmentsList = departments.map(department => {
@ -321,7 +305,8 @@ class TicketQueryFilters extends React.Component {
{...formState, orderBy: filters.orderBy, page: 1},
true
);
if(formEdited) {
if(formEdited && formState.dateRange.valid) {
const filtersForAPI = searchTicketsUtils.prepareFiltersForAPI(listConfigWithCompleteAuthorsList.filters);
const currentPath = window.location.pathname;
const urlQuery = searchTicketsUtils.getFiltersForURL({
@ -351,25 +336,25 @@ class TicketQueryFilters extends React.Component {
}
onChangeForm(data) {
let newStartDate = data.dateRange.startDate === "" ? DEFAULT_START_DATE : data.dateRange.startDate;
let newEndDate = data.dateRange.endDate === "" ? DateTransformer.getDateToday() : data.dateRange.endDate;
let departmentsId = data.departments.map(department => department.id);
let staffsId = data.owners.map(staff => staff.id);
let tagsName = this.tagsNametoTagsId(data.tags);
let authors = data.authors.map(({name, id, isStaff, profilePic, color}) => ({name, id: id*1, isStaff, profilePic, color}));
const newStartDate = data.dateRange.startDate ? data.dateRange.startDate : searchTicketsUtils.getDefaultLocalStartDate();
const newEndDate = data.dateRange.endDate ? data.dateRange.endDate : searchTicketsUtils.getDefaultlocalEndDate();
const departmentsId = data.departments.map(department => department.id);
const staffsId = data.owners.map(staff => staff.id);
const tagsName = this.tagsNametoTagsId(data.tags);
const authors = data.authors.map(({name, id, isStaff, profilePic, color}) => ({name, id: id*1, isStaff, profilePic, color}));
this.onChangeFormState({
...data,
tags: tagsName,
owners: staffsId,
departments: departmentsId,
authors: authors,
dateRange: {
...data.dateRange,
startDate: newStartDate,
endDate: newEndDate
}
});
this.onChangeFormState({
...data,
tags: tagsName,
owners: staffsId,
departments: departmentsId,
authors: authors,
dateRange: {
...data.dateRange,
startDate: newStartDate,
endDate: newEndDate
}
});
}
getFormValue(form) {

View File

@ -3,7 +3,7 @@ import _ from 'lodash';
import {connect} from 'react-redux';
import i18n from 'lib-app/i18n';
import searchTicketsUtils from '../../../lib-app/search-tickets-utils';
import searchTicketsUtils from 'lib-app/search-tickets-utils';
import Menu from 'core-components/menu';
import queryString from 'query-string';

View File

@ -97,7 +97,7 @@ class AdminPanelViewArticle extends React.Component {
</Button>
</div>
<FormField name="title" label={i18n('TITLE')} />
<FormField name="content" label={i18n('CONTENT')} field="textarea" fieldProps={{allowImages: this.props.allowAttachments}}/>
<FormField name="content" label={i18n('CONTENT')} field="textarea" validation="TEXT_AREA" required fieldProps={{allowImages: this.props.allowAttachments}}/>
</Form>
);
}

View File

@ -58,7 +58,6 @@ class AdminPanelSystemPreferences extends React.Component {
</div>
<div className="col-md-6">
<FormField label={i18n('SUPPORT_CENTER_TITLE')} fieldProps={{size: 'large'}} name="title" validation="TITLE" required/>
<FormField label={i18n('DEFAULT_TIMEZONE')} fieldProps={{size: 'large'}} name="time-zone"/>
</div>
</div>
<div className="row">
@ -149,7 +148,6 @@ class AdminPanelSystemPreferences extends React.Component {
'url': form['url'],
'title': form['title'],
'layout': form['layout'] ? 'full-width' : 'boxed',
'time-zone': form['time-zone'],
'maintenance-mode': form['maintenance-mode'] * 1,
'allow-attachments': form['allow-attachments'] * 1,
'max-size': form['max-size'],
@ -190,7 +188,6 @@ class AdminPanelSystemPreferences extends React.Component {
'url': result.data['url'],
'title': result.data['title'],
'layout': (result.data['layout'] == 'full-width') ? 1 : 0,
'time-zone': result.data['time-zone'],
'maintenance-mode': !!(result.data['maintenance-mode'] * 1),
'allow-attachments': !!(result.data['allow-attachments'] * 1),
'max-size': result.data['max-size'],

View File

@ -109,7 +109,7 @@ class StaffEditor extends React.Component {
<div className="col-md-4">
<div className="staff-editor__departments">
<div className="staff-editor__departments-title">{i18n('DEPARTMENTS')}</div>
{(!this.props.myAccount) ? this.renderDepartmentsForm() : this.renderDepartmentsInfo()}
{(this.props.myAccount && this.props.level !== 3) ? this.renderDepartmentsInfo() : this.renderDepartmentsForm()}
</div>
</div>
<div className="col-md-8">
@ -193,7 +193,7 @@ class StaffEditor extends React.Component {
renderDepartmentsInfo() {
return (
<Form values={{departments: this.state.departments}}>
<FormField name="departments" field="checkbox-group" fieldProps={{items: this.getDepartments()}} />
<FormField name="departments" field="checkbox-group" fieldProps={{items: this.getDepartments().filter((department,index) => this.state.departments.includes(index))}} />
</Form>
);
}
@ -262,7 +262,6 @@ class StaffEditor extends React.Component {
departmentIndexes.push(index);
}
});
return departmentIndexes;
}

View File

@ -41,7 +41,6 @@ export function updateSearchTicketsFromURL() {
searchTicketsUtils.prepareFiltersForAPI(listConfig.filters)
));
});
}
}

View File

@ -33,18 +33,22 @@ class DateRange extends React.Component {
}
onChange(date, dateValue) {
if(dateValue !== "") {
dateValue = dateValue*10000;
dateValue = (date === "startDate") ? dateValue : dateValue+2359;
} else {
dateValue = 0;
}
const value = _.clone(this.props.value);
value[date] = dateValue;
value.valid =
value.startDate !== 0 &&
value.endDate !== 0 && this.dateCompare({startDate: value.startDate, endDate: value.endDate});
value.valid = this.dateCompare({startDate: value.startDate, endDate: value.endDate});
this.props.onChange(value);
}
dateCompare(dateRange) {
const { defaultValue, } = this.props;
let startDate = dateRange.startDate === "" ? defaultValue.startDate : dateRange.startDate;
let endDate = dateRange.endDate === "" ? defaultValue.endDate : dateRange.endDate;
const { defaultValue } = this.props;
const startDate = dateRange.startDate ? dateRange.startDate : defaultValue.startDate;
const endDate = dateRange.endDate ? dateRange.endDate : defaultValue.endDate;
let isValidRange = startDate <= endDate;
return isValidRange;
}

View File

@ -13,7 +13,6 @@ module.exports = [
'url': 'http://www.opensupports.com/support',
'title': 'Support Center',
'layout': 'boxed',
'time-zone': 3,
'server-email': 'shitr@post.com',
'smtp-host': 'localhost',
'smtp-port': '7070',

View File

@ -4,6 +4,8 @@ import _ from 'lodash';
import DateTransformer from 'lib-core/date-transformer';
import API from 'lib-app/api-call';
const DEFAULT_UTC_START_DATE = 201701010000;
const TICKET_STATUSES = {
ANY: undefined,
OPENED: 0,
@ -81,6 +83,7 @@ export default {
} :
filters
);
const dateRange = filtersForAPI.dateRange;
if(filtersForAPI && filtersForAPI.closed !== undefined) {
filtersForAPI = {
@ -91,14 +94,11 @@ export default {
filtersForAPI = {
...filtersForAPI,
dateRange: filtersForAPI.dateRange ? filtersForAPI.dateRange : this.getDefaultDateRangeForFilters()
dateRange: dateRange ? dateRange : this.getDefaultUTCRange()
}
return filtersForAPI ? filtersForAPI : {};
},
getDefaultDateRangeForFilters() {
return JSON.stringify(DateTransformer.formDateRangeToFilters([20170101, DateTransformer.getDateToday()]));
},
getFiltersForURL(filtersWithShouldRemoveParams) {
const shouldRemoveCustomParam = filtersWithShouldRemoveParams.shouldRemoveCustomParam ? filtersWithShouldRemoveParams.shouldRemoveCustomParam : false;
const shouldRemoveUseInitialValuesParam = filtersWithShouldRemoveParams.shouldRemoveUseInitialValuesParam ? filtersWithShouldRemoveParams.shouldRemoveUseInitialValuesParam : false;
@ -148,6 +148,13 @@ export default {
return closedDropdownIndex;
},
transformToFormValue(filters) {
const localDateRange = DateTransformer.rangeTransformer(JSON.parse(filters.dateRange), "UTCToLocal");
const newDateRange = {
valid: true,
startDate: localDateRange[0],
endDate: localDateRange[1],
};
return {
...filters,
query: filters.query ? filters.query : '',
@ -155,7 +162,7 @@ export default {
departments: JSON.parse(filters.departments),
owners: JSON.parse(filters.owners),
tags: JSON.parse(filters.tags),
dateRange: DateTransformer.dateRangeToFormValue(filters.dateRange),
dateRange: newDateRange,
authors: filters.authors ? JSON.parse(filters.authors) : [],
};
},
@ -177,7 +184,7 @@ export default {
},
formValueToListConfig(form, hasAllAuthorsInfo = false) {
const authors = form.authors ? form.authors.map(author => ({id: author.id*1, isStaff: author.isStaff})) : [];
const dateRangeFilter = [form.dateRange.startDate, form.dateRange.endDate];
const localRange = [form.dateRange.startDate, form.dateRange.endDate];
return {
filters: {
@ -187,11 +194,25 @@ export default {
departments: form.departments !== undefined ? JSON.stringify(form.departments) : '[]',
owners: JSON.stringify(form.owners),
tags: JSON.stringify(form.tags),
dateRange: JSON.stringify(DateTransformer.formDateRangeToFilters(dateRangeFilter)),
dateRange: JSON.stringify(DateTransformer.rangeTransformer(localRange, "localToUTC")),
authors: JSON.stringify(authors),
},
hasAllAuthorsInfo
};
},
getDefaultUTCRange() {
return JSON.stringify([DEFAULT_UTC_START_DATE, this.getDefaultUTCEndDate()]);
},
getDefaultUTCStartDate() {
return DEFAULT_UTC_START_DATE
},
getDefaultUTCEndDate() {
return DateTransformer.localDateToUTCNumericDate(JSON.stringify((DateTransformer.getDateToday()*10000)+2359));
},
getDefaultLocalStartDate() {
return DateTransformer.UTCDateToLocalNumericDate(this.getDefaultUTCStartDate())
},
getDefaultlocalEndDate() {
return DateTransformer.UTCDateToLocalNumericDate(this.getDefaultUTCEndDate())
}
}
}

View File

@ -1,20 +1,33 @@
let month = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
import moment from 'moment';
const stringDateFormat = 'YYYYMMDDHHmm';
const localUTCMins = new Date().getTimezoneOffset();
export default {
stringDateToMoment(date) {
return moment(`${date}`, stringDateFormat);
},
momentToStringDate(date) {
return date.format(stringDateFormat);
},
UTCDateToLocalNumericDate(date) {
return JSON.parse(this.momentToStringDate(this.stringDateToMoment(date).subtract(localUTCMins, 'minutes')));
},
localDateToUTCNumericDate(date) {
return JSON.parse(this.momentToStringDate(this.stringDateToMoment(date).add(localUTCMins, 'minutes')));
},
rangeTransformer(range, trasformerFunctionKey) {
const trasformerDateFunction = {
UTCToLocal: this.UTCDateToLocalNumericDate.bind(this),
localToUTC: this.localDateToUTCNumericDate.bind(this)
}[trasformerFunctionKey];
return range.map((date) => {return trasformerDateFunction(JSON.stringify(date))});
},
transformToString(date, expressive = true) {
date += ''; // Transform to string
let y = date.substring(0, 4);
let m = date.substring(4, 6);
let d = date.substring(6, 8);
m = (m[0] - '0') * 10 + (m[1] - '0');
if(!expressive)
return d + " " + month[m] + " " + y;
let hr = date.substring(8, 10);
let min = date.substring(10, 12);
return d + " " + month[m] + " " + y + " at " + hr + ":" + min;
const momentDateLocal = this.stringDateToMoment(JSON.stringify(this.UTCDateToLocalNumericDate(date)));
if (expressive) momentDateLocal.format('D MMMM YYYY')
return momentDateLocal.format('D MMMM YYYY, HH:mm');
},
getDate(date) {
return date < 10 ? `0${date}` : `${date}`;
@ -28,34 +41,4 @@ export default {
return newDate*1;
},
getDefaultDateRange(range = undefined) {
let newDateRange = range;
if(range) {
let dateRange = JSON.parse(range);
let startDate = dateRange[0];
let endDate = dateRange[1];
let valid = true;
newDateRange = {
startDate: startDate,
endDate: endDate,
valid: valid
}
}
return newDateRange;
},
formDateRangeToFilters(dateRange) {
return [dateRange[0]*10000, dateRange[1]*10000+2400];
},
dateRangeToFormValue(_dateRange) {
const dateRange = JSON.parse(_dateRange);
return {
valid: true,
startDate: dateRange[0]/10000,
endDate: (dateRange[1]-2400)/10000,
};
},
};

View File

@ -3,18 +3,15 @@ import queryString from 'query-string';
import Reducer from 'reducers/reducer';
import DateTransformer from 'lib-core/date-transformer';
import searchTicketsUtils from '../lib-app/search-tickets-utils';
const DEFAULT_START_DATE = 20170101;
const DEFAULT_FILTERS = {
query: undefined,
closed: undefined,
departments: '[]',
owners: '[]',
tags: '[]',
dateRange: searchTicketsUtils.getDefaultDateRangeForFilters(),
dateRange: searchTicketsUtils.getDefaultUTCRange(),
orderBy: undefined,
authors: '[]',
};
@ -33,7 +30,11 @@ class searchFiltersReducer extends Reducer {
owners: [],
tags: [],
authors: [],
dateRange: {valid: true, startDate: DEFAULT_START_DATE, endDate: DateTransformer.getDateToday()}
dateRange: {
valid: true,
startDate: searchTicketsUtils.getDefaultLocalStartDate(),
endDate: searchTicketsUtils.getDefaultlocalEndDate()
}
},
ticketQueryListState : {
tickets: [],

View File

@ -16,7 +16,7 @@ DataValidator::with('CustomValidations', true);
*
* @apiParam {String} allowedLanguages The list of languages allowed.
* @apiParam {String} supportedLanguages The list of languages supported.
* @apiParam {Setting} setting A setting can be any of the following: language, recaptcha-public, recaptcha-private, server-email, smtp-host, smtp-port, smtp-user, smtp-pass, time-zone, maintenance-mode, layout, allow-attachments, max-size, title, url.
* @apiParam {Setting} setting A setting can be any of the following: language, recaptcha-public, recaptcha-private, server-email, smtp-host, smtp-port, smtp-user, smtp-pass, maintenance-mode, layout, allow-attachments, max-size, title, url.
*
* @apiUse NO_PERMISSION
*
@ -53,7 +53,6 @@ class EditSettingsController extends Controller {
'smtp-host',
'smtp-user',
'smtp-pass',
'time-zone',
'maintenance-mode',
'layout',
'allow-attachments',

View File

@ -38,7 +38,6 @@ class GetSettingsController extends Controller {
'language' => Setting::getSetting('language')->getValue(),
'reCaptchaKey' => Setting::getSetting('recaptcha-public')->getValue(),
'reCaptchaPrivate' => Setting::getSetting('recaptcha-private')->getValue(),
'time-zone' => Setting::getSetting('time-zone')->getValue(),
'maintenance-mode' => intval(Setting::getSetting('maintenance-mode')->getValue()),
'layout' => Setting::getSetting('layout')->getValue(),
'allow-attachments' => intval(Setting::getSetting('allow-attachments')->getValue()),
@ -66,7 +65,6 @@ class GetSettingsController extends Controller {
$settingsList = [
'language' => Setting::getSetting('language')->getValue(),
'reCaptchaKey' => Setting::getSetting('recaptcha-public')->getValue(),
'time-zone' => Setting::getSetting('time-zone')->getValue(),
'maintenance-mode' => intval(Setting::getSetting('maintenance-mode')->getValue()),
'layout' => Setting::getSetting('layout')->getValue(),
'allow-attachments' => intval(Setting::getSetting('allow-attachments')->getValue()),

View File

@ -78,7 +78,6 @@ class InitSettingsController extends Controller {
'smtp-host' => Controller::request('smtp-host'),
'smtp-user' => Controller::request('smtp-user'),
'smtp-pass' => Controller::request('smtp-pass'),
'time-zone' => 0,
'maintenance-mode' => 0,
'layout' => 'boxed',
'allow-attachments' => !!Controller::request('allow-attachments'),

View File

@ -2,6 +2,7 @@
@include 'config.php';
require_once 'vendor/autoload.php';
date_default_timezone_set ('UTC');
// REDBEAN CONFIGURATION
use RedBeanPHP\Facade as RedBean;

View File

@ -7,7 +7,6 @@ describe'system/edit-settings' do
"csrf_userid" => $csrf_userid,
"csrf_token" => $csrf_token,
"maintenance-mode" => 0,
"time-zone" => -3,
"layout" => 'full-width',
"allow-attachments" => 1,
"max-size" => 2,
@ -21,9 +20,6 @@ describe'system/edit-settings' do
row = $database.getRow('setting', 'maintenance-mode', 'name')
(row['value']).should.equal('0')
row = $database.getRow('setting', 'time-zone', 'name')
(row['value']).should.equal('-3')
row = $database.getRow('setting', 'layout', 'name')
(row['value']).should.equal('full-width')