Merge pull request #7952 from opf/fix/bump_fullcalendar

Fix/bump fullcalendar
pull/7974/head
ulferts 5 years ago committed by GitHub
commit 74e39a846e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      app/assets/stylesheets/content/_calendars.sass
  2. 1
      app/assets/stylesheets/content/_index.sass
  3. 3
      frontend/angular.json
  4. 56
      frontend/npm-shrinkwrap.json
  5. 4
      frontend/package.json
  6. 2
      frontend/src/app/angular4-modules.ts
  7. 3
      frontend/src/app/init-vendors.js
  8. 4
      frontend/src/app/modules/calendar/openproject-calendar.module.ts
  9. 256
      frontend/src/app/modules/calendar/wp-calendar/wp-calendar.component.ts
  10. 22
      frontend/src/app/modules/calendar/wp-calendar/wp-calendar.template.html
  11. 9
      frontend/src/app/modules/common/config/configuration.service.ts
  12. 4
      spec/features/calendars/calendars_spec.rb

@ -0,0 +1,27 @@
// overrides for full-calendar so that it looks to belong into OpenProject
full-calendar
.fc-toolbar
.fc-button
@extend .button
height: 34px
&.fc-today-button
margin-right: 0
margin-bottom: 0
margin-left: 0.5rem
// ensure to have higher specificity than above extend
.fc-button-group
.fc-button
margin-right: 0
margin-bottom: 0
padding: 0.4em 0.65em
.fc-button-active
@extend .button.-active
.fc-header-toolbar
h2
@extend h2
font-size: 1.5rem

@ -7,6 +7,7 @@
@import content/editable_toolbar
@import content/forms
@import content/forms_mobile
@import content/calendars
@import content/comments
@import content/collapsible_section
@import content/copy_to_clipboard

@ -27,7 +27,8 @@
"node_modules/jquery-ui/themes/base/core.css",
"node_modules/jquery-ui/themes/base/datepicker.css",
"node_modules/jquery-ui/themes/base/dialog.css",
"node_modules/fullcalendar/dist/fullcalendar.css"
"node_modules/@fullcalendar/core/main.css",
"node_modules/@fullcalendar/daygrid/main.css"
],
"stylePreprocessorOptions": {
"includePaths": [

@ -2190,6 +2190,26 @@
}
}
},
"@fullcalendar/angular": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@fullcalendar/angular/-/angular-4.3.1.tgz",
"integrity": "sha512-2RWJFpSeBJGyGzRFOJ/aP5BPBbmCwvUnVS0mc9mLGiSGW2BlNfYE6UTIhjCKwaGpy8cO0tParLLC2iG2XLHbTg==",
"requires": {
"@fullcalendar/core": "~4.3.1",
"fast-deep-equal": "^2.0.1",
"tslib": "^1.9.0"
}
},
"@fullcalendar/core": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-4.3.1.tgz",
"integrity": "sha512-Eh+p/wpMkWGu26f8NpfQK9ecQMoZxX/aopv+0+4/CH+Ip0paP6iEc40JYgTz7RFl0bFqV1dvwyGyUZ4+9ZeySA=="
},
"@fullcalendar/daygrid": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-4.3.0.tgz",
"integrity": "sha512-OrGaRIGbELESOXOCXtoQVY4cOxnxmN7OrjDGbMoVITdoXWuIZ6sFNO84WcBQoRaIbkmqVM0SAU2MENwy+eEwqQ=="
},
"@ng-select/ng-option-highlight": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@ng-select/ng-option-highlight/-/ng-option-highlight-0.0.2.tgz",
@ -2365,15 +2385,6 @@
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
},
"@types/fullcalendar": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/@types/fullcalendar/-/fullcalendar-3.5.2.tgz",
"integrity": "sha512-g1e2KAMdvzNkxodyo8F4z9asU6YR4z9v0J5WC9kf6gmdeTN2q05cY18oVKhIxrfsQ40LGP3+UhJb0gEfK74A9g==",
"requires": {
"@types/jquery": "*",
"moment": ">=2.14.0"
}
},
"@types/glob": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
@ -5839,15 +5850,6 @@
"rimraf": "2"
}
},
"fullcalendar": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-3.6.1.tgz",
"integrity": "sha1-C5tiseaX1S05wRGK+eTkEeUEVZA=",
"requires": {
"jquery": "2 - 3",
"moment": "^2.9.0"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@ -8174,24 +8176,6 @@
"resolved": "https://registry.npmjs.org/ng-dynamic-component/-/ng-dynamic-component-5.0.0.tgz",
"integrity": "sha512-87ragKzHGkeuXY3OqphZwNog7na4FhzJqcpqHFxCov2MXWm+fcInqcf3xunPhjJFYpAnbjb89VZO2zElLqvosA=="
},
"ng-fullcalendar": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/ng-fullcalendar/-/ng-fullcalendar-1.7.1.tgz",
"integrity": "sha512-8OMHPOt32QmNU5x2Bj8R4bCgoi//CgBX+1+O3xvDtChfwkD96pq12mgWvRb4+XqixYizJjzQX/zD6bh7d+MdJg==",
"requires": {
"@types/fullcalendar": "3.5.2",
"@types/jquery": "3.2.17",
"fullcalendar": "3.6.1",
"jquery": "^3.2.1"
},
"dependencies": {
"@types/jquery": {
"version": "3.2.17",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.2.17.tgz",
"integrity": "sha512-lt8i2ZqymxxN1JnWSOTPU7Xc3ze32lhASkVdsMd6/SZnb/jtBsmFEoYCBSa0tzGDSyO7ZB+4r4aihj+KTlDs5w=="
}
}
},
"ng2-charts": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-2.3.0.tgz",

@ -63,6 +63,9 @@
"@types/webpack-env": "^1.14.0",
"@uirouter/angular": "^4.0.0",
"@uirouter/core": "^5.0.23",
"@fullcalendar/core": "4.3.1",
"@fullcalendar/angular": "4.3.1",
"@fullcalendar/daygrid": "4.3.0",
"URIjs": "^1.14.1",
"amdefine": "^1.0.0",
"angular-dragula": "^1.2.8",
@ -101,7 +104,6 @@
"moment-timezone": "^0.5.26",
"mousetrap": "~1.6.3",
"ng-dynamic-component": "^5.0.0",
"ng-fullcalendar": "^1.7.1",
"ng2-charts": "^2.3.0",
"ng2-dragula": "^2.1.1",
"ng2-rx-componentdestroyed": "3.0.1",

@ -76,7 +76,6 @@ import {OpenprojectRouterModule} from "core-app/modules/router/openproject-route
import {OpenprojectWorkPackageRoutesModule} from "core-app/modules/work_packages/openproject-work-package-routes.module";
import {BrowserModule} from "@angular/platform-browser";
import {OpenprojectCalendarModule} from "core-app/modules/calendar/openproject-calendar.module";
import {FullCalendarModule} from "ng-fullcalendar";
import {OpenprojectBoardsModule} from "core-app/modules/boards/openproject-boards.module";
import {OpenprojectGlobalSearchModule} from "core-app/modules/global_search/openproject-global-search.module";
import {DeviceService} from "core-app/modules/common/browser/device.service";
@ -127,7 +126,6 @@ import {OpenprojectProjectsModule} from "core-app/modules/projects/openproject-p
// Calendar module
OpenprojectCalendarModule,
FullCalendarModule,
// Dashboards
OpenprojectDashboardsModule,

@ -84,3 +84,6 @@ require('expose-loader?URI!URIjs');
require('URIjs/src/URITemplate');
require("expose-loader?I18n!../vendor/i18n");
// Localization for fullcalendar
require("@fullcalendar/core/locales-all.min");

@ -28,15 +28,13 @@
import {OpenprojectCommonModule} from 'core-app/modules/common/openproject-common.module';
import {NgModule} from '@angular/core';
import {FullCalendarModule} from 'ng-fullcalendar';
import {FullCalendarModule} from '@fullcalendar/angular';
import {WorkPackagesCalendarEntryComponent} from "core-app/modules/calendar/wp-calendar-entry/wp-calendar-entry.component";
import {WorkPackagesEmbeddedCalendarEntryComponent} from "core-app/modules/calendar/wp-embedded-calendar/wp-embedded-calendar-entry.component";
import {WorkPackagesCalendarController} from "core-app/modules/calendar/wp-calendar/wp-calendar.component";
import {OpenprojectWorkPackagesModule} from "core-app/modules/work_packages/openproject-work-packages.module";
import {Ng2StateDeclaration, UIRouterModule} from "@uirouter/angular";
require("fullcalendar/dist/locale-all.js");
const menuItemClass = 'calendar-menu-item';
export const CALENDAR_ROUTES:Ng2StateDeclaration[] = [

@ -1,6 +1,5 @@
import {Component, ElementRef, Input, OnDestroy, OnInit, SecurityContext, ViewChild} from "@angular/core";
import {CalendarComponent} from 'ng-fullcalendar';
import {Options} from 'fullcalendar';
import {Component, ElementRef, Input, OnDestroy, OnInit, SecurityContext, ViewChild, AfterViewInit} from "@angular/core";
import {FullCalendarComponent} from '@fullcalendar/angular';
import {States} from "core-components/states.service";
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space";
import {untilComponentDestroyed} from "ng2-rx-componentdestroyed";
@ -8,30 +7,46 @@ import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-r
import {WorkPackageCollectionResource} from "core-app/modules/hal/resources/wp-collection-resource";
import {WorkPackageViewFiltersService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-filters.service";
import * as moment from "moment";
import {Moment} from "moment";
import {WorkPackagesListService} from "core-components/wp-list/wp-list.service";
import {StateService} from "@uirouter/core";
import {UrlParamsHelperService} from "core-components/wp-query/url-params-helper";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
import {DomSanitizer} from "@angular/platform-browser";
import {WorkPackagesListChecksumService} from "core-components/wp-list/wp-list-checksum.service";
import {OpTitleService} from "core-components/html/op-title.service";
import dayGridPlugin from '@fullcalendar/daygrid';
import { EventInput, EventApi } from '@fullcalendar/core';
import { EventSourceError } from '@fullcalendar/core/structs/event-source';
import { take } from 'rxjs/operators';
import { ToolbarInput } from '@fullcalendar/core/types/input-types';
import {ConfigurationService} from "core-app/modules/common/config/configuration.service";
interface CalendarViewEvent {
el:HTMLElement;
event:EventApi;
jsEvent:MouseEvent;
}
@Component({
templateUrl: './wp-calendar.template.html',
styleUrls: ['./wp-calendar.sass'],
selector: 'wp-calendar',
})
export class WorkPackagesCalendarController implements OnInit, OnDestroy {
calendarOptions:Options;
@ViewChild(CalendarComponent, { static: false }) ucCalendar:CalendarComponent;
export class WorkPackagesCalendarController implements OnInit, OnDestroy, AfterViewInit {
@ViewChild(FullCalendarComponent, { static: false }) ucCalendar:FullCalendarComponent;
@Input() projectIdentifier:string;
@Input() static:boolean = false;
static MAX_DISPLAYED = 100;
public tooManyResultsText:string|null;
public calendarPlugins = [dayGridPlugin];
public calendarHeight:Function;
public calendarEvents:Function;
public calendarHeader:ToolbarInput|boolean;
private alreadyLoaded = false;
constructor(readonly states:States,
readonly $state:StateService,
readonly wpTableFilters:WorkPackageViewFiltersService,
@ -39,36 +54,71 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
readonly querySpace:IsolatedQuerySpace,
readonly wpListChecksumService:WorkPackagesListChecksumService,
readonly titleService:OpTitleService,
readonly urlParamsHelper:UrlParamsHelperService,
private element:ElementRef,
readonly i18n:I18nService,
readonly notificationsService:NotificationsService,
private sanitizer:DomSanitizer) { }
private sanitizer:DomSanitizer,
private configuration:ConfigurationService) { }
ngOnInit() {
// Clear any old subscribers
this.querySpace.stopAllSubscriptions.next();
this.setCalendarOptions();
this.setupWorkPackagesListener();
this.initializeCalendar();
}
ngOnDestroy() {
// nothing to do
}
public onCalendarInitialized() {
this.setupWorkPackagesListener();
ngAfterViewInit() {
// The full-calendar component's outputs do not seem to work
// see: https://github.com/fullcalendar/fullcalendar-angular/issues/228#issuecomment-523505044
// Therefore, setting the outputs via the underlying API
this.ucCalendar.getApi().setOption('eventRender', (event:CalendarViewEvent) => { this.addTooltip(event); });
this.ucCalendar.getApi().setOption('eventClick', (event:CalendarViewEvent) => { this.toWPFullView(event); });
}
public updateTimeframe($event:any) {
let calendarView = this.calendarElement.fullCalendar('getView')!;
let startDate = (calendarView.start as Moment).format('YYYY-MM-DD');
let endDate = (calendarView.end as Moment).format('YYYY-MM-DD');
public calendarEventsFunction(fetchInfo:{ start:Date, end:Date, timeZone:string },
successCallback:(events:EventInput[]) => void,
failureCallback:(error:EventSourceError) => void ):void | PromiseLike<EventInput[]> {
if (this.alreadyLoaded) {
this.alreadyLoaded = false;
let events = this.updateResults(this.querySpace.results.value!);
successCallback(events);
} else {
this.querySpace.results.values$().pipe(
take(1)
).subscribe((collection:WorkPackageCollectionResource) => {
let events = this.updateResults((collection));
successCallback(events);
});
}
this.updateTimeframe(fetchInfo);
}
private initializeCalendar() {
this.calendarEvents = this.calendarEventsFunction.bind(this);
this.setCalendarHeight();
this.setCalendarHeader();
}
public updateTimeframe(fetchInfo:{ start:Date, end:Date, timeZone:string }) {
let filtersEmpty = this.wpTableFilters.isEmpty;
if (filtersEmpty && this.querySpace.query.value) {
// nothing to do
} else if (filtersEmpty) {
return;
}
let startDate = moment(fetchInfo.start).format('YYYY-MM-DD');
let endDate = moment(fetchInfo.end).format('YYYY-MM-DD');
if (filtersEmpty) {
let queryProps = this.defaultQueryProps(startDate, endDate);
if (this.$state.params.query_props) {
@ -86,24 +136,22 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
}
}
public addTooltip($event:any) {
let event = $event.detail.event;
let element = $event.detail.element;
let workPackage = event.workPackage;
jQuery(element).tooltip({
content: this.contentString(workPackage),
public addTooltip(event:CalendarViewEvent) {
jQuery(event.el).tooltip({
content: this.tooltipContentString(event.event.extendedProps.workPackage),
items: '.fc-content',
close: function () { jQuery(".ui-helper-hidden-accessible").remove(); },
track: true
});
}
public toWPFullView($event:any) {
let workPackage = $event.detail.event.workPackage;
public toWPFullView(event:CalendarViewEvent) {
let workPackage = event.event.extendedProps.workPackage;
// do not display the tooltip on the wp show page
this.removeTooltip($event.detail.jsEvent.currentTarget);
if (event.el) {
// do not display the tooltip on the wp show page
this.removeTooltip(event.el);
}
// Ensure checksum is removed to allow queries to load
this.wpListChecksumService.clear();
@ -117,8 +165,70 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
{ inherit: false });
}
public get calendarEditable() {
return false;
}
public get calendarEventLimit() {
return false;
}
public get calendarLocale() {
return this.i18n.locale;
}
public get calendarFixedWeekCount() {
return false;
}
public get calendarDefaultView() {
if (this.static) {
return 'dayGridWeek';
} else {
return null;
}
}
public get calendarFirstDay() {
return this.configuration.startOfWeek();
}
private get calendarElement() {
return jQuery(this.element.nativeElement).find('ng-fullcalendar');
return jQuery(this.element.nativeElement).find('.fc-view-container');
}
private setCalendarHeight() {
if (this.static) {
this.calendarHeight = () => {
let heightElement = jQuery(this.element.nativeElement);
while (!heightElement.height() && heightElement.parent()) {
heightElement = heightElement.parent();
}
let topOfCalendar = jQuery(this.element.nativeElement).position().top;
let topOfHeightElement = heightElement.position().top;
return heightElement.height()! - (topOfCalendar - topOfHeightElement);
};
} else {
this.calendarHeight = () => {
// -12 for the bottom padding
return jQuery(window).height()! - this.calendarElement.offset()!.top - 12;
};
}
}
public setCalendarHeader() {
if (this.static) {
this.calendarHeader = false;
} else {
this.calendarHeader = {
right: 'dayGridMonth,dayGridWeek',
center: 'title',
left: 'prev,next today'
};
}
}
private setCalendarsDate() {
@ -130,7 +240,7 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
let datesIntervalFilter = _.find(query.filters || [], {'id': 'datesInterval'}) as any;
let calendarDate:any = null;
let calendarUnit = 'month';
let calendarUnit = 'dayGridMonth';
if (datesIntervalFilter) {
let lower = moment(datesIntervalFilter.values[0] as string);
@ -140,14 +250,14 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
calendarDate = lower.add(diff / 2, 'days');
if (diff === 7) {
calendarUnit = 'basicWeek';
calendarUnit = 'dayGridWeek';
}
}
if (calendarDate) {
this.calendarElement.fullCalendar('changeView', calendarUnit, calendarDate);
this.ucCalendar.getApi().changeView(calendarUnit, calendarDate.toDate());
} else {
this.calendarElement.fullCalendar('changeView', calendarUnit);
this.ucCalendar.getApi().changeView(calendarUnit);
}
}
@ -155,18 +265,25 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
this.querySpace.results.values$().pipe(
untilComponentDestroyed(this)
).subscribe((collection:WorkPackageCollectionResource) => {
this.warnOnTooManyResults(collection);
this.mapToCalendarEvents(collection.elements);
this.alreadyLoaded = true;
this.setCalendarsDate();
this.ucCalendar.getApi().refetchEvents();
});
}
private updateResults(collection:WorkPackageCollectionResource) {
this.warnOnTooManyResults(collection);
return this.mapToCalendarEvents(collection.elements);
}
private mapToCalendarEvents(workPackages:WorkPackageResource[]) {
let events = workPackages.map((workPackage:WorkPackageResource) => {
let startDate = this.eventDate(workPackage, 'start');
let endDate = this.eventDate(workPackage, 'due');
let exclusiveEnd = moment(endDate).add(1, 'days');
let exclusiveEnd = moment(endDate).add(1, 'days').format('YYYY-MM-DD');
return {
title: workPackage.subject,
@ -178,12 +295,7 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
};
});
// Instead of using two way bindings we manually trigger
// event rendering here. For whatever reasons, when embedded
// in a grid, having two way binding will lead to having constantly
// removed the events after showing them initially.
// It appears as if the two way binding is initialized twice if used.
this.ucCalendar.renderEvents(events);
return events;
}
private warnOnTooManyResults(collection:WorkPackageCollectionResource) {
@ -202,58 +314,6 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
}
}
private setCalendarOptions() {
if (this.static) {
this.calendarOptions = this.staticOptions;
} else {
this.calendarOptions = this.dynamicOptions;
}
}
private get dynamicOptions() {
return {
editable: false,
eventLimit: false,
locale: this.i18n.locale,
height: () => {
// -12 for the bottom padding
return jQuery(window).height()! - this.calendarElement.offset()!.top - 12;
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek'
},
views: {
month: {
fixedWeekCount: false
}
}
};
}
private get staticOptions() {
return {
editable: false,
eventLimit: false,
locale: this.i18n.locale,
height: () => {
let heightElement = jQuery(this.element.nativeElement);
while (!heightElement.height() && heightElement.parent()) {
heightElement = heightElement.parent();
}
let topOfCalendar = jQuery(this.element.nativeElement).position().top;
let topOfHeightElement = heightElement.position().top;
return heightElement.height()! - (topOfCalendar - topOfHeightElement);
},
header: false,
defaultView: 'basicWeek'
};
}
private defaultQueryProps(startDate:string, endDate:string) {
let props = { "c": ["id"],
"t":
@ -273,7 +333,7 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
}
}
private contentString(workPackage:WorkPackageResource) {
private tooltipContentString(workPackage:WorkPackageResource) {
return `
${this.sanitizedValue(workPackage, 'type')} #${workPackage.id}: ${this.sanitizedValue(workPackage, 'subject', null)}
<ul class="tooltip--map">
@ -313,9 +373,9 @@ export class WorkPackagesCalendarController implements OnInit, OnDestroy {
return this.sanitizer.sanitize(SecurityContext.HTML, value);
}
private removeTooltip(target:ElementRef) {
private removeTooltip(element:HTMLElement) {
// deactivate tooltip so that it is not displayed on the wp show page
jQuery(target).tooltip({
jQuery(element).tooltip({
close: function () { jQuery(".ui-helper-hidden-accessible").remove(); },
disabled: true
});

@ -1,15 +1,19 @@
<!-- position: relative added in order for the loading indicator to be positioned correctly -->
<div *ngIf="calendarOptions"
class="wp-calendar--container loading-indicator--location"
<div class="wp-calendar--container loading-indicator--location"
[attr.data-indicator-name]="'table'"
style="position: relative">
<ng-fullcalendar #ucCalendar
[options]="calendarOptions"
(initialized)="onCalendarInitialized()"
(viewRender)="updateTimeframe($event)"
(eventRender)="addTooltip($event)"
(eventClick)="toWPFullView($event)">
</ng-fullcalendar>
<full-calendar #ucCalendar
[editable]="calendarEditable"
[eventLimit]="calendarEventLimit"
[locale]="calendarLocale"
[fixedWeekCount]="calendarFixedWeekCount"
[height]="calendarHeight"
[header]="calendarHeader"
[defaultView]="calendarDefaultView"
[firstDay]="calendarFirstDay"
[events]="calendarEvents"
[plugins]="calendarPlugins">
</full-calendar>
<div
*ngIf="static"
[textContent]="tooManyResultsText"

@ -30,6 +30,7 @@ import {Injectable} from '@angular/core';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {ConfigurationDmService} from "core-app/modules/hal/dm-services/configuration-dm.service";
import {ConfigurationResource} from "core-app/modules/hal/resources/configuration-resource";
import * as moment from "moment";
@Injectable()
export class ConfigurationService {
@ -95,14 +96,8 @@ export class ConfigurationService {
public startOfWeek() {
if (this.startOfWeekPresent()) {
return this.systemPreference('startOfWeek');
} else if (I18n.locale === 'en') {
return 1;
} else if (I18n.locale === 'de') {
// This if/else statement is used because
// jquery regionals have different start day for German locale
return 0;
} else {
return null;
return moment.localeData(I18n.locale).firstDayOfWeek();
}
}

@ -107,7 +107,7 @@ describe 'Work package calendars', type: :feature, js: true do
filters.expect_filter_count 2
# navigate to the next month
find('.fc-left button.fc-next-button').click
find('.fc-next-button').click
expect(page)
.to have_no_selector '.fc-event-container', text: current_work_package.subject
@ -133,7 +133,7 @@ describe 'Work package calendars', type: :feature, js: true do
future_url = current_url
# navigate back a month
find('.fc-left button.fc-prev-button').click
find('.fc-prev-button').click
expect(page)
.to have_selector '.fc-event-container', text: current_work_package.subject

Loading…
Cancel
Save